嵌入式系统移植wifi功能


前言

由于项目需要开发一款家用云台摄像机(T31),其中有一个功能是要支持wifi功能,既要能充当热点热客户端能够链接,也要能充当客户端可以链接热点。

WIFI一般有以下四种工作模式

Master(AP)		成为无线接入点提供无线接入服务
Managed(STA)	        作为客户端连接其他无线接入点
Monitor			监听附近所有无线流量
Ad-hoc			多台计算机直接相连

这里使用的主要是 AP + STA 的模式

基本的功能设计大概是:

设备先起一个热点,从而使客户端可以搜索到设备的热点并链接设备。

通过设备搜索到附近的路由热点并配置链接,从而使设备可以链接路由。

手机断开设备的热点,并链接到路由,从而使设备和手机都链接到同一个路由。

画个草图凑合着看:


 
 

主要工作有以下几点:

内核选项的配置。

驱动的修改。

工具的移植。

上层的应用。

一、内核选项

具体需要哪些内核选项其实可以在工具移植后根据报错提示逐步修改。

二、驱动修改

由于我们需要WiFi模块既能上网也能做一个热点,用于初次使用的配置链接等。

所以我们需要同时支持AP + STA。

修改驱动配置文件

修改驱动配置文件

vi include/autoconf.h
找到如下部分,并修改
//#define CONFIG_CONCURRENT_MODE 
#ifdef CONFIG_CONCURRENT_MODE
//#define CONFIG_HWPORT_SWAP//Port0->Sec , Port1 -> Pri
#define CONFIG_RUNTIME_PORT_SWITCH
//#define DBG_RUNTIME_PORT_SWITCH
#define CONFIG_STA_MODE_SCAN_UNDER_AP_MODE
#define CONFIG_TSF_RESET_OFFLOAD// For 2 PORT TSF SYNC.
#endif

修改如下:
#define CONFIG_CONCURRENT_MODE 1
#ifdef CONFIG_CONCURRENT_MODE
	#define CONFIG_HWPORT_SWAP  //Port0->Sec , Port1 ->Pri 
	#define CONFIG_RUNTIME_PORT_SWITCH
	//#define DBG_RUNTIME_PORT_SWITCH
	#define CONFIG_STA_MODE_SCAN_UNDER_AP_MODE
	#define CONFIG_TSF_RESET_OFFLOAD1   // For 2 PORT TSF SYNC.
#endif

修改前后的对比如下:

左边是原始未修改的, 右边是修改之后的

我所用的开发板flash比较紧张,所以在不影响功能的前提下尽可能的裁剪体积

修改Mkefile, 关闭Debug可以减小驱动大小
########################## Debug ###########################
CONFIG_RTW_DEBUG = n

重新加载驱动后内核中就会多一个设备节点,我们就可以一个用于 STA,一个用于AP

三、工具移植

1.依赖的基础库编译

所依赖的为 ssl和libnl

#libnl库 编译
1.git下载opensource源码,此版本为3.2.x

    git clone git://github.com/tgraf/libnl.git

本次编译采用3.2.25的版本,切换方法如下:

    cd libnl
    git branch 3.2.25
    git checkout 3.2.25
    git reset --hard libnl3_2_25


2.编译

配置Makefile:
如果没有configure文件,需要执行`./autogen.sh`先生成configure

glibc版本:

    ./configure --host=mips-linux-gnu --prefix=${PWD}/_install_glibc

uclibc版本:

    CFLAGS="-muclibc -O2" CPPFLAGS="-muclibc -O2" LDFLAGS="-muclibc -O2" ./configure --host=mips-linux-gnu --prefix=${PWD}/_install_uclibc

如果需要编译链接的wpa,则需要加入`--disable-shared`,编译静态的libnl。例如:

glibc版本:

    ./configure --host=mips-linux-gnu --prefix=${PWD}/_install_glibc --disable-shared

uclibc版本:

    CFLAGS="-muclibc -O2" CPPFLAGS="-muclibc -O2" LDFLAGS="-muclibc -O2" ./configure --host=mips-linux-gnu --prefix=${PWD}/_install_uclibc --disable-shared

然后 :

    make;make install

---

