嵌入式Linux系统大多支持WiFi联网,实际项目中既可以通过Shell脚本,也可以用C/C++等语言编程实现。本文以飞凌开发板自带的WiFi启动脚本为例,拆解一套Shell脚本配置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:统计行数。
注:“ps aux”其实是一种组合命令形式。
“ps”是“process status”的缩写;
“a”表示显示所有用户的进程,而不仅仅是当前用户启动的进程;
“u”表示以用户为导向的详细格式显示进程信息,例如启动用户、CPU和内存占用、进程状态等;
“x”表示显示没有控制终端的进程,也就是那些在后台运行、不是通过常规终端启动的进程。
hostapd 是Linux中一款用于创建无线接入点的软件。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
先看这一句:
[ -f /etc/dnsmasq.conf ] || exit 0
它的作用是检查指定文件 dnsmasq.conf 是否存在且为普通文件,如果不存在,就退出脚本。
分析:
[ 和 ]:这是 test 命令的语法糖形式,用于条件测试;
-f:test 命令的选项,用于判断指定对象是否为普通文件;
||:shell中的逻辑或运算符;
exit 0:退出当前脚本执行环境,返回值0表示正常退出。
接下来的 case 用来判断脚本的输入参数并做相应处理。如果参数是 stop,就会执行:
printf "Stopping dnsmasq: "
start-stop-daemon -K -q -x /usr/sbin/dnsmasq
[ $? = 0 ] && echo "OK" || echo "FAIL"
分析:
start-stop-daemon 是一个用于管理守护进程的工具,这里用于操作 dnsmasq 守护进程;
-K:向指定守护进程发送信号,以实现停止该进程的目的;
-q:表示安静模式,执行过程中不会产生太多额外输出;
-x /usr/sbin/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:指示软件绑定到指定网络接口,确保相关网络服务只在该接口上操作;
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地址区间,12h 表示租约期限为12小时;
dhcp-option=3,192.168.2.1:设置DHCP选项,3 通常代表默认网关选项;
dhcp-option=6,192.168.2.1:同样设置DHCP选项,6 通常代表DNS服务器选项。
2.2 参数解析部分
usage() 和 parse_args() 是脚本里定义的两个函数,分别用于打印帮助信息和解析输入参数。
function usage()
{
echo "Usage: -i <wifi> -s <ssid> -p <password>"
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个,就解析这6个输入参数。
回顾一下6个参数:
fltest_wifi.sh -i mlan0 -s "wifi_name" -p wifi_password
2.3 连接wifi部分
连接WiFi使用的是 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:以全格式显示进程信息;
-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 "Finished!"
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 "Finished!"
else
echo "************************************************"
echo "connect failed, please check the password 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秒后,脚本检查指定无线网络接口的认证过程是否已完成:
wpa_cli -i$wifi status |grep COMPLETED |grep -v grep >/dev/null
分析:
wpa_cli:与 wpa_supplicant 配套使用的命令行工具,用于交互;
-i:指定无线网络接口名称;
status:查询指定无线网络接口的连接状态信息;
- 然后查找输出中是否包含
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。
脚本随后判断上一条命令的执行结果:如果为0,说明连接成功,就执行 udhcpc -i $wifi 获取动态IP;否则提示重试,等待3秒再次检测,若仍失败则输出错误信息并结束。
udhcpc 是Linux中常用的DHCP客户端程序,用于从网络中的DHCP服务器获取动态IP地址以及相关网络配置参数,例如子网掩码、默认网关、DNS服务器地址。
2.4 整体回顾
整体流程可以概括为:
- 停掉
hostapd;
- 停掉
dnsmasq;
- 读取并解析参数;
- 根据参数修改
/etc/wpa_supplicant.conf;
- 关闭
mlan0、mlan1、eth0、eth1 网络接口;
- 停掉
wpa_supplicant;
- 启用指定的网络接口
mlan0;
- 通过
wpa_supplicant 搭配配置文件进行配网;
- 使用
udhcpc 获取动态IP地址。
另外,整理一些容易混淆的名词:
AP:Access Point,无线接入点
WPA:Wi-Fi Protected Access,保护Wi-Fi安全的接入协议
hostapd:Linux系统中带加密功能的无线接入点程序
hostapd_cli:hostapd 中包含的一个基于文本的工具
wpa_supplicant:Wi-Fi Protected Access Supplicant,用于扫描和连接AP,后台运行
wpa_cli:用于搜索、设置和连接网络
udhcpd:工作在服务端的DHCP服务,用于为设备分配IP地址
udhcpc:工作在客户端的DHCP服务,用于获取IP地址
3. 总结
本篇以飞凌嵌入式Linux开发板为例,介绍了其自带的WiFi配网脚本执行原理:先清理可能冲突的服务和进程,再解析输入参数,自动修改 wpa_supplicant.conf,最终调用 wpa_supplicant 完成WiFi配网。下一篇,将继续介绍如何通过C/C++编程来实现WiFi配网。