找回密码
立即注册
搜索
发回帖 发新帖

5180

积分

0

好友

656

主题
发表于 昨天 23:20 | 查看: 12| 回复: 0

嵌入式Linux系统大多支持WiFi联网,实际项目中既可以通过Shell脚本,也可以用C/C++等语言编程实现。本文以飞凌开发板自带的WiFi启动脚本为例,拆解一套Shell脚本配置WiFi并完成联网的完整流程。

1. sh脚本WiFi联网介绍

这里以飞凌开发板中的WiFi启动脚本为例来介绍。

飞凌嵌入式FETMX6ULL-C开发板接口标注:WiFi天线、HDMI、串口调试、12V DC

在飞凌开发板的串口中,执行如下命令,调用 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 进程,就把它停掉。

hostapd在开发板上创建无线AP流程图

如果 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。

wpa_supplicant连接WiFi示意图

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:用于获取动态IP地址的客户端程序。

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配网。




上一篇:Agent 动手之后的麻烦:ReAct、Function Calling 与自主循环拆解
下一篇:嵌入式Linux C++ WiFi配网实战:调用wpa_supplicant与交叉编译验证
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-22 07:27 , Processed in 0.118147 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表