#libopenssl 库编译
1.git下载opensource源码

    git clone git://git.openssl.org/openssl.git

注意,请使用1.0.2f版本,1.1.0版本的原生源码不支持uclibc。

切换到  1.0.2f版本

    cd openssl
    git branch 1.0.2f
    git checkout 1.0.2f
    git reset --hard OpenSSL_1_0_2f

2.编译

第一步:

配置Makefile:

glibc:

    ./Configure linux-generic32 shared -DL_ENDIAN --prefix=${PWD}/_install_glibc --openssldir=${PWD}/_install_glibc

uclibc:

    ./Configure linux-generic32 shared -DL_ENDIAN --prefix=${PWD}/_install_uclibc --openssldir=${PWD}/_install_uclibc

如果需要编译链接的wpa,则需要加入`no-shared no-dso`,编译静态的libnl。例如:

glibc:

    ./Configure linux-generic32 no-shared no-dso -DL_ENDIAN --prefix=${PWD}/_install_glibc --openssldir=${PWD}/_install_glibc

uclibc:

    ./Configure linux-generic32 no-shared no-dso -DL_ENDIAN --prefix=${PWD}/_install_uclibc --openssldir=${PWD}/_install_uclibc


第二步:

修改makefile

glibc版本:

默认 glibc版本 直接执行第三步

uclibc版本:

    vi Makefile

CFLAG 和 SHARED_LDFLAGS 添加-muclibc


    CFLAG= -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN
            -O3 -fomit-frame-pointer -Wall
    ...
    SHARED_LDFLAGS=
改成:

    CFLAG= -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN
             -O3 -fomit-frame-pointer -Wall -muclibc
    ...

    SHARED_LDFLAGS= -muclibc

第三步:

    make CC=mips-linux-gnu-gcc RANLIB=mips-linux-gnu-ranlib LD=mips-linux-gnu-ld MAKEDEPPROG=mips-linux-gnu-gcc PROCESSOR=MIPS
    make install

---

2.编译wpa_suppliant及使用

编译移植

1.git下载opensource源码,假设版本为2.5

    git clone git://w1.fi/hostap.git
    cd hostap
    git branch 2.5
    git checkout 2.5
    git reset --hard hostap_2_5

2.编译
第一步:

    cd hostap/wpa_supplicant
    cp defconfig .config

第二步:修改.config 添加 libnl openssl 库路径配置

    vi .config

在文件末尾添加如下

glibc版本:

    CC=mips-linux-gnu-gcc
    PWD-libnl = /your/install/path/_install_glibc
    PWD-openssl = /your/install/path/_install_glibc

    CFLAGS += -I/$(PWD-libnl)/include/libnl3/
    LIBS += -L/$(PWD-libnl)/lib
    LIBS_c += -L/$(PWD-libnl)/lib
    LIBS_p += -L/$(PWD-libnl)/lib
    CFLAGS += -I/$(PWD-openssl)/include/
    LIBS += -L/$(PWD-openssl)/lib
    LIBS_c += -L/$(PWD-openssl)/lib
    LIBS_p += -L/$(PWD-openssl)/lib

    LDFLAGS += -lpthread -lm

    CONFIG_LIBNL32=y
    CONFIG_EAP_FAST=y
    CONFIG_TLS=openssl

uclibc版本:


    CC=mips-linux-gnu-gcc
    PWD-libnl = /your/install/path/_install_uclibc
    PWD-openssl = /your/install/path/_install_uclibc

    CFLAGS += -I/$(PWD-libnl)/include/libnl3/
    LIBS += -L/$(PWD-libnl)/lib
    LIBS_c += -L/$(PWD-libnl)/lib
    LIBS_p += -L/$(PWD-libnl)/lib
    CFLAGS += -I/$(PWD-openssl)/include/
    LIBS += -L/$(PWD-openssl)/lib
    LIBS_c += -L/$(PWD-openssl)/lib
    LIBS_p += -L/$(PWD-openssl)/lib

    CFLAGS += -muclibc
    LDFLAGS += -muclibc -lpthread -lm

    CONFIG_LIBNL32=y
    CONFIG_EAP_FAST=y
    CONFIG_TLS=openssl

