Tuesday, February 23, 2021

The journey for updating Realtek NIC MAC

Realtek Network Interface Controller (NIC, also known as a Network Interface Card) is widely used in PC. Usually an EEPROM would be connected to the RTL NIC chip to provide programmable storage for saving some network related setting, such as MAC address. IP address is bound with the MAC. So if multiple NIC has same MAC, it would be a disaster for switch/bridge/router to correctly forward IP packet.

On Linux and Windows, it is possible to change the MAC address temporarily by using some command such as ifconfig, but the setting won't persist during reboot. It is also possible to override the MAC address with a saved file or value stored in Registry table and keep the change permanently. However, this change can also get lost if the card is moved to a different setup, or the OS gets reinstalled.

So to permanently change the MAC, will need to reprogram the EEPROM. There is an Open Source tools, rtl8168-eeprom, supposed can be used to update EEPROM. However, several issues to get it working:

1) open('/dev/mem') may fail, due to a new kernel feature 'KERNEL_LOCKDOWN'.

2) Rebuild kernel from source. After build and install, it cannot boot the new kernel with error

/boot/vmlinuz-x.y.z-generic has invalid signature

This is due to for secure boot, customer kernel has to be signed. Refer to this.

3) Tried to build kernel with CONFIG_SECURITY_LOCKDOWN_LSM disabled, will run into problem during kernel_config, as KERNEL_LOCKDOWN is forced on due to config policy setting

4) Build old kernel 4.4 from source for Ubuntu 20.04 (Focal Fossa) doesn't work very well, as the kernel version is too low which cause build problem.

5) So the way to run the tools is install kernel 4.4 deb package from LaunchPad. However, the tools cannot properly access RTL8168 EEPROM as it failed to read back the ID from EEPROM.

Ethtool has option '-m' for dump module EEPROM, '-e' for dump EEPROM, and '-E' for update MAC. However, running ethtool with these option may get  'Operation Not Permitted' error. Run 'ethtool -i devname' may get 'support-eeprom-access: no'. So the NIC driver does not support EEPROM access.

As a side note, Realtek might have released some tools for this purpose, which can run on Windows, Linux, and UEFI shell. You can search for 'RTNicPG' from Internet. I'm able to find several links but none of them from Realtek official website. Maybe it got leaked out as an internal used tools.

Sunday, February 7, 2021

Update build.gradle for build native code with NDK

Because of Android Studio/Gradle keeps evolution, and the special need of Android NDK's configuration, sometimes it is a little difficult to get things working smoothly.

There is some references like:

https://riptutorial.com/android/example/13985/enable-experimental-ndk-plugin-support-for-gradle-and-androidstudio

https://stackoverflow.com/questions/16667903/android-studio-gradle-and-ndk

https://android-developers.googleblog.com/2020/02/native-dependencies-in-android-studio-40.html

Will see some mismatch between above posts, or things not working with Android Studio, such as with Android Studio 4.1.2, Gradle model 6.5, the ndk setting in above first link will lead to weird error. The 2nd link from stackoverflow has the correct setting, i.e. ndk setting has to be put under defaultConfig, specially the abiFilters setting. As explained in the 3rd link, when deal with native code, frequently may need to link with prebuilt lib, which may only support one special ABI such as armeabi-v7a, but not all others such as 64 bit or x86. Here is an example app build.gradle file for android-eye:

apply plugin: 'com.android.application'

android {
compileSdkVersion 14
buildToolsVersion "30.0.3"
ndkVersion "17.2.4988734"

defaultConfig {
applicationId "teaonly.droideye"
targetSdkVersion 14
minSdkVersion="14"
ndk {
abiFilters 'armeabi-v7a'
// 64-bit support requires an Android API level higher than 19; Namely 21 and higher
//abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
//cppFlags.add("-O2 -Werror -Wall")
//ldLibs.addAll(['log', 'z', 'ld'])
stl = "c++_static"
}

}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
externalNativeBuild {
ndkBuild {
path file('src/main/jni/Android.mk')
}
}
}

dependencies {
implementation files('libs/java_websocket.jar')
}

Building under Android Studio may hide the detail of the build, which makes it difficult to root cause when something goes wrong.

Beside gradle related setting, sometimes developer might get sysroot setting issue. Such as compiling x264 with NDK (specially old version) sometimes need some tweak, such as sysroot setting. Refer to SO1, SO2, and BuildSystemMaintainers for latest new NDK. For old NDK, at compile time sysroot is $NDK/sysroot, and at link time sysroot points to $NDK/platforms/android-$API/arch-$ARCH. One way is refer to standalone_toolchain, run $NDK/build/tools/make_standalone_toolchain.py --arch arm --api 14 --install-dir /tmp/my_toolchain to create a standalone toolchain. May need to specify CFLAGS=-D__ANDROID_API__=$API as mentioned here. The other possible way is refer to this: Using clang instead of gcc also works, e.g. for autotools-based projects CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ ./configure --cross-prefix=arm-linux-androideabi- ... works without disabling unified headers and without specifying __ANDROID_API__

With new version NDK,  'Application.mk' has to be provided. Also, NDK will assume the 'Application.mk' and 'Android.mk' are all located under a 'jni' sub-folder. If that is not the case, then user will have to specify the path of 'Application.mk' while invoking 'ndk-build' script, by setting NDK_APPLICATION_MK, and in 'Application.mk', user has to specify the path of 'Android.mk' by set 'APP_BUILD_SCRIPT'. Refer to https://developer.android.com/ndk/guides/ndk-build for more detail.