嵌入式Linux之wifi配网脚本分析
嵌入式Linux系统,一般都支持wifi联网,可以通过sh脚本或其它语言代码编程来实现wifi联网。
本篇来介绍一种通过sh脚本来配置wifi的脚本执行原理。
1 sh脚本wifi联网介绍
这里以飞凌开发板中的wifi启动脚本为例来介绍。

在飞凌开发板的串口中,执行如下命令(调用fltest_wifi.sh脚本,并指定一些参数),进行wifi连接:
fltest_wifi.sh -i mlan0 -s "wifi_name" -p wifi_password
- wifi_name是自己的wifi名称
- wifi_password是对于的wifi密码
然后ifconfig指令可以查看板子IP信息:
[root@ok3568:/usr/sbin]# ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:239 errors:0 dropped:0 overruns:0 frame:0
TX packets:239 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:346556 (338.4 KiB) TX bytes:346556 (338.4 KiB)
mlan0 Link encap:Ethernet HWaddr E8:FB:1C:66:AF:DF
inet addr:192.168.5.111 Bcast:192.168.5.255 Mask:255.255.255.0
inet6 addr: fe80::eafb:1cff:fe66:afdf/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1799 errors:0 dropped:0 overruns:0 frame:0
TX packets:981 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:109635 (107.0 KiB) TX bytes:331552 (323.7 KiB)
[root@ok3568:/usr/sbin]#
可以看到,mlan0这个网络接口的IP为192.168.5.111
2 fltest_wifi.sh脚本文件分析
下面来具体分析fltest_wifi.sh脚本的内容。
2.1 开头部分分析
先来看开头的这段脚本:
cnt1=`ps aux | grep hostapd | grep -v grep | wc -l`
if [ "$cnt1" != "0" ];then
killall hostapd > /dev/null
fi
/etc/init.d/S80dnsmasq stop > /dev/null
分析:
首先是执行一条指令,确认正在运行的hostapd进程的个数,保存在cnt1变量中
ps aux:查看系统中当前正在运行的所有进程的详细信息| grep hostapd | grep -v grep:匹配包含hostapd 并且不包含grep字样的行| wc -l:统计行数(word count,字数统计)
注:“ps aux” 其实是一种组合使用的命令形式
- “ps” 是 “process status”(进程状态)的缩写
- “a” 表示显示所有用户(包括其他用户和终端用户)的进程,不仅仅是当前用户启动的进程
- “u” 表示以用户为导向的详细格式(user-oriented detailed format)来显示进程信息,会给出诸如启动进程的用户、进程占用的 CPU 和内存资源百分比、进程状态等更为详细的信息
- “x” 表示显示没有控制终端的进程,也就是那些在后台运行的、不是通过常规终端启动的进程
hostapd是Linux中一款用于创建无线接入点(Wireless Access Point,WAP)的软件
hostapd的功能是用来创建AP,因为是要连接wifi,而不是创建热点,所以如果有hostapd进程,则停掉。

