1. 程式人生 > >ARM上的linux如何實現無線網絡卡的冷插拔和熱插拔

ARM上的linux如何實現無線網絡卡的冷插拔和熱插拔

ARM上的linux如何實現無線網絡卡的冷插拔和熱插拔

fulinux

1. 冷插拔

如果在系統上電之前就將RT2070/RT3070晶片的無線網絡卡(以下簡稱wlan)插上,即冷插拔。我們通過分析系統啟動流程過程中的執行的指令碼,將啟動wlan的指令碼加入其中,就可以實現自動執行wlan.

系統啟動後的第一個程序/sbin/initinit程序最主要的功能就是準備軟體執行的環境,包括系統的主機名、網路配置、語系處理、檔案系統格式以及其他服務的啟動等。而所有的操作都會通過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 >: 

#上面這個正則表示式的目的是提取出網絡卡名,例如eth0wlan0,其中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是一個特殊的回送地址(即預設的本機地址),可以在自己的系統上用telnetIP地址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

#如果這時候$iwlan0,則下面的目的是提取出ifcfg-wlan0檔案中的DEVICETYPE等號後面的內容。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,也有可能是StaAp書寫方法,通過下面的第一個語句就可以將這些選項統統裝化為大寫模式,toupper()是一個轉換為大寫的函式。如果不是STAstation)模式,就賦值為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}'

roo這樣可以獲得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                                                                                           

}                                                                                               

#配置wifistation模式。                                                                                     

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字元長度不為0DEFROUTE選項為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檔案中,其中“>”和“>>”是重定向:

1shell遇到”>”操作符,會判斷右邊檔案是否存在,如果存在就先刪除,並且建立新檔案。不存在直接建立。 無論左邊命令執行是否成功。右邊檔案都會變為空。

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.2128段內的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                                                                    

#