第三步:

    make -j4;

编译wpa_suppliant

**注意**:如果libnl和openssl编译为静态库,则wpa是静态链接的,如果前两者是动态链接的,则编译出的是动态链接的wpa

**注意**:编译出来的库和应用都是not stripped,可以用 mips-linux-gnu-strip 命令节省空间

*例子:*

    mips-linux-gnu-strip  wpa_supplicant

如果还是太大,可以用upx进一步压缩,upx的编译和安装,这里就不探讨了。
wpa_supplicant是一个连接、配置WIFI的工具。它主要包含两个程序:wpa_supplicant与wpa_cli。二者的关系就是server与client的关系。通常情况下,我们可以通过wpa_cli来进行WIFI的配置与连接

用法

启动wpa_supplicant应用

$ wpa_supplicant -D nl80211 -i wlan0 -c /etc/wpa_supplicant.conf -B
注意:/etc/wpa_supplicant.conf文件里是相关的配置,这里列出我用的配置。

 

ctrl_interface=/var/run/wpa_supplicant
update_config=1
network={
ssid="AP_TEST"
scan_ssid=1
psk="12345678"
key_mgmt=WPA-PSK"
}

由于ctrl_interface=/var/run/wpa_supplicant,因此要保证/var/run/目录的存在

###  启动wpa_cli应用

    $ wpa_cli -i wlan0 scan             搜索附近wifi网络
    $ wpa_cli -i wlan0 scan_result      打印搜索wifi网络结果
    $ wpa_cli -i wlan0 add_network      添加一个网络连接

如果要连接加密方式是:[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS] (wpa加密)  
wifi名称是:wifi_name  
wifi密码是:wifi_psk  

    $ wpa_cli -i wlan0 set_network 0 ssid '"wifi_name"'
    $ wpa_cli -i wlan0 set_network 0 psk '"wifi_psk"'
    $ wpa_cli -i wlan0 enable_network 0

如果要连接加密方式是:[WEP][ESS] (wep加密)  
wifi名称是:wifi_name  
wifi密码是:wifi_psk  

    $ wpa_cli -i wlan0 set_network 0 ssid '"wpa_name"'
    $ wpa_cli -i wlan0 set_network 0 key_mgmt NONE
    $ wpa_cli -i wlan0 set_network 0 wep_key0 '"wap_psk"'
    $ wpa_cli -i wlan0 enable_network 0

如果要连接加密方式是:[ESS] (无加密)  
wifi名称是:wifi_name

    $ wpa_cli -i wlan0 set_network 0 ssid '"wifi_name"'
    $ wpa_cli -i wlan0 set_network 0 key_mgmt NONE
    $ wpa_cli -i wlan0 enable_network 0

### 分配ip,netmask,gateway,dns

    $ udhcpc -i wlan0 -s /etc/udhcpc.script -q

执行完毕,就可以连接网络了。

### 保存连接

    $ wpa_cli -i wlan0 save_config

### 断开连接

    $ wpa_cli -i wlan0 disable_network 0

### 连接已有的连接

    $ wpa_cli -i wlan0 list_network             列举所有保存的连接
    $ wpa_cli -i wlan0 select_network 0         连接第1个保存的连接
    $ wpa_cli -i wlan0 enable_network 0         使能第1个保存的连接

### 断开wifi

    $ ifconfig wlan0 down
    $ killall udhcpc
    $ killall wpa_supplicant

我这里用到的其实只有
1、 wpa_cli -i wlan0 status //查看wifi链接状态

状态值
{
COMPLETED  已连接
INACTIVE
DISCONNECTED INTERFACE_DISABLED SCANNING AUTHENTICATING ASSOCIATING ASSOCIATED 4WAY_HANDSHAKE GROUP_HANDSHAKE
}

# ./wpa_cli -i wlan0 status
bssid=ec:26:ca:26:8f:f0
ssid=TP-LINK_8FF0
id=0
mode=station
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=192.168.1.102
address=54:f1:5f:a3:e1:a7

2、wpa_cli -i wlan0 scan_result      打印搜索wifi网络结果

3.编译hostapd及使用

编译

