Tuesday, September 30, 2008

Building Wireless Perimeter With WPA2 and RADIUS

Most of the KISS (Keep It Simple Stupid) steps are explained in an article by SmallNetBuilder. However, those guides were not working out-of-the-box for me. I'll talk about it later.

Let's start with my system setup:
1. Slamd64 12.1
2. Freeradius 1.1.7
3. OpenSSL 0.9.8g (comes with Slamd64 12.1)

Now, to the quirks of building Freeradius 1.1.7. I didn't manage to compile Freeradius with the default ./configure and make command in Slamd64. Therefore, I'm only interested to enable EAP-TLS support. Therefore, I use the following commands to build it:

./configure --prefix=/usr --libdir=/usr/lib64 --sysconfdir=/etc --mandir=/usr/man \
--enable-strict-dependencies --without-rlm_dbm --without-rlm_krb5 --without-rlm_pam \
--without-rlm_sql_postgresql

make

As you see, Kerberos, pam, and sql support are disabled. In this setup, it's not needed as well. Therefore, it's not a problem.

The next quirk is in the wpa_supplicant configuration file. You have to be very careful especially regarding the entries you put in the certificate related fields. Below is the snippet of the wpa_supplicant configuration file in my laptop.

# WPA2-EAP/CCMP using EAP-TLS
network={
ssid="your_ap_ssid"
key_mgmt=WPA-EAP
proto=RSN
identity="your_machine_common_name"
pairwise=CCMP
group=CCMP
eap=TLS
ca_cert="/etc/wireless/cacert.pem"
private_key="/etc/wireless/linux_laptop.p12"
private_key_passwd="your_secret_pkcs12_password"
}

In the configuration snippet above, the laptop (a user in RADIUS vocabulary), lump the certificate and the private key together into a PKCS12 file for Windows compatibility reason. This is not needed in Linux. You can split the certificate and the private if you are using Linux by using the following configuration:

# WPA2-EAP/CCMP using EAP-TLS
network={
ssid="your_ap_ssid"
key_mgmt=WPA-EAP
proto=RSN
identity="your_machine_common_name"
pairwise=CCMP
group=CCMP
eap=TLS
ca_cert="/etc/wireless/cacert.pem"
client_cert="/etc/wireless/linux_laptop_cert.pem"
private_key="/etc/wireless/linux_laptop_key.pem"
private_key_passwd="your_private_key_password"
}

If you look carefully in both of the configuration above, you will notice that the password for both of the configuration are different. Indeed, the former uses the password that you enter when you make the PKCS12 file while the latter uses the password that you enter when you make the private key. These are different passwords. For RADIUS newbie this can be easily become problem. Therefore, as always, run Freeradius as radiusd -X before you found a working configuration.

Also, take a note on file permissions for Freeradius configuration file because it can be easily becomes a problem. Moreover, if you run the Freeradius daemon as nobody (as explained in the tutorial by SmallNetBuilder), then set the config file group to user nobody, so that it can be read by Freeradius when it runs. Don't forget to disable read-write-execute permission on the configuration file for unwanted users. This way is safer for you.

This Freeradius howto explains a much cleaner approach if you are interested. It's a bit more complicated as well. But, manageable for quite average *NIX administrator and user.

In any case, by protecting your home wireless access point with radius, you have established a strong enough perimeter against malicious wannabes around your access point.

Wednesday, September 24, 2008

MIPS Cross Compiling on Linux x86_64

Cross compiling might be a quite "scary" subject for some programmers. Nevertheless, it's not so difficult as long as you have already obtained the right cross-toolchain.

At first sight, I thought that I have to put lengthy LDFLAGS and CFLAGS arguments in the Makefile of my test program. But, surprisingly, it's not the case. Let's see how it works. My build system is Slamd64 12.1, a Linux x86_64 platform. The target is a MIPS R3000 system. This is the Makefile:

all: set_power_cck

CC = mips-uclibc-gcc
STRIP = mips-uclibc-strip