如果cnt1不为0,则杀掉所有的hostapd进程
killall:用于通过进程名来终止一个或多个正在运行的进程>:Linux中常用的一种重定向操作,用于将命令的输出重定向到指定的位置/dev/null:一个特殊的设备文件,可以接收任何写入的数据,但会直接丢弃这些数据
然后,执行/etc/init.d/S80dnsmasq stop
2.1.1 S80dnsmasq脚本分析
S80dnsmasq 也是一个脚本,内容为:
#!/bin/sh
[ -f /etc/dnsmasq.conf ] || exit 0
case "$1" in
start)
printf "Starting dnsmasq: "
start-stop-daemon -S -x /usr/sbin/dnsmasq
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
stop)
printf "Stopping dnsmasq: "
start-stop-daemon -K -q -x /usr/sbin/dnsmasq
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
restart|reload)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit 0
先来看这一句,含义是检查指定文件dnsmasq.conf是否存在且为普通文件,若不存在,则退出
[ -f /etc/dnsmasq.conf ] || exit 0
分析:
[和]:这是test命令的一种语法糖形式(一种更简洁、方便书写的等效形式),用于条件测试。-f:这是test命令的一个选项参数,用于判断指定的对象是否为普通文件||:这是 shell 中的逻辑或运算符exit 0:shell 命令,退出当前的脚本执行环境或者命令行执行环境,返回值0表示正常退出
接下来,case用来判断脚本的输入参数并进行处理,如果参数是stop,则执行:
printf "Stopping dnsmasq: "
start-stop-daemon -K -q -x /usr/sbin/dnsmasq
[ $? = 0 ] && echo "OK" || echo "FAIL"
分析:
start-stop-daemon是一个用于管理守护进程(daemon)的工具,上述命令具体是要对dnsmasq这个守护进程进行某种操作。-K:该选项通常用于向指定的守护进程发送一个信号,以实现停止(kill)该进程的目的。-q:表示 “quiet”,即安静模式。在这种模式下,命令执行过程中不会产生太多的额外输出信息。-x /usr/sbin/dnsmasq:其中-x用于指定要操作的可执行文件路径,这里明确指定了要对位于/usr/sbin/dnsmasq的dnsmasq可执行文件所对应的守护进程进行操作。
dnsmasq是Linux中一款轻量级 DNS 转发器和 DHCP 服务器软件。
2.1.2 dnsmasq.conf
再来看下dnsmasq.conf 中的内容:
interface=uap0
bind-interfaces
except-interface=lo
dhcp-range=192.168.2.100,192.168.2.254,12h
dhcp-option=3,192.168.2.1
dhcp-option=6,192.168.2.1
它是dnsmasq软件的的一个配置文件
interface=uap0:指定了要绑定或进行相关网络操作的网络接口名称为uap0。bind-interfaces:指示软件要绑定到指定的网络接口(在这里就是前面提到的uap0接口)。它确保了相关的网络服务(如 DHCP 服务、DNS 转发等,如果适用)只会在这个特定接口上进行操作,而不会影响到其他未指定的接口。except-interface=lo:lo通常代表本地回环接口(loopback interface)。设置except-interface=lo表示在进行上述的绑定操作以及后续的网络服务提供过程中,要排除本地回环接口。dhcp-range=192.168.2.100,192.168.2.254,12h:作为 DHCP 服务器的配置项,它指定了要分配给客户端的 IP 地址范围以及租约期限。具体来说:192.168.2.100和192.168.2.254:这两个 IP 地址界定了可分配给客户端的 IP 地址区间。12h:表示租约期限为 12 小时。dhcp-option=3,192.168.2.1:这是设置 DHCP 选项的配置项。在这里的3通常代表默认网关选项(default gateway option)。dhcp-option=6,192.168.2.1:同样是设置 DHCP 选项的配置项。这里的6通常代表 DNS 服务器选项(DNS server option)。
2.2 参数解析部分
usage()和parse_args()是编写的两个函数,用于打印帮助信息和解析脚本的输入参数
function usage()
{
echo "Usage: -i -s -p "
echo "eg: ./wifi.sh -i mlan0 -s bjforlinx -p 12345678 "
echo "eg: ./wifi.sh -i mlan0 -s bjforlinx -p NONE "
echo " -i : mlan0 or mlan1"
echo " -s : wifi ssid"
echo " -p : wifi password or NONE"
}
function parse_args()
{
while true; do
case "$1" in
-i ) wifi=$2;echo wifi $wifi;shift 2 ;;
-s ) ssid=$2;echo ssid $ssid;shift 2 ;;
-p ) pasw=$2;echo pasw $pasw;shift 2 ;;
-h ) usage; exit 1 ;;
* ) break ;;
esac
done
}
if [ $# != 6 ]
then
usage;
exit 1;
fi
parse_args $@
该脚本的功能部分是:判断fltest_wifi.sh脚本的输入参数是否为6个:
- 如果不是,则打印帮助信息,并退出
- 如果是,则对脚本的6个输入参数进行解析
再来回顾下,6个参数:
fltest_wifi.sh -i mlan0 -s "wifi_name" -p wifi_password
2.3 连接wifi部分
连接wifi使用的是wpa_supplicant工具,wpa_supplicant全称Wi-Fi Protected Access Supplicant。

2.3.1 修改wpa_supplicant配置文件
if [ -e /etc/wpa_supplicant.conf ]
then
rm /etc/wpa_supplicant.conf
fi
echo \#PSK/TKIP >> /etc/wpa_supplicant.conf
echo ctrl_interface=/var/run/wpa_supplicant >>/etc/wpa_supplicant.conf
echo ctrl_interface_group=0 >>/etc/wpa_supplicant.conf
echo update_config=1 >>/etc/wpa_supplicant.conf
echo network={ >>/etc/wpa_supplicant.conf
echo ssid=\"$ssid\" >>/etc/wpa_supplicant.conf
echo scan_ssid=1 >>/etc/wpa_supplicant.conf
if [ $pasw == NONE ]
then
echo key_mgmt=NONE >>/etc/wpa_supplicant.conf
else
echo psk=\"$pasw\" >>/etc/wpa_supplicant.conf
echo key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE >>/etc/wpa_supplicant.conf
echo group=CCMP TKIP WEP104 WEP40 >>/etc/wpa_supplicant.conf
fi
echo } >>/etc/wpa_supplicant.conf
我们可以看下wpa_supplicant.conf最终被修改后的内容
#PSK/TKIP
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=0
update_config=1
network={
ssid="MERCURY_3394"
scan_ssid=1
psk="2H2+O2=2H2O"
key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
group=CCMP TKIP WEP104 WEP40
}
2.3.2 一些ifconfig指令关闭网络接口
ifconfig -a|grep mlan0 |grep -v grep > /dev/null
if [ $? -eq 0 ]
then
ifconfig mlan0 down > /dev/null
fi
ifconfig -a|grep mlan1 |grep -v grep > /dev/null
if [ $? -eq 0 ]
then
ifconfig mlan1 down > /dev/null
fi
ifconfig -a|grep eth0 |grep -v grep > /dev/null
if [ $? -eq 0 ]
then
ifconfig eth0 down > /dev/null
fi
ifconfig -a|grep eth1 |grep -v grep > /dev/null
if [ $? -eq 0 ]
then
ifconfig eth1 down > /dev/null
fi
分析:
ifconfig -a:用于查看系统中所有网络接口(包括已启用和未启用的)的详细配置信息- 然后查找mlan0、mlan1、eth0、eth1,如果有这些网络接口,则将其关闭
2.3.3 停掉wpa_supplicant
ps -fe|grep wpa_supplicant |grep -v grep > /dev/null
if [ $? -eq 0 ]
then
kill -9 $(pidof wpa_supplicant)
fi
分析:ps -fe 是全面详细地查看系统中所有用户启动的所有进程的状态信息
-f表示以全格式(full format)显示进程信息-e表示显示所有用户(包括其他用户和终端用户)的进程
如果存在wpa_supplicant进程在运行,则杀掉该进程
2.3.4 启用指定的网络接口
sleep 1
ifconfig $wifi up > /dev/null
sleep 1
up是ifconfig命令中设置网络接口为启用状态的一个参数。$wifi:是一个变量,在parse_args()中对其进行赋值,即mlan0这个网络接口。
2.3.5 通过wpa_supplicant进行配网
(wpa_supplicant -Dnl80211,wext -i$wifi -c/etc/wpa_supplicant.conf >/dev/null) &
echo "waiting..."
sleep 3
wpa_cli -i$wifi status |grep COMPLETED |grep -v grep >/dev/null
if [ $? -eq 0 ]
then
udhcpc -i $wifi
echo "Finshed!"
else
echo "try to connect again..."
sleep 3
wpa_cli -i$wifi status |grep COMPLETED |grep -v grep >/dev/null
if [ $? -eq 0 ]
then
udhcpc -i $wifi
echo "nameserver 114.114.114.114" > /etc/resolv.conf
echo "Finshed!"
else
echo "************************************************"
echo "connect faild,please check the passward and ssid"
kill -9 $(pidof wpa_supplicant)
exit 1
fi
fi
先来看第一条,该命令是在后台启动 wpa_supplicant 进程,并按照指定的参数进行无线网络配置相关的操作
(wpa_supplicant -Dnl80211,wext -i$wifi -c/etc/wpa_supplicant.conf >/dev/null) &
主要分析wpa_supplicant的参数选项:
-D:用于指定驱动程序类型。nl80211和wext:是两种常见的无线网卡驱动程序类型。在这里同时指定这两种驱动程序类型。-i:用于指定要连接的无线网络接口名称。-c:用于指定配置文件的路径。
等待3秒后,再来看这条指令,用于检查通过指定无线网络接口连接wifi的认证过程是否已经完成:
wpa_cli -i$wifi status |grep COMPLETED |grep -v grep >/dev/null
分析:
wpa_cli:是与wpa_supplicant配套使用的命令行工具,用于与wpa_supplicant进程进行交互。-i:用于指定要连接的无线网络接口名称。status:是wpa_cli命令的一个操作,用于查询指定无线网络接口的连接状态信息。- 然后查找输出信息中是否包含COMPLETED字样
我们可以手动输入前半部分指令:
[root@ok3568:/usr/sbin]# wpa_cli -imlan0 status
bssid=f4:ee:14:1b:33:94
freq=2412
ssid=MERCURY_3394
id=0
mode=station
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=192.168.5.111
p2p_device_address=e8:fb:1c:66:af:df
address=e8:fb:1c:66:af:df
uuid=dbddbcf1-3fcd-54be-b9aa-57858a84189f
[root@ok3568:/usr/sbin]#
可以看到,wpa_state=COMPLETED
根据查询结果,如果连接成功,则尝试获取一个动态 IP 地址。如果失败,则继续尝试连接:
if [ $? -eq 0 ]
then
udhcpc -i $wifi
echo "Finshed!"
else
echo "try to connect again..."
udhcpc:用于获取动态 IP 地址的客户端程序。
udhcpc是Linux中一个常用的动态主机配置协议(DHCP)客户端程序,用于从网络中的 DHCP 服务器获取动态 IP 地址以及相关的网络配置参数。
- 获取动态IP
- 获取获取动态IP获取(子网掩码、动态网关、DNS服务器地址)
2.4 整体回顾
- 停掉hostapd(创建WAP无线接入点的软件)
- 停掉dnsmasq(DNS 转发器和 DHCP 服务器软)
- 读取解析参数(网络接口名、wifi名称、wifi密码)
- 根据参数,修改/etc/wpa_supplicant.conf文件
- 关闭mlan0、mlan1、eth0、eth1这些网络接口
- 停掉wpa_supplicant
- 启用指定的网络接口(mlan0)
- 通过wpa_supplicant进行配网(搭配wpa_supplicant.conf文件)
- 使用udhcpc获取一个动态 IP 地址
另外,这里再整理一些易混的名词:
AP:Access Point,无线接入点
WPA:Wi-Fi Protected Access,Wi-Fi安全的无线接入点
hostapd:是Linux系统中带加密功能的无线接入点(AP)程序
hostapd_cli:是hostapd中包含一个基于文本的使用工具
wpa_supplicant:(Wi-Fi Protected Access Supplicant)用来扫描和连接AP,后台运行
wpa_cli:用来搜索、设置和连接网络
udhcpd:工作在server端的DHCP服务,用来为设备分配IP地址
udhcpc:工作在client端的DHCP服务,用来获取IP地址
3 总结
本篇,以飞凌嵌入式Linux开发板为例,介绍了其自带的wifi配网脚本的执行原理。通过自动配置wpa_supplicant.conf文件,并调用wpa_supplicant进行wifi配网。下篇,将继续介绍如何通过C/C++编程,来实现wifi配网。