1、下载hostapd
可以到官网上下,主页:http://w1.fi/hostapd/, 我用的版本是 hostapd-2.5

解压并进入源码目录
tar -zxvf hostapd-2.5.tar.gz
cd hostapd-2.5/hostapd


2、配置hostapd,使它编译为支持nl80211驱动
修改Makefile指定你的编译器, 我用的是mips-linux-gnu-gcc
ifndef CC
CC=mips-linux-gnu-gcc
endif

cp defconfig .config
vi .config
找到“#CONFIG_DRIVER_NL80211=y”,如果被注释掉了去掉“#”符号。保存。


3、添加依赖的库
ssl和libnl

编译完成之后,在.config的末尾添加以下

CC=mips-linux-gnu-gcc
PWD-libnl = /home/work/tool_wifi/libnl-3.5.0/_install_uclibc
PWD-openssl = /home/work/tool_wifi/openssl-1.0.2d/_install_uclibc

CFLAGS += -I/$(PWD-libnl)/include/libnl3/
LIBS += -L/$(PWD-libnl)/lib
LIBS_c += -L/$(PWD-libnl)/lib
LIBS_p += -L/$(PWD-libnl)/lib
CFLAGS += -I/$(PWD-openssl)/include/
LIBS += -L/$(PWD-openssl)/lib
LIBS_c += -L/$(PWD-openssl)/lib
LIBS_p += -L/$(PWD-openssl)/lib

CFLAGS += -muclibc
LDFLAGS += -muclibc -lpthread -lm

CONFIG_LIBNL32=y
CONFIG_EAP_FAST=y
CONFIG_TLS=openssl

4、编译hostapd
make

将hostpad和hostapd_cli拷贝至开发板
开发板上执行./hostapd –v,输出版本信息,表示移植成功

# ./hostapd -v
hostapd v2.5
User space daemon for IEEE 802.11 AP management,
IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
Copyright (c) 2002-2015, Jouni Malinen <[email protected]> and contributors

**注意**:如果libnl和openssl编译为静态库,则hostapd是静态链接的,如果前两者是动态链接的,则编译出的是动态链接的hostapd

**注意**:编译出来的库和应用都是not stripped,可以用 mips-linux-gnu-strip 命令节省空间

*例子:*

    mips-linux-gnu-strip  hostapd

**注意**:如果libnl和openssl编译为静态库,则hostapd是静态链接的,如果前两者是动态链接的,则编译出的是动态链接的hostapd

**注意**:编译出来的库和应用都是not stripped,可以用 mips-linux-gnu-strip 命令节省空间

*例子:*

    mips-linux-gnu-strip  hostapd

还嫌大就upx

hostapd 即为热点程序。

hostapd_cli是用于访问hostapd并且获取当前ap信息和对ap进行操作的客户端程序。

用法

hostapd.conf文件配置说明
interface=wlan0
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
ssid=TEST_Wifi
hw_mode=g
channel=1
beacon_int=100
driver=nl80211
macaddr_acl=0
#deny_mac_file=/etc/hostapd.deny
#accept_mac_file=/etc/hostapd.accept
auth_algs=1
ignore_broadcast_ssid=0
own_ip_addr=127.0.0.1
wpa=2
wpa_passphrase=12345678
rsn_pairwise=TKIP CCMP
上面列出的配置基本上是必须的,其中:
ssid:别人所看到的我们这个无线接入点的名称;
WIFI Host AP 功能使用详解
WIFI Host AP 功能使用详解 2016/5/31wpa_passphrase:接入点密码,如果不设,即不加密
hw_mode:指定802.11协议,包括 a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE
802.11g;
channel:设定无线频道;
interface:接入点设备名称,注意不要包含ap后缀,即如果该设备称为wlan0ap,填写wlan0
即可;
bridge:指定所处网桥,对于一个同时接入公网、提供内部网和无线接入的路由器来说,设
定网桥很有必要;
driver:设定无线驱动,我这里是nl80211;
macaddr_acl:可选,指定MAC地址过滤规则,0表示除非在禁止列表否则允许,1表示除非
在允许列表否则禁止,2表示使用外部RADIUS服务器;
accept_mac_file:指定允许MAC列表文件所在;
deny_mac_file:指定禁止MAC列表文件所在;