CFLAGS = -v
IFLAGS =
LDFLAGS =


DEBUG = -Wall -Os

set_power_cck: Makefile set_power_cck.o
$(CC) -o $@ $(DEBUG) $(CFLAGS) $(IFLAGS) $(LDFLAGS) set_power_cck.o
$(STRIP) $@

clean:
rm -f set_power_cck *.o

set_power_cck.o: set_power_cck.c
$(CC) -c -o $@ $(DEBUG) $(CFLAGS) $(IFLAGS) $<



As you see, the only exotic option is in the CC and STRIP program definition which specify a cross-mips toolchain. Actually this is an x86 (not x86_64) cross toolchain, but because my Slamd64 is a multilib linux installation, it's not a problem. In the first run of this makefile, I'm very surprised how the cross-toolchain could find the right include paths and library paths. After tinkering with GCC for sometime, I found that the -v CFLAGS could reveal what exactly happens. Now, let's see how the cross-toolchain found the right library paths and include paths.


darmawan@opunaga:realtek_rtl8186_sdk_v1.4c_svn_co $ make -C AP/set_power_cck/
make: Entering directory `/home/darmawan/_Projects/Antek_SRL/RTL8186_work/realtek_rtl8186_sdk_v1.4c_svn_co/AP/set_power_cck'
mips-uclibc-gcc -c -o set_power_cck.o -Wall -Os -v set_power_cck.c
Reading specs from /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/specs
Configured with: /root/toolchain/gcc-3.3.x/toolchain_build_mips_nofpu/gcc-3.3.3/configure --prefix=/usr/local/gcc333/lexra-nnop-v5 --build=i386-pc-linux-gnu --host=i386-pc-linux-gnu --target=mips-linux-uclibc --enable-languages=c,c++ --enable-shared --with-gxx-include-dir=/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/include/c++ --disable-__cxa_atexit --enable-target-optspace --with-gnu-ld -with-gnu-as --disable-nls --enable-multilib --without-float --enable-sjlj-exceptions
Thread model: posix
gcc version 3.3.3
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/cc1 -quiet -v -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=3 set_power_cck.c -quiet -dumpbase set_power_cck.c -auxbase-strip set_power_cck.o -Os -Wall -version -msoft-float -o /tmp/ccNOlsiQ.s
GNU C version 3.3.3 (mips-linux-uclibc)
compiled by GNU C version 2.96 20000731 (Red Hat Linux 7.3 2.96-110).
GGC heuristics: --param ggc-min-expand=94 --param ggc-min-heapsize=120073
ignoring duplicate directory "/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/include
/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/sys-include
End of search list.
set_power_cck.c: In function `set_tx_power_cck':
set_power_cck.c:20: warning: unused variable `tx_power_cck'
set_power_cck.c:22: warning: control reaches end of non-void function
set_power_cck.c: At top level:
set_power_cck.c:19: warning: `set_tx_power_cck' defined but not used
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/bin/as -EB -g0 -32 -v -KPIC -o set_power_cck.o /tmp/ccNOlsiQ.s
GNU assembler version 2.14.90.0.7 (mips-linux-uclibc) using BFD version 2.14.90.0.7 20031029
mips-uclibc-gcc -o set_power_cck -Wall -Os -v set_power_cck.o
Reading specs from /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/specs
Configured with: /root/toolchain/gcc-3.3.x/toolchain_build_mips_nofpu/gcc-3.3.3/configure --prefix=/usr/local/gcc333/lexra-nnop-v5 --build=i386-pc-linux-gnu --host=i386-pc-linux-gnu --target=mips-linux-uclibc --enable-languages=c,c++ --enable-shared --with-gxx-include-dir=/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/include/c++ --disable-__cxa_atexit --enable-target-optspace --with-gnu-ld -with-gnu-as --disable-nls --enable-multilib --without-float --enable-sjlj-exceptions
Thread model: posix
gcc version 3.3.3
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/collect2 --eh-frame-hdr -EB -dynamic-linker /lib/ld-uClibc.so.0 -o set_power_cck /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib/crt1.o /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib/crti.o /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/crtbegin.o -L/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3 -L/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib set_power_cck.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/crtend.o /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib/crtn.o
mips-uclibc-strip set_power_cck
make: Leaving directory `/home/darmawan/_Projects/Antek_SRL/RTL8186_work/realtek_rtl8186_sdk_v1.4c_svn_co/AP/set_power_cck'



As you see, the cross-compiler driver (mips-uclibc-gcc) found the right paths for libraries and include files in the spec file definition. Now, it's clear to me what a "compiler driver" really is. This knowledge is very handy when you are working with cross-toolchain. Now, let's see the result using the file utility.

darmawan@opunaga:realtek_rtl8186_sdk_v1.4c_svn_co $ file AP/set_power_cck/set_power_cck
AP/set_power_cck/set_power_cck: ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), stripped

It's very clear that the binary result is indeed MIPS ELF 32-bit executable file. When I run the executable in the target MIPS system, it works just fine as follows:

BusyBox v1.00-pre8 (2008.09.24-13:53+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.
# set_power_cck
Usage: $0 (0-255 decimal)
where (0-255 decimal) is the power level gain. Choose a value between 0 and 255 decimal

Cross compiling is not as scary as it sounds, doesn't it? Personally, I think it's scary if you have to build the cross-toolchain yourself. Let's leave it for another time.

Sunday, September 21, 2008

Ndiswrapper-SSB Driver Bug in Slamd64 12.1 (Kernel 2.6.25.9) -- Somehow With A wpa_supplicant Fix

It's quite sad to find out that the current generation of opensource driver for Broadcom BCM43xx WLAN chipset is still unable to get WEP working as expected--after some checks, I found that the driver unable to work with WEP unless you use wpa_supplicant to set the WEP keys. It forces me to go back to use ndiswrapper once more. Nonetheless, using ndiswrapper is not as easy as it seems because the driver has a conflict with the ssb driver module. The workaround is an ugly workaround, but it seems working so far.

First, block all drivers related to WLAN handling and the ssb kernel module in /etc/modprobe.d/blacklist (note that it's very fortunate that I build the ssb driver as a kernel module)

...
# Disable Broadcom b43 driver and all related wifi drivers because
# we are using ndiswrapper.
# Also, disable ssb and ohci_hcd and then enable them back in /etc/rc.d/rc.local
blacklist b43
blacklist rfkill_input
blacklist rfkill
blacklist mac80211
blacklist cfg80211
blacklist ohci_hcd
blacklist ssb
...


Second, load ndiswrapper driver before ssb loaded using /etc/rc.d/rc.local:

...
# Load ndiswrapper-based BCM4318 WLAN driver
modprobe ndiswrapper

# Enable ssb and ohci_hcd
modprobe ssb
modprobe ohci_hcd
...


Now everything worked as expected. Nonetheless, this is an ugly hack just to make the encryption work in this particular WLAN chipset.
Note that I'm using the Windows XP x64 Broadcom BCM43xx driver as the driver which is loaded by ndiswrapper on boot.

----
Update:

After conducting some experiments, I found out that WEP actually works with the opensource Linux BCM43xx driver (b43 driver module along with its dependency modules). The catch is, I have to use wpa_supplicant to set the WEP key. This is the wpa_supplicant configuration file for WEP that I use:

# Static WEP keys

ctrl_interface=/var/run/wpa_supplicant

network={
ssid="bounsier"
key_mgmt=NONE
wep_key0="very_secret_wep_key"
# wep_key1=0102030405
wep_tx_keyidx=0
}



Further tests, shows that WPA is also working correctly in the current generation of BCM43xx opensource driver with the help of wpa_supplicant as the WPA "back-end".

BIOS Disasembly Ninjutsu Uncovered Russian Edition

The Russian edition of my BIOS Disassembly Ninjutsu Uncovered book actually has been published in August last year. However, I haven't been able to write about it for a while. Here it is:



Cyrillic maybe a problem for most people used to Latin characters. This is what the title said (more or less):

BIOS
Disassemblirovaniye
Modifikatsiya
Programmirovaniye

translated to english:

BIOS
Disassembly
Modification
Programming

Here's the back cover (a.k.a blurb):



For me, it's an honor to have my book translated to other language. But it's quite sad that the book hasn't been translated to Bahasa Indonesia, my native language. Maybe next time when I have enough time to do that. At the moment, the book probably overly technical and doesn't find enough market share to take advantage of the economic of scale to be published in Bahasa Indonesia. Time will tell.

Friday, September 19, 2008

The Diff Ninjutsu (Part 2)

In the previous installment of this series, I haven't show how we can use diff to do the automatic checking of the applied patch. Now. let's look at a sample shell script that do just that.

#!/bin/bash
#
# Script to apply patches to Realtek v1.4 ADK, SDK and CMK in order to
# upgrade it to version 1.4c (with latest v1.4c patches)
#
# Author: Darmawan Salihun
#
# Date: 26-08-2008
#

##### ASSUMPTIONS a.k.a PRECONDITION ####################################
#
# The following directories must have been decompressed prior to the
# execution of this script!
#
# CMK_1_4b_ROOT_DIR=rtl8186-cmk-1.4b
# CMK_1_4c_ROOT_DIR=rtl8186-cmk-1.4c-release
# ADK_ROOT_DIR=rtl8186-adk-1.4
# SDK_ROOT_DIR=rtl8186-sdk-1.4
# CMK_1_4c_PATCH_DIR=patch/files
#
#########################################################################


# directories definition
CMK_1_4b_ROOT_DIR=rtl8186-cmk-1.4b
CMK_1_4b_ADK_PATCH_DIR=$CMK_1_4b_ROOT_DIR/patch/ADK/AP
CMK_1_4b_SDK_PATCH_DIR=$CMK_1_4b_ROOT_DIR/patch/SDK/linux-2.4.18

CMK_1_4c_ROOT_DIR=rtl8186-cmk-1.4c-release
CMK_1_4c_ADK_PATCH_DIR=$CMK_1_4c_ROOT_DIR/patch/ADK/AP
CMK_1_4c_SDK_PATCH_DIR=$CMK_1_4c_ROOT_DIR/patch/SDK/linux-2.4.18
CMK_1_4c_CONFIG_DIR=$CMK_1_4c_ROOT_DIR/config
CMK_1_4c_LINUX_TOOLS=$CMK_1_4c_ROOT_DIR/tools/LINUX/tools.tar.gz

ADK_ROOT_DIR=rtl8186-adk-1.4
ADK_ASP_DIR=$ADK_ROOT_DIR/rtl8186-ASP-1.4
SDK_ROOT_DIR=rtl8186-sdk-1.4
SDK_LINUX_DIR=$SDK_ROOT_DIR/rtl8186-linux-1.4
SDK_TOOLCHAIN=$SDK_ROOT_DIR/rtl8186-toolchain-1.0.tar.gz
SDK_BOOTCODE=$SDK_ROOT_DIR/rtl8186-btcode-1.4a.tar.gz

CMK_1_4c_PATCH_DIR=patch/files
ANTEK_RTL_SDK_DIR=antek-rtl8186-sdk

# Guard against error during execution
set -e

#
# step 1: prepare target directory (Antek RTL8186 SDK)
#
echo "Preparing target directory.."
rm -rf $ANTEK_RTL_SDK_DIR
mkdir -v $ANTEK_RTL_SDK_DIR


#
# step 2: prepare original ADK and SDK v1.4
#
echo "Preparing original ADK and SDK.."
rm -rf $ADK_ASP_DIR
tar xzf $ADK_ROOT_DIR/rtl8186-ASP-1.4.tar.gz -C $ADK_ROOT_DIR

rm -rf $SDK_LINUX_DIR
tar xzf $SDK_ROOT_DIR/rtl8186-linux-1.4.tar.gz -C $SDK_ROOT_DIR


#
# step 3: copy original ADK and SDK v1.4 to target directory
#
echo "Copying original ADK and SDK.."
cp -r --remove-destination $ADK_ASP_DIR/AP $ANTEK_RTL_SDK_DIR
cp -r --remove-destination $SDK_LINUX_DIR/linux-2.4.18 $ANTEK_RTL_SDK_DIR


#
# step 4: upgrade v1.4 to v1.4b in target directory
#
echo "Upgrading ADK and SDK to v1.4b.."
cp -r --remove-destination $CMK_1_4b_ADK_PATCH_DIR/* $ANTEK_RTL_SDK_DIR/AP
cp -r --remove-destination $CMK_1_4b_SDK_PATCH_DIR/* $ANTEK_RTL_SDK_DIR/linux-2.4.18


#
# step 5: check the validity of the applied ADK and SDK v1.4b patch
#

#
# Check ADK patch validity
#
echo "Checking ADK v1.4b patch validity.."
find $CMK_1_4b_ADK_PATCH_DIR -type f -name '*' > files.txt

# Eliminate CMK_1_4b_ADK_PATCH_DIR/ from filenames path
cat /dev/null > new_files.txt
while read FILENAME
do
echo $FILENAME | sed -e "s%$CMK_1_4b_ADK_PATCH_DIR/%%g" >> new_files.txt # Note: sed uses % as delimiter
done < files.txt

rm -f files.txt

# Merge list of files into single line,
# i.e. as the value of TARGETS variable
while read FILENAME
do
TARGETS="$TARGETS $FILENAME"
done < new_files.txt

rm -f new_files.txt


for i in $TARGETS;
do
SRC=$CMK_1_4b_ADK_PATCH_DIR/$i
DEST=$ANTEK_RTL_SDK_DIR/AP/$i
diff $SRC $DEST > result.txt

if [ -s result.txt ]; then
echo "Error. $SRC and $DEST differ"
fi
rm -f result.txt
done


#
# Reset reused variables!!!
#
TARGETS=""
FILENAME=""
SRC=""
DEST=""

#
# Check SDK patch validity
#
echo "Checking SDK 1.4b patch validity.."
find $CMK_1_4b_SDK_PATCH_DIR -type f -name '*' > files.txt

# Eliminate CMK_1_4b_SDK_PATCH_DIR/ from filenames path
cat /dev/null > new_files.txt
while read FILENAME
do
echo $FILENAME | sed -e "s%$CMK_1_4b_SDK_PATCH_DIR/%%g" >> new_files.txt # Note: sed uses % as delimiter
done < files.txt

rm -f files.txt

# Merge list of files into single line,
# i.e. as the value of TARGETS variable
while read FILENAME
do
TARGETS="$TARGETS $FILENAME"
done < new_files.txt

rm -f new_files.txt

for i in $TARGETS;
do
SRC=$CMK_1_4b_SDK_PATCH_DIR/$i
DEST=$ANTEK_RTL_SDK_DIR/linux-2.4.18/$i
diff $SRC $DEST > result.txt

if [ -s result.txt ]; then
echo "Error. $SRC and $DEST differ"
fi
rm -f result.txt
done

#
# Reset reused variables!!!
#
TARGETS=""
FILENAME=""
SRC=""
DEST=""


#
# step 6: patch _the ADK and SDK v1.4c patch files_ with latest patches
#
CMK_1_4c_PATCH_TARGETS="patch/SDK/linux-2.4.18/rtl8186/wireless_ag_net.o patch/ADK/linux-2.4.18/drivers/net/wireless_ag/ieee802_mib.h patch/SDK/linux-2.4.18/drivers/net/wireless_ag/ieee802_mib.h patch/SDK/l
inux-2.4.18/rtl8186.tar.gz patch/ADK/AP/mkimg"


for i in $CMK_1_4c_PATCH_TARGETS;
do
DEST=$CMK_1_4c_ROOT_DIR/$i
SRC=`basename $i`
SRC=$CMK_1_4c_PATCH_DIR/$SRC
cp -f $SRC $DEST
done

#
# step 7: check the patch for ADK and SDK v1.4c patch files
#
for i in $CMK_1_4c_PATCH_TARGETS;
do
DEST=$CMK_1_4c_ROOT_DIR/$i
SRC=`basename $i`
SRC=$CMK_1_4c_PATCH_DIR/$SRC

diff $SRC $DEST > result.txt
if [ -s result.txt ]; then
echo "Error. $SRC and $DEST differ"
fi
rm -f result.txt
done


#
# Reset reused variables!!!
#
TARGETS=""
FILENAME=""
SRC=""
DEST=""


#
# step 8: upgrade ADK and SDK v1.4b to patched ADK and SDK v1.4c in target dir
#
echo "Upgrading ADK and SDK v1.4b to v1.4c.."
cp -r --remove-destination $CMK_1_4c_ADK_PATCH_DIR/* $ANTEK_RTL_SDK_DIR/AP
cp -r --remove-destination $CMK_1_4c_SDK_PATCH_DIR/* $ANTEK_RTL_SDK_DIR/linux-2.4.18

#
# check ADK v1.4c patch validity
#

echo "Checking ADK v1.4c patch validity.."
find $CMK_1_4c_ADK_PATCH_DIR -type f -name '*' > files.txt

# Eliminate CMK_1_4c_ADK_PATCH_DIR/ from filenames path
cat /dev/null > new_files.txt
while read FILENAME
do
echo $FILENAME | sed -e "s%$CMK_1_4c_ADK_PATCH_DIR/%%g" >> new_files.txt # Note: sed uses % as delimiter
done < files.txt

rm -f files.txt

# Merge list of files into single line,
# i.e. as the value of TARGETS variable
while read FILENAME
do
TARGETS="$TARGETS $FILENAME"
done < new_files.txt

rm -f new_files.txt


for i in $TARGETS;
do
SRC=$CMK_1_4c_ADK_PATCH_DIR/$i
DEST=$ANTEK_RTL_SDK_DIR/AP/$i
diff $SRC $DEST > result.txt

if [ -s result.txt ]; then
echo "Error. $SRC and $DEST differ"
fi
rm -f result.txt
done


#
# Reset reused variables!!!
#
TARGETS=""
FILENAME=""
SRC=""
DEST=""

#
# Check SDK v1.4c patch validity
#
echo "Checking SDK v1.4c patch validity.."
find $CMK_1_4c_SDK_PATCH_DIR -type f -name '*' > files.txt


# Eliminate CMK_1_4c_SDK_PATCH_DIR/ from filenames path
cat /dev/null > new_files.txt
while read FILENAME
do
echo $FILENAME | sed -e "s%$CMK_1_4c_SDK_PATCH_DIR/%%g" >> new_files.txt # Note: sed uses % as delimiter
done < files.txt

rm -f files.txt

# Merge list of files into single line,
# i.e. as the value of TARGETS variable
while read FILENAME
do
TARGETS="$TARGETS $FILENAME"
done < new_files.txt

rm -f new_files.txt

for i in $TARGETS;
do
SRC=$CMK_1_4c_SDK_PATCH_DIR/$i
DEST=$ANTEK_RTL_SDK_DIR/linux-2.4.18/$i
diff $SRC $DEST > result.txt

if [ -s result.txt ]; then
echo "Error. $SRC and $DEST differ"
fi
rm -f result.txt
done



mkdir -v $ANTEK_RTL_SDK_DIR/tool
cp -rf $CMK_1_4c_CONFIG_DIR $ANTEK_RTL_SDK_DIR/tool
tar xzf $CMK_1_4c_LINUX_TOOLS -C $ANTEK_RTL_SDK_DIR/tool/

cp -vf $SDK_TOOLCHAIN $ANTEK_RTL_SDK_DIR/tool
cp -vf $SDK_BOOTCODE $ANTEK_RTL_SDK_DIR/tool

# inform that we're done
echo "Realtek RTL8186 SDK v1.4c installed."


That's one hell of a script. Nonetheless, the most important part is the automatic patch-checking routine such as:

echo "Checking SDK v1.4c patch validity.."
find $CMK_1_4c_SDK_PATCH_DIR -type f -name '*' > files.txt

# Eliminate CMK_1_4c_SDK_PATCH_DIR/ from filenames path
cat /dev/null > new_files.txt
while read FILENAME
do
echo $FILENAME | sed -e "s%$CMK_1_4c_SDK_PATCH_DIR/%%g" >> new_files.txt # Note: sed uses % as delimiter
done < files.txt

rm -f files.txt

# Merge list of files into single line,
# i.e. as the value of TARGETS variable
while read FILENAME
do
TARGETS="$TARGETS $FILENAME"
done < new_files.txt

rm -f new_files.txt

for i in $TARGETS;
do
SRC=$CMK_1_4c_SDK_PATCH_DIR/$i
DEST=$ANTEK_RTL_SDK_DIR/linux-2.4.18/$i
diff $SRC $DEST > result.txt

if [ -s result.txt ]; then
echo "Error. $SRC and $DEST differ"
fi
rm -f result.txt
done

As you can see, the script first create list of files to be diff-ed and then iterate the diff-ing process on each of those file, creating a diff file (result.txt) in the process. If the size of result.txt is bigger than zero, it means there is at least one difference which means the patch is not correctly applied.

There you have it, an automatic patch-checking script. In the next installment of this series, I will tidy up the code and make some functions because the current version is a quick'n'dirty script.

Saturday, September 13, 2008

The Diff Ninjutsu

Sometimes patches for certain source code which are distributed by programmers, are not in the form of the usual patch like linux kernel patches (either incremental or against the base version) which you can apply by just using the patch utility in *nix. This can cause months of headache for maintainer or someone who come later. This is where utility like diff comes handy. Let's see how to use it effectively.

First, examine the entire directory structure of the different version of the source code

diff -q -r <orig_dir> <new_dir>


Second, examine the differences between different version of certain file of interest.

diff <path_to_orig_file> <path_to_new_file>


Third, create a shell script to do the real patching. For example:

#!/bin/bash
#
# Script to apply patches to Realtek v1.4 ADK, SDK and CMK in order to
# upgrade it to version 1.4c (with latest v1.4c patches)
#
# Author: Darmawan Salihun
#
#

##### ASSUMPTIONS a.k.a PRECONDITION ####################################
#
# The following directories must have been decompressed prior to the
# execution of this script!
#
# RTL8186_LINUX_DIR="../rtl8186-sdk-1.4/rtl8186-linux-1.4"
# RTL8186_ASP_DIR="../rtl8186-adk-1.4/rtl8186-ASP-1.4"
# PATCH_1_4b_ADK="rtl8186-cmk-1.4b/patch/ADK"
# PATCH_1_4b_SDK="rtl8186-cmk-1.4b/patch/SDK"
# PATCH_1_4c_ADK_DIR="rtl8186-cmk-1.4c-release/patch/ADK"
# PATCH_1_4c_SDK_DIR="rtl8186-cmk-1.4c-release/patch/SDK"
# CMK_1_4c_PATCH_DIR="patch/files"
# CMK_1_4c_CONFIG_DIR="rtl8186-cmk-1.4c-release/config"
#
#########################################################################


# directories definition
PATCH_1_4b_ADK="rtl8186-cmk-1.4b/patch/ADK/*"
PATCH_1_4b_SDK="rtl8186-cmk-1.4b/patch/SDK/*"
PATCH_1_4c_ADK_DIR="rtl8186-cmk-1.4c-release/patch/ADK"
PATCH_1_4c_SDK_DIR="rtl8186-cmk-1.4c-release/patch/SDK"
RTL8186_ASP_DIR="../rtl8186-adk-1.4/rtl8186-ASP-1.4"
RTL8186_LINUX_DIR="../rtl8186-sdk-1.4/rtl8186-linux-1.4"
CMK_1_4c_PATCH_DIR="patch/files"
CMK_1_4c_CONFIG_DIR="rtl8186-cmk-1.4c-release/config"
CMK_1_4c_LINUX_TOOLS="rtl8186-cmk-1.4c-release/tools/LINUX/tools.tar.gz"
SDK_TOOLCHAIN="../rtl8186-sdk-1.4/rtl8186-toolchain-1.0.tar.gz"
SDK_BOOTCODE=" ../rtl8186-sdk-1.4/rtl8186-btcode-1.4a.tar.gz"
ANTEK_RTL_SDK_DIR="antek-rtl8186-sdk"

# Guard against error during execution
set -e

# step 1: upgrade ADK and SDK v1.4 to v1.4b
cp -r -v --remove-destination $PATCH_1_4b_ADK $RTL8186_ASP_DIR
cp -r -v --remove-destination $PATCH_1_4b_SDK $RTL8186_LINUX_DIR

# step 2: patch _the ADK and SDK v1.4c patch files_ with latest patches
cp -v --remove-destination $CMK_1_4c_PATCH_DIR/wireless_ag_net.o $PATCH_1_4c_SDK_DIR/linux-2.4.18/rtl8186
cp -v --remove-destination $CMK_1_4c_PATCH_DIR/ieee802_mib.h $PATCH_1_4c_ADK_DIR/linux-2.4.18/drivers/net/wireless_ag

cp -v --remove-destination $CMK_1_4c_PATCH_DIR/ieee802_mib.h $PATCH_1_4c_SDK_DIR/linux-2.4.18/drivers/net/wireless_ag

cp -v --remove-destination $CMK_1_4c_PATCH_DIR/rtl8186.tar.gz $PATCH_1_4c_SDK_DIR/linux-2.4.18

cp -v --remove-destination $CMK_1_4c_PATCH_DIR/mkimg $PATCH_1_4c_ADK_DIR/AP

# step 3: upgrade ADK and SDK v1.4b to v1.4c_with_latest_patches
#
# Note: Watch for the "/*" because the paths are only _directory paths_.
# That's why ypu have to append them with an "/*" to ensure you don't break
# the directory structure of the ADK/SDK and that you replace the right
# files and directories.
#
cp -r -v --remove-destination $PATCH_1_4c_ADK_DIR/* $RTL8186_ASP_DIR
cp -r -v --remove-destination $PATCH_1_4c_SDK_DIR/* $RTL8186_LINUX_DIR

# step 4 create Antek RTL8186 SDK from patched ADK, SDK and CMK
rm -rf $ANTEK_RTL_SDK_DIR
mkdir $ANTEK_RTL_SDK_DIR

cp -rf $RTL8186_ASP_DIR/AP $ANTEK_RTL_SDK_DIR
cp -rf $RTL8186_LINUX_DIR/linux-2.4.18 $ANTEK_RTL_SDK_DIR

mkdir -v $ANTEK_RTL_SDK_DIR/tool
cp -rvf $CMK_1_4c_CONFIG_DIR $ANTEK_RTL_SDK_DIR/tool
tar xvzf $CMK_1_4c_LINUX_TOOLS -C $ANTEK_RTL_SDK_DIR/tool/

cp -vf $SDK_TOOLCHAIN $ANTEK_RTL_SDK_DIR/tool
cp -vf $SDK_BOOTCODE $ANTEK_RTL_SDK_DIR/tool

# inform that we're done
echo "Realtek RTL8186 SDK v1.4c installed."


Next, you can do the first step to examine whether you have applied the patch correctly.
Actually, analysis of the patching result can be automated with shell script as well. But, let's leave it for another installment of this diff series of tutorial.

That's it for now. Ciao.