#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命令。查看
[lingyun@vmlinux fulinux]$ man source
. filename [arguments]
这里是使能ifcfg-wlan0配置文件,如下:
/apps/etc/network >: vim 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
WORKMODE=STA
#BOOTPROT should be static or dhcp, it will only take effact
#when the NIC work on STA mode
BOOTPROTO=dhcp
#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=no
#DHCP Server configuration, only take effact when the NIC work on AP mode
DHCP_SERVER=yes
DHCP_START_IP=192.168.1.10
DHCP_END_IP=192.168.1.100
DHCP_NETMASK=255.255.255.0
DHCP_GATEWAY=192.168.1.1
DHCP_DNS1=4.2.2.2
DHCP_DNS2=8.8.8.8
DHCP_LEASE=18800
使能了这些文件后上面的一些参数就成为系统中的全局参数,比如说我在下面加入如下代码时,
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"
#[lingyun@localhost ~]$ 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
#[lingyun@localhost ~]$ipcalc -p 192.168.1.1 255.255.255.0
PREFIX=24
#[lingyun@localhost ~]$ipcalc -n 192.168.1.1 255.255.255.0
NETWORK=192.168.1.0
#[lingyun@localhost ~]$ipcalc -h 192.168.1.1
HOSTNAME=dbrg-2
#[lingyun@localhost ~]$ipcalc -m 192.168.1.1
NETMASK=255.255.255.0
#[lingyun@localhost ~]$ipcalc -pnbm 192.168.1.1 255.255.255.0
NETMASK=255.255.255.0
PREFIX=24
BROADCAST=192.168.1.255
NETWORK=192.168.1.0
#[lingyun@localhost ~]$
所以下面的意图是取得子网的网络地址。例如
[lingyun@localhost ~]$ ipcalc -n 192.168.5.1 255.255.255.0
NETWORK=192.168.5.0
[lingyun@localhost ~]$ ipcalc -n 192.168.5.1 255.255.255.0 | awk -F "=" '{print $2}'
192.168.5.0
[lingyun@localhost ~]$
DHCP_SUBNET=`ipcalc -n $DHCP_START_IP $DHCP_NETMASK | awk -F "=" '{print $ 2}`
#下面是将子网的网络地址、子网掩码、动态分配的起止地址、域名解析、网关、租约时间(IP默认失效时间)等写到/tmp/dhcpd_wlan0.config文件中,其中“>”和“>>”是重定向:
1、shell遇到”>”操作符,会判断右边文件是否存在,如果存在就先删除,并且创建新文件。不存在直接创建。 无论左边命令执行是否成功。右边文件都会变为空。
2、“>>”操作符,判断右边文件,如果不存在,先创建。以添加方式打开文件,会分配一个文件描述符[不特别指定,默认为1,2]然后,与左边的标准输出
形成下面类似的结构:
[root@localhost 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
#大多数情况下,DHCP 的安装不创建一个 dhcpd.leases 文件,在你启动 DHCP 服务器之前,你必须创建空文件 dhcpd.leases:
touch $lease_file
dhcpd -q -pf $pid_file -cf $conf_file -lf $lease_file $DEVICE
#
-q 安静模式
-pf 指定pid_file, 这里的pid file就是程序后台运行的时候,记录这个进程的进程号是多少;
-cf指定配置文件
-lf指定lease分配的IP地址文件
$DEVICE指定在哪个网卡上开启DHCP
fi
#下面启动AP模式
# Start hostapd to server on AP mode
mkdir -p /var/run/hostapd
/apps/tools/hostapd -B ${network_cfg_dir}/hostapd.conf
}
#真正的主题在这,上面相当于C函数,而这里相当于main函数。判断是不是STA模式,如果是就先关闭wifi,再启动STA模式,AP模式亦然
if [ $WORKMODE == "STA" ]; then
stop_wifi_worker
configure_wifi_sta
else
stop_wifi_worker
configure_wifi_ap
fi
#结束