由于ctrl_interface=/var/run/hostapd, 所以同样要保证/var/run/存在

启动

hostapd  -B  hostap.conf

既然我们作为AP热点,那自然要有dhcp功能,给链进来的客户端分配ip,我们可以使用udhcpd

hostapd_cli 可以用来修改AP的账号密码以及加密方式

./hostapd_cli  --help可以查看详细用法。

我在使用中想要用hostapd_cli  把热点从加密的改成无密码的,所以在编译hostapd的时候打开了

# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y

但是在使用的时候执行 wps_confg选项时,hostapd服务就死掉了。

所以我换了一种方式配置无密码时

1、先用 hostapd_cli disable  停掉hostapd

2、然后删除/var/run/hostapd/ (ctrl_interface的路径) ,避免退出不正常导致失败,简单粗暴的删掉。(如果不删除,在运行上层应用之后,修改AP为不加密会报以下错误)

3、然后修改hostapd.conf为不加密的再重新启动 

hostapd_cli disable
killall hostapd
rm -r /var/run/hostapd/

修改hostapd.conf为以下内容
interface=wlan1
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
ssid=AP_OPEN
hw_mode=g
channel=1
beacon_int=100
driver=nl80211
macaddr_acl=0
ignore_broadcast_ssid=0
own_ip_addr=127.0.0.1

hostapd  -B  hostap.conf

这个问题查源码应该是可以查出问题的,欢迎解决掉这个问题的朋友指导交流。

4.wifi_ctrl.sh

上述过程又要创建目录,又要改配置文件,重启服务之类的,太麻烦,所以我比较喜欢用一个.sh

把这些步骤整合起来,这样上层应用调用的时候只需调用一行代码即可(一行代码基本不会出现用法错误的问题),排查问题时就能很容易确定是上层业务逻辑的问题还是下面wifi模块的问题啦。

上代码

我这里实现了三个用法:

直接执行对应的操作,上层一行调用搞定

wifi_ctrl.sh ap_up                        #启动AP热点和ducpd,如果不指定账号密码,则使用脚本里面写死的
wifi_ctrl.sh ap_open ssid                 #启动AP热点以不加密的方式,可以初始化时使用,也可以在AP启动后用来改成不加密的
wifi_ctrl.sh conn_up ssid pssswd         #链接指定的wifi路由

#!/bin/sh

handler_help()
{
    echo "参数错误"
    echo "使用方式:"
    echo -e "1: $0 ap_up"
    echo -e "2: $0 ap_open ssid"
    echo -e "3: $0 conn_up ssid pssswd"
    exit 1
}

WIFI_TOOL_PASH=/mnt/mtd/wifitools

UDHCPD_LEASES_PASH=/mnt/run_data/udhcpd.leases #租约配置文件
UDHCP_CONF_PASH=/etc/udhcpd.conf #dhcpd配置文件

WIFI_AP_CONF_PASH=/etc/hostapd.conf #wifi ap 配置文件

WIFI_AP_ADDR=169.254.10.1 #热点IP
WIFI_AP_SSID="AP_WIFI" #热点名称
WIFI_AP_PASSPHRASE="88888888" #热点密码

WIFI_CONN_CONF_PASH=/etc/wpa_supplicant.conf #连接wifi的配置文件

