ARM上的linux如何實現無線網絡卡的冷插拔和熱插拔
ARM上的linux如何實現無線網絡卡的冷插拔和熱插拔
fulinux
1. 冷插拔
如果在系統上電之前就將RT2070/RT3070晶片的無線網絡卡(以下簡稱wlan)插上,即冷插拔。我們通過分析系統啟動流程過程中的執行的指令碼,將啟動wlan的指令碼加入其中,就可以實現自動執行wlan.。
系統啟動後的第一個程序/sbin/init。init程序最主要的功能就是準備軟體執行的環境,包括系統的主機名、網路配置、語系處理、檔案系統格式以及其他服務的啟動等。而所有的操作都會通過init的配置檔案,即/etc/inittab來規劃。
在inittab檔案中有很多如下格式的語句:
label:runlevel:action:process
但是我們這裡只關注下面這條語句:
# now run any rc scripts
null::wait:/etc/init.d/rcS
即執行所有的rc 指令碼,這裡是執行rcS指令碼,rcS指令碼內容如下:
~ >: cat /etc/init.d/rcS
#!/bin/sh
# Copyright (C) 2011 GuoWenxue <[email protected] QQ:281143292>
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
$i
done
~ >:
很簡單的一個指令碼,即執行/etc/init.d/目錄下以S開頭,兩個?匹配任意兩個字元
*匹配0或多個字元。該目錄下有一個檔案S01_network,內容如下:
注:綠色為註釋
~ >: cat etc/init.d/S01_network
#!/bin/sh
# FILE:/etc/init.d/S01_network
# Copyright (C) 2012 GuoWenxue <[email protected] QQ:281143292>
# This file used to configure the network from the configure files
#network_cfg_dir變數是否為空,如果是將/apps/etc/network賦值給network_cfg_dir。
if [ -z "$network_cfg_dir" ] ; then
export network_cfg_dir=/apps/etc/network
Fi
#進入/apps/etc/network目錄
cd $network_cfg_dir
#~ >: cd apps/etc/network/
/apps/etc/network >: ls
bakifcfg-wlan0 ifcfg-eth0 resolv.conf
gatewayD.conf ifcfg-ppp10 wpa_supplicant.conf
hostapd.conf ifcfg-wlan0
/apps/etc/network >:
#上面這個正則表示式的目的是提取出網絡卡名,例如eth0、wlan0,其中wlan0為我們所需要的。
interfaces=$( ls ifcfg* | \
sed -e '/ifcfg-[A-Za-z0-9\._-]\+$/ { s/^ifcfg-//g;s/[0-9]/ &/}' | \
sort -k 1,1 -k 2n | \
sed 's/ //')
#如果網絡卡還沒有配置好,那麼執行:#ifconfig 系統只會輸出以lo 為首的部分。lo 是look-back網路介面,從IP地址127.0.0.1就可以看出,它代表本機。無論系統是否接入網路,這個裝置總是存在的,除非你在核心編譯的時候禁止了網路支援,這是一個稱為回送裝置的特殊裝置,它自動由Linux配置以提供網路的自身連線。IP地址127.0.0.1是一個特殊的回送地址(即預設的本機地址),可以在自己的系統上用telnet對IP地址127.0.0.1進行測試。如果有inetd程序在執行的話您會從自己的機器上獲得登入提示符。Linux可以利用這個特徵在程序與模擬網路之間進行通訊。(您有興趣的話還可以試試本機的實際IP地址,如這裡的機器就是210.34.6.89,或者試試"localhost",或者"127.0.0.1",同樣可以模擬網路通訊。這可是Linux一個非常突出的優點!)
ifconfig lo 127.0.0.1
# No interface configure, then use the default IP address
如果/apps/etc/network目錄下沒有帶網絡卡名的檔案,這時interface變數為空,配置eth0網絡卡,之後退出。
if [ -z "$interfaces" ] ; then
ifconfig eth0 192.168.1.223 up
exit
fi
# Set up all the interface
設定所有網絡卡介面
for i in $interfaces; do
#unset刪除變數或函式
unset DEVICE TYPE
#如果這時候$i為wlan0,則下面的目的是提取出ifcfg-wlan0檔案中的DEVICE、TYPE等號後面的內容。ifcfg-wlan0在該指令碼下面。
eval $(fgrep "DEVICE=" ifcfg-$i)
eval $(fgrep "TYPE=" ifcfg-$i)
#如果$DEVICE為空,著將$i的值賦給它。
if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi
#如果ifcfg-wlan0檔案中的ONBOOT不為no,時執行下面的語句。
if ! egrep -L "^ONBOOT=['\"]?[Nn][Oo]['\"]?" ifcfg-$i > /dev/null ; then
#下面是根據各自的TYPE值,執行相應的指令碼
if [ "$TYPE" = "Ethernet" ] ; then
echo "Bring up $TYPE interface $i"
/usr/sbin/ifup-eth $i
elif [ "$TYPE" = "PPP" ] ; then
echo "Bring up $TYPE interface $i"
elif [ "$TYPE" = "WLAN" ] ; then
# Just bring up the wiFi module here. Configure it in the followed shell scripts
#如果是WLAN,存在目錄/sys/class/net/wlan0/就會執行下面的命令,其中/apps/tools/ifup-wlan是一個指令碼。在ifcfg-wlan0配置檔案下面。
if [ -d /sys/class/net/$DEVICE/ ] ; then
/apps/tools/ifup-wlan $i
fi
else
echo "Bring up $TYPE interface $i"
fi
fi
# for迴圈結束
done
#結束
~ >:
1.1. ifcfg-wlan0配置檔案
/apps/etc/network/ifcfg-wlan0配置檔案中的內容如下:
/apps/etc/network >: cat ifcfg-wlan0
#Wireless Network adapter RT3070(wlan0) device configure file
#FILE:/apps/etc/network/ifcfg-wlan0
# Copyright (C) 2012 GuoWenxue <[email protected] QQ:281143292>
DEVICE=wlan0
ONBOOT=yes
NAME="RT3070"
TYPE=WLAN
#The WiFi Module should work on AP or STA mode
#AP mode 是類似於一個不帶有限介面lan的無線路由,即市面上的迷你無線路由,STA mode是無線上網終端一般所用的模式。我們要向無線上網就必須使用STA mode
WORKMODE=STA
#WORKMODE=AP
#BOOTPROT should be static or dhcp, it will only take effact
#when the NIC work on STA mode
#可以說靜態分配ip,也可以使用DHCP動態分配ip.這裡使用靜態,靜態建立連線到速度快。
BOOTPROTO=static
#這是AP模式要使用的配置
#Work on AP mode IP address
IPADDR_AP=192.168.5.1
NETMASK_AP=255.255.255.0
#Work on STA mode IP address
IPADDR_STA=192.168.1.166
NETMASK_STA=255.255.255.0
#Gateway Settings
GATEWAY=192.168.1.1
DEFROUTE=yes
#DHCP Server configuration, only take effact when the NIC work on AP mode
#這是AP模式要使用的配置
DHCP_SERVER=yes
DHCP_START_IP=192.168.5.10
DHCP_END_IP=192.168.5.100
DHCP_NETMASK=255.255.255.0
DHCP_GATEWAY=192.168.5.1
DHCP_DNS1=4.2.2.2
DHCP_DNS2=8.8.8.8
DHCP_LEASE=18800
1.2. ifup-wlan指令碼
#ifup-wlan指令碼解析
/apps/etc/init.d >: vim /apps/tools/ifup-wlan
#!/bin/sh
# FILE:/usr/sbin/ifup-wlan0
# Copyright (C) 2011 GuoWenxue <[email protected] QQ:281143292>
# This file used to configure the specified network interface device
source /etc/profile
#判斷目錄是否存在,如果不存在,則賦值為/apps/etc/network目錄。
if [ -z "$network_cfg_dir" ]; then
export network_cfg_dir=/apps/etc/network
fi
#將傳入的引數賦值給DEVICE ,$1和${1}的區別,例如:
val=10
test=${val}ue 這種情況下,是獲取val變數的值,則test=10ue
text=$value 這種情況下,是獲取value變數的值,這裡value未定義
這兩個是不一樣的:
帶括號的話,所以{}使用來標識哪一部分是變數名
/*****************************轉載宣告****************************/
DEVICE=${1}
#下面這個是一個很巧妙的語句,關鍵是&&,”[]”這個也具有判斷的功能,一般執行與判斷時,如果第一個判斷語句是假,則不必往下執行,如果為真就會判斷下一個語句。這裡如果傳進來的引數有不為空,即為真時,就會執行與後面的語句列印資訊,並退出指令碼。
[ -z "${DEVICE}" ] && {
echo $"Usage: $0 <device name>" >&2
exit 1
}
#下面的判斷語句中-o是或的意思,檢視man test
( EXPRESSION )
EXPRESSION is true 真判定
! EXPRESSION
EXPRESSION is false 否判定
EXPRESSION1 -a EXPRESSION2
both EXPRESSION1 and EXPRESSION2 are true 與判定
EXPRESSION1 -o EXPRESSION2
either EXPRESSION1 or EXPRESSION2 is true 或判定
-d FILE
FILE exists and is a directory
-f FILE
FILE exists and is a regular file
if [ ! -d $network_cfg_dir -o ! -f "$network_cfg_dir/ifcfg-${DEVICE}" ]; then
echo "$0: configuration<$network_cfg_dir/ifcfg-${DEVICE}> not found." >&2
echo "Usage: $0 <device name>" >&2
exit 1
fi
#判斷/sys/class/net/wlan0是否存在,說明沒有wlan0介面卡退出
if [ ! -d /sys/class/net/$DEVICE/ ] ; then
echo "Wireless network adapter $DEVICE dosn't exist, exit now..."
exit
fi
#其中有個“。”相當於source命令。檢視
[[email protected] fulinux]$ man source
. filename [arguments]
這裡是使能ifcfg-wlan0配置檔案。
使能了這些檔案後上面的一些引數就成為系統中的全域性引數,比如說我在下面加入如下程式碼時,
cd $network_cfg_dir
. ifcfg-${DEVICE}
echo "print wifi workmode is $WORKMODE"
會列印如資訊
/apps/tools >: sh ifup-wlan wlan0
print wifi workmode is STA
因為是在指令碼中使能了這個檔案,所以相當於建立了一個子程序,如果退出這個指令碼後出來執行echo $WORKMODE不會有什麼顯示。
cd $network_cfg_dir
. ifcfg-${DEVICE}
#由於配置檔案中的WORKMODE的選項很肯使用小寫的sta或是ap,也有可能是Sta和Ap書寫方法,通過下面的第一個語句就可以將這些選項統統裝化為大寫模式,toupper()是一個轉換為大寫的函式。如果不是STA(station)模式,就賦值為AP模式。
WORKMODE=$(echo $WORKMODE | awk '{ print toupper($0) }')
if [ $WORKMODE != "STA" ] ; then
WORKMODE="AP"
fi
echo "Enable network interface $DEVICE[$NAME] work on $WORKMODE mode." >&2
#下面主要的是理解eval命令,可以通過在shell中拆解來理解,如下
/apps/etc/network >: export WORKMODE=STA
/apps/etc/network >: export IPADDR_STA=192.168.1.166
/apps/etc/network >: echo $WORKMODE
STA
/apps/etc/network >: echo \$IPADDR_$WORKMODE
$IPADDR_STA
/apps/etc/network >: eval "echo \$IPADDR_$WORKMODE"
192.168.1.166
/apps/etc/network >:
也就是把192.168.1.166賦值給ipaddr,同理netmask=255.255.255.0
parser_ip()
{
unset ipaddr netmask
ipaddr=$(eval "echo \$IPADDR_$WORKMODE")
netmask=$(eval "echo \$NETMASK_$WORKMODE")
}
#下面這一個是關掉wifi介面卡的函式。
stop_wifi_worker()
{
#stop DHCP work on this NIC
#分解執行分析如下:
/apps/etc/network >: ps | grep dhcp
5385 root 1332 S udhcpc -i eth0
10678 root 1324 S udhcpc -i wlan0
11598 root 1316 S grep dhcp
/apps/etc/network >: ps | grep dhcp | grep -v grep
5385 root 1332 S udhcpc -i eth0
10678 root 1324 S udhcpc -i wlan0
/apps/etc/network >: ps | grep dhcp | grep -v grep | grep wlan
10678 root 1324 S udhcpc -i wlan0
/apps/etc/network >: ps | grep dhcp | grep -v grep | grep wlan | awk '{print $1}'
10678
/apps/etc/network >: ps | grep dhcp | grep -v grep | grep wlan | awk '{print $2}'
root 這樣可以獲得udhcpc -i wlan0的程序id,並將其殺死。下同。
dhcp_pid=`ps | grep -v grep | grep "dhcp" | grep $DEVICE | awk '{print $1;}'`
if [ -n "$dhcp_pid" ] ; then
kill $dhcp_pid
fi
ifconfig $DEVICE 0.0.0.0
#Stop wpa_supplicant work on STA mode
pid=`ps | grep -v grep | grep "wpa_supplicant" | grep $DEVICE | awk '{print $1;}'`
if [ -n "$pid" ] ; then
kill $pid
sleep 1
fi
if [ -d /var/run/wpa_supplicant ] ; then
rm -rf /var/run/wpa_supplicant
fi
#Stop hostapd work on AP mode
pid=`ps | grep -v grep | grep "hostapd" | awk '{print $1;}'`
if [ -n "$pid" ] ; then
kill $pid
sleep 1
fi
if [ -d /var/run/hostapd ] ; then
rm -rf /var/run/hostapd
fi
}
#配置wifi為station模式。
configure_wifi_sta()
{
parser_ip
#If enable DHCP configure or IP address not configured, then use DHCP get IP address and exit
#man test 可以檢視下面判斷選項的意思
-n STRING
the length of STRING is nonzero
字串的長度不為0為真
STRING equivalent to -n STRING
-z STRING
the length of STRING is zero
字串的長度為0為真
-o選項是或運算
if [ -n "$BOOTPROTO" -o -z "$ipaddr" ]; then
BOOTPROTO=$(echo $BOOTPROTO | awk '{ print toupper($0) }')
if [ "$BOOTPROTO" = "DHCP" ] ; then
ifconfig $DEVICE up
#Start wpa_supplicant to work now
#連線路由命令,這裡使用的配置檔案是apps/etc/network/目錄下的wpa_supplicant.conf
/apps/tools/wpa_supplicant -B -Dwext -i$DEVICE -c${network_cfg_dir}/wpa_supplicant.conf
#再為我們的wifi動態分配ip地址,並且是後臺執行。
udhcpc -i $DEVICE &
exit
fi
fi
# Calculate the network configuration value
#如果沒有上面的動態分配且不存在子網掩碼,就需要分配一個
if [ -z "${netmask}" ] ; then
eval $(/bin/ipcalc --netmask ${ipaddr})
fi
#Configure for the WiFi interface IP address and bring up it
#靜態分配ip地址和掩碼。
ifconfig $DEVICE $ipaddr netmask $netmask up
#Set the default route
#把DEFROUTE選項都轉化為大寫。
DEFROUTE=$(echo $DEFROUTE | awk '{ print toupper($0) }')
#如果GATEWAY字元長度不為0且DEFROUTE選項為YES時,
if [ -n "$GATEWAY" -a "$DEFROUTE" = "YES" ]; then
#ip route add ${NETWORK}/${PREFIX} via $GATEWAY > /dev/null 2>&1
ip route replace default via $GATEWAY
fi
#Start wpa_supplicant to work now
mkdir -p /var/run/wpa_supplicant
/apps/tools/wpa_supplicant -B -Dwext -i$DEVICE -c${network_cfg_dir}/wpa_supplicant.conf
}
#通過將rt2070/rt3070配置為AP模式後,我們的筆記本和手機就能連線到wlan0上來,再通過netfilter/iptables構建的防火牆,使eth0接有線連線到internet上,我們的筆記本和手機就能通過它上網 -_-||
configure_wifi_ap()
{
parser_ip
#Configure for the WiFi interface IP address and bring up it
#如果ipaddr長度為0,就靜態分配ipaddr
if [ -z "$ipaddr" ] ; then
ipaddr=192.168.1.166
netmask=255.255.255.0
fi
ifconfig $DEVICE $ipaddr netmask $netmask up
#Enable DHCP server
#使能DHCP服務功能,這樣我們就不用為每臺連線到開發板上的電腦和手機靜態分配ip地址,而是通過開發板上的DHCP服務為每一臺連線的終端裝置動態分配地址。
DHCP_SERVER=$(echo $DHCP_SERVER | awk '{ print toupper($0) }')
#如果$DHCP_SERVER 長度不為空,且$DHCP_SERVER為YES時才為真。
if [ -n "$DHCP_SERVER" -a "$DHCP_SERVER" = "YES" ]; then
#定義一些配置檔案:/tmp/dhcpd_wlan0.config , /tmp/dhcpd_wlan0.leases , /var/run/dhcpd_wlan0.pid
conf_file="/tmp/dhcpd_${DEVICE}.conf"
lease_file="/tmp/dhcpd_${DEVICE}.leases"
pid_file="/var/run/dhcpd_${DEVICE}.pid"
#[[email protected] ~]$ ipcalc -h
ipcalc: ip address expected
Usage: ipcalc [OPTION...]
-c, --check Validate IP address for specified address family
-4, --ipv4 IPv4 address family (default)
-6, --ipv6 IPv6 address family
-b, --broadcast Display calculated broadcast address(顯示指定ip和子網掩碼的廣播地址)-h, --hostname Show hostname determined via DNS(顯示指定ip的主機名)-m, --netmask Display default netmask for IP (class A, B, or C)(顯示指定ip的子網掩碼--特指預設,實際未必是)-n, --network Display network address(顯示指定ip的網路地址)-p, --prefix Display network prefix(顯示網路字首)-s, --silent Don't ever display error messages (不顯示錯誤資訊)
Help options:
-?, --help Show this help message
--usage Display brief usage message
#[[email protected] ~]$ipcalc -p 192.168.1.1 255.255.255.0PREFIX=24#[[email protected] ~]$ipcalc -n 192.168.1.1 255.255.255.0NETWORK=192.168.1.0#[[email protected] ~]$ipcalc -h 192.168.1.1HOSTNAME=dbrg-2#[[email protected] ~]$ipcalc -m 192.168.1.1NETMASK=255.255.255.0#[[email protected] ~]$ipcalc -pnbm 192.168.1.1 255.255.255.0NETMASK=255.255.255.0PREFIX=24BROADCAST=192.168.1.255NETWORK=192.168.1.0#[[email protected] ~]$
所以下面的意圖是取得子網的網路地址。例如
[[email protected] ~]$ ipcalc -n 192.168.5.1 255.255.255.0
NETWORK=192.168.5.0
[[email protected] ~]$ ipcalc -n 192.168.5.1 255.255.255.0 | awk -F "=" '{print $2}'
192.168.5.0
[[email protected] ~]$
DHCP_SUBNET=`ipcalc -n $DHCP_START_IP $DHCP_NETMASK | awk -F "=" '{print $ 2}`
#下面是將子網的網路地址、子網掩碼、動態分配的起止地址、域名解析、閘道器、租約時間(IP預設失效時間)等寫到/tmp/dhcpd_wlan0.config檔案中,其中“>”和“>>”是重定向:
1、shell遇到”>”操作符,會判斷右邊檔案是否存在,如果存在就先刪除,並且建立新檔案。不存在直接建立。 無論左邊命令執行是否成功。右邊檔案都會變為空。
2、“>>”操作符,判斷右邊檔案,如果不存在,先建立。以新增方式開啟檔案,會分配一個檔案描述符[不特別指定,預設為1,2]然後,與左邊的標準輸出
形成下面類似的結構:
[[email protected] etc]# cat dhcpd.conf ddns-update-style interim; ignore client-updates; subnet 192.168.1.0 netmask 255.255.255.0 { # --- default gateway option routers 192.168.1.1; /*預設路由器地址*/ option subnet-mask 255.255.255.0; /*預設子網掩碼*/ option nis-domain "510.home"; /*為客戶機設定nis域*/ option domain-name "510.home"; /*客戶機所屬DNS域的域名*/ option domain-name-servers 192.168.1.1; /*DNS伺服器地址*/ option time-offset -18000; /*為客戶設定與格林威治時間的偏移時間*/ option host-name "myDhcpServer"; /*設定主機名*/ range dynamic-bootp 192.168.1.2 192.168.1.128 ; /*伺服器將為客戶分配192.168.1.2-128段內的ip*/ default-lease-time 21600; /*預設地址租期,單位為s*/ max-lease-time 43200; /*最長地址租期,單位為s*/ }
echo "subnet $DHCP_SUBNET netmask $DHCP_NETMASK { " > $conf_file
echo " range $DHCP_START_IP $DHCP_END_IP;" >> $conf_file
echo " option domain-name-servers $DHCP_DNS1, $DHCP_DNS2;" >> $conf_file
echo " option routers $DHCP_GATEWAY;" >> $conf_file
echo " default-lease-time $DHCP_LEASE;" >> $conf_file
echo " max-lease-time 72000;" >> $conf_file
echo " authoritative;" >> $conf_file
echo "}" >> $conf_file
#