#启动dhcpd服务
dhcpd_up()
{    
    local ARGV1=$1
    local WIFI_AP_HEAD=${ARGV1%.*}
    local IP_END=${ARGV1##*.}
    local DHCP_START_IP=$WIFI_AP_HEAD.50
    local DHCP_END_IP=$WIFI_AP_HEAD.200
    
    local UDHCPD_PID=`pidof udhcpd`
    
    if [ $IP_END -gt 100 ];then
        START_IP=$WIFI_AP_HEAD.10
        END_IP=$WIFI_AP_HEAD.99
    else
        START_IP=$WIFI_AP_HEAD.101
        END_IP=$WIFI_AP_HEAD.200
    fi
    
    if [ "$UDHCPD_PID" != "" ];then
        echo "dhcpd_down"
        kill -9 $UDHCPD_PID
    fi
    
    echo "dhcpd_up"
    
    rm $UDHCPD_LEASES_PASH
    rm $UDHCP_CONF_PASH
    
    touch $UDHCPD_LEASES_PASH    
    echo -e "start $DHCP_START_IP" >> $UDHCP_CONF_PASH
    echo -e "end $DHCP_END_IP" >> $UDHCP_CONF_PASH
    echo -e "interface wlan1" >> $UDHCP_CONF_PASH
    echo -e "remaining yes" >> $UDHCP_CONF_PASH
    echo -e "option subnet 255.255.255.0" >> $UDHCP_CONF_PASH
    echo -e "opt router $WIFI_AP_HEAD.1" >> $UDHCP_CONF_PASH
    echo -e "auto_time 0" >> $UDHCP_CONF_PASH
    echo -e "decline_time 3600" >> $UDHCP_CONF_PASH
    echo -e "conflict_time 3600" >> $UDHCP_CONF_PASH
    echo -e "min_lease 60" >> $UDHCP_CONF_PASH
    echo -e "offer_time 60" >> $UDHCP_CONF_PASH
    echo -e "lease_file $UDHCPD_LEASES_PASH" >> $UDHCP_CONF_PASH
    
    udhcpd $UDHCP_CONF_PASH
}


#启动WIFI热点
wifi_ap_up()
{
    local SSID=$1
    local PASSPHRASE=$2
    local AP_ADDR=$3
    
    local HOSTAPD_PID=`pidof hostapd`
    if [ "$HOSTAPD_PID" != "" ];then
        echo "wifi_ap_down"
        $WIFI_TOOL_PASH/hostapd_cli disable
        killall hostapd
        rm -rf /var/run/hostapd/
    fi
    
    echo "wifi_ap_up"
    
    rm $WIFI_AP_CONF_PASH
    touch $WIFI_AP_CONF_PASH
    
    #ifconfig wlan1 down
    #ifconfig wlan1 $WIFI_AP_ADDR.10 up

    echo -e "interface=wlan1" >> $WIFI_AP_CONF_PASH
    echo -e "ctrl_interface=/var/run/hostapd" >> $WIFI_AP_CONF_PASH
    echo -e "ctrl_interface_group=0" >> $WIFI_AP_CONF_PASH
    echo -e "ssid=$SSID" >> $WIFI_AP_CONF_PASH
    echo -e "hw_mode=g" >> $WIFI_AP_CONF_PASH
    echo -e "channel=1" >> $WIFI_AP_CONF_PASH
    echo -e "beacon_int=100" >> $WIFI_AP_CONF_PASH
    echo -e "driver=nl80211" >> $WIFI_AP_CONF_PASH
    echo -e "macaddr_acl=0" >> $WIFI_AP_CONF_PASH
    echo -e "#deny_mac_file=/etc/hostapd.deny" >> $WIFI_AP_CONF_PASH
    echo -e "auth_algs=1" >> $WIFI_AP_CONF_PASH
    echo -e "ignore_broadcast_ssid=0" >> $WIFI_AP_CONF_PASH
    echo -e "own_ip_addr=127.0.0.1" >> $WIFI_AP_CONF_PASH
    echo -e "wpa=2" >> $WIFI_AP_CONF_PASH
    echo -e "wpa_passphrase=$PASSPHRASE" >> $WIFI_AP_CONF_PASH
    echo -e "rsn_pairwise=TKIP CCMP" >> $WIFI_AP_CONF_PASH
    $WIFI_TOOL_PASH/hostapd -B $WIFI_AP_CONF_PASH

    dhcpd_up $AP_ADDR
}

#启动WIFI免密模式
wifi_ap_up_open()
{
    local SSID=$1
    local AP_ADDR=$2
    
    local HOSTAPD_PID=`pidof hostapd`
    if [ "$HOSTAPD_PID" != "" ];then
        echo "wifi_ap_down"
        $WIFI_TOOL_PASH/hostapd_cli disable
        killall hostapd
        rm -rf /var/run/hostapd/
    fi
    
    echo "wifi_ap_up"
    
    rm $WIFI_AP_CONF_PASH
    touch $WIFI_AP_CONF_PASH
    
    #ifconfig wlan1 down
    #ifconfig wlan1 $WIFI_AP_ADDR.10 up

    echo -e "interface=wlan1" >> $WIFI_AP_CONF_PASH
    echo -e "ctrl_interface=/var/run/hostapd" >> $WIFI_AP_CONF_PASH
    echo -e "ctrl_interface_group=0" >> $WIFI_AP_CONF_PASH
    echo -e "ssid=$SSID" >> $WIFI_AP_CONF_PASH
    echo -e "hw_mode=g" >> $WIFI_AP_CONF_PASH
    echo -e "channel=1" >> $WIFI_AP_CONF_PASH
    echo -e "beacon_int=100" >> $WIFI_AP_CONF_PASH
    echo -e "driver=nl80211" >> $WIFI_AP_CONF_PASH
    echo -e "macaddr_acl=0" >> $WIFI_AP_CONF_PASH
    echo -e "ignore_broadcast_ssid=0" >> $WIFI_AP_CONF_PASH
    echo -e "own_ip_addr=127.0.0.1" >> $WIFI_AP_CONF_PASH    
    
    $WIFI_TOOL_PASH/hostapd -B $WIFI_AP_CONF_PASH

    local DHCPD_PID=`pidof dhcpd_up`
    if [ "$HOSTAPD_PID" == "" ];then
        dhcpd_up $AP_ADDR
    fi
}

#连接wifi
wifi_conn_up()
{    
    local WPA_PID=`pidof wpa_supplicant`
    if [ "$WPA_PID" != "" ];then
        echo "wifi_conn_down"
        kill -9 $WPA_PID
    fi
    
    echo "wifi_conn_up"
    
    local SSID=$1
    local PSK=$2
    
    rm $WIFI_CONN_CONF_PASH
    touch $WIFI_CONN_CONF_PASH
    
    #ifconfig wlan0 down
    #ifconfig wlan0 up

    echo -e "ctrl_interface=/var/run/wpa_supplicant" >> $WIFI_CONN_CONF_PASH
    echo -e "update_config=1" >> $WIFI_CONN_CONF_PASH
    echo -e "network={" >> $WIFI_CONN_CONF_PASH
    echo -e "ssid=\"$SSID\"" >> $WIFI_CONN_CONF_PASH
    echo -e "scan_ssid=1" >> $WIFI_CONN_CONF_PASH
    echo -e "psk=\"$PSK\"" >> $WIFI_CONN_CONF_PASH
    echo -e "key_mgmt=WPA-PSK" >> $WIFI_CONN_CONF_PASH
    echo -e "}" >> $WIFI_CONN_CONF_PASH
    
    $WIFI_TOOL_PASH/wpa_supplicant -B -Dnl80211 -i wlan0 -c $WIFI_CONN_CONF_PASH
}

if [ $# -lt 1 ];then
    handler_help
fi

CTRL_INTERFACE=/var/run

if [ ! -d "$CTRL_INTERFACE" ]; then
    mkdir -p $CTRL_INTERFACE
fi


if [ $1 == "ap_up" ];then
    if [ $# == 4 ];then
        WIFI_AP_SSID=$2
        WIFI_AP_PASSPHRASE=$3
        WIFI_AP_ADDR=$4
    fi
    echo "ap_up $WIFI_AP_SSID $WIFI_AP_PASSPHRASE $WIFI_AP_ADDR ....."
    wifi_ap_up $WIFI_AP_SSID $WIFI_AP_PASSPHRASE $WIFI_AP_ADDR
elif [ $1 == "ap_open" ];then
    if [ $# == 2 ];then
        WIFI_AP_SSID=$2
    fi
    echo "ap_open $WIFI_AP_SSID $WIFI_AP_PASSPHRASE $WIFI_AP_ADDR ....."
    wifi_ap_up_open $WIFI_AP_SSID $WIFI_AP_ADDR
elif [ $1 == "conn_up" ];then
    echo "conn_up ....."
    if [ $# != 3 ];then
        handler_help
    fi
    wifi_conn_up $2 $3
else
    handler_help
fi

总结

其他常用的命令还有

iwlist:(使用 iwlist wlan0 scanning搜索的热点信息 要比使用wpa_cli搜索的更完整和准确,也相对不那么容易解析)

# iwlist wlan0 scanning 搜索当前无线网络
# iwlist wlan0 frequen  显示频道信息
# iwlist wlan0 rate  显示连接速度
# iwlist wlan0 power  显示电源模式
# iwlist wlan0 txpower 显示功耗
# iwlist wlan0 retry  显示重试连接次数(网络不稳定查看)
# iwlist wlan0 ap 显示热点信息
# iwlist --help 显示帮助信息
# iwlist --version 显示版本信息

iwlist wlan0 scanning搜索出来的内容长这样子:

解析代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

typedef long int int64;

const int MAX_LINE_STR_LEN = 256;

static int read_package_line(char line_buf[], int max_len, const unsigned char *p_package_buf)
{
	assert(NULL != p_package_buf);

	memset(line_buf, 0, max_len);

	int i = 0;
	int j = 0;

	for (int s = 0; s < max_len; s++)
	{
		i = s;

		if (j >= max_len)
		{
			line_buf[max_len - 1] = '\0';
			return 0;
		}

		if ('\n' == p_package_buf[i])
		{
			if (0 == i)
				continue;
			
			line_buf[j] = '\0';
			s++;
			break;
		}
		else if ('\r' == p_package_buf[i] || '\t' == p_package_buf[i])
		{
			continue;
		}
		else
		{
			line_buf[j++] = p_package_buf[i];
		}
	}

	return 0;
}

int main()
{
	char result_buf[1024 * 36] = {};
	int result_len = 0;
	FILE * fp = fopen("./ap_list", "r");
	if (fp)
	{
		result_len = fread(result_buf, 1, 1024 * 18, fp);
		puts(result_buf);
		fclose(fp);
	}
	
	int64 pos = 0;
	char line_buf[MAX_LINE_STR_LEN];
	memset(line_buf, 0, sizeof(line_buf));
	while (pos < result_len)
	{
		memset(line_buf, 0, sizeof(line_buf));
		read_package_line(line_buf, MAX_LINE_STR_LEN, result_buf + pos);
		pos += strlen(line_buf) + 1;
		
		puts(line_buf);
		
		if ((0 == s_flag) && (strstr(line_buf, "Address")))
		{
			s_flag = 1;
		}
		
		if ((0 == e_flag) && (strstr(line_buf, "Extra:fm")))
		{
			e_flag = 1;
		}
		
		char str[64] = {};
		if (strstr(line_buf, "Address"))
		{
			sscanf(line_buf, "%*[^:]:%s", str);
			printf("-------------------Address[%s]\n", str);
		}
		else if (strstr(line_buf, "ESSID"))
		{
			sscanf(line_buf, "%*[^\"]\"%[^\"]", str);
			printf("-------------------ESSID[%s]\n", str);
		}
		else if (strstr(line_buf, "Frequency"))
		{
			sscanf(line_buf, "%*[^l]l%[^)]", str);
			printf("-------------------Frequency[%s]\n", str);
		}
		else if (strstr(line_buf, "Authentication"))
		{
			sscanf(line_buf, "%*[^:]:%s", str);
			printf("-------------------Authentication[%s]\n", str);
		}
		else if (strstr(line_buf, "Quality"))
		{
			sscanf(line_buf, "%*[^=]=%[^/]", str);
			printf("-------------------Quality[%s]\n", str);
		}
			
		
	}
	
	
	return 0;
}

iwconfig :

auto 自动模式
essid 设置ESSID
nwid 设置网络ID
freq 设置无线网络通信频段
chanel 设置无线网络通信频段
sens 设置无线网络设备的感知阀值
mode 设置无线网络设备的通信设备
ap 强迫无线网卡向给定地址的接入点注册
nick<名字> 为网卡设定别名
rate<速率> 设定无线网卡的速率
rts<阀值> 在传输数据包之前增加一次握手,确信信道在正常的
power 无线网卡的功率设置

至此我们就可以使用无线进行设备通信了。

至于应用层的实现,就根据实际场景实现咯。

猜你喜欢

转载自blog.csdn.net/weixin_59665492/article/details/118811369