本文将介绍如何使用 wpa_supplicant
服务程序和wpa_cli
客户端程序,让嵌入式设备的WIFI模块工作在station模式并连接网络,以及如何使用hostapd
和udhcpd
创建一个WIFI热点,并且解决如何让这两种工作模式共存。
WLAN一般有四种工作模式
Master(AP) 成为无线接入点提供无线接入服务
Managed(STA) 作为客户端连接其他无线接入点
Monitor 监听附近所有无线流量
Ad-hoc 多台计算机直接相连
网卡一般是工作在Managed(STA)
模式,使用 wpa_supplicant
服务程序和wpa_cli
客户端程序,要使用AP模式需要使用hostapd
这个服务程序
因为我手里用的是Realetk 的RTL8188EU模块,所以在该模块的基础上来做的测试
要编译出wpa_supplicant
、wpa_cli
和hostapd
这几个程序,首先要编译OpenSSL库和netlink库
从官网下载对应的源码
https://www.openssl.org/source/
http://www.infradead.org/~tgr/libnl/
./config no-asm -shared --prefix=$PWD/build --cross-compile-prefix=arm-linux-
make
make install
有的ubuntu系统是64位的编译的时候会报错 “-m64” 在Makefile文件中去掉这个参数,共有两处
./configure --host=arm-linux --prefix=$PWD/build CC=arm-linux-gcc
make
make install
cp defconfig .config
修改.config 添加libnl 和openssl 的头文件和库
添加CC 交叉编译链
#CFLAGS += -I$
#LIBS += -L$
CFLAGS += -I/home/linux/Tools/libnl-1.1.4/build/include
LIBS += -L/home/linux/Tools/libnl-1.1.4/build/lib
CFLAGS += -I/home/linux/Tools/openssl-1.0.2q/build/include
LIBS += -L/home/linux/Tools/openssl-1.0.2q/build/lib
CC=arm-linux-gcc
然后make编译,得到wpa_supplicant
和 wpa_cli
还有配置文件 wpa_supplicant.conf
在板子上加载该模块
insmod 8188eu.ko
cp defconfig .config
修改.config 添加libnl 和openssl 的头文件和库
添加CC 交叉编译链
#CFLAGS += -I$
#LIBS += -L$
CFLAGS += -I/home/linux/Tools/libnl-1.1.4/build/include
LIBS += -L/home/linux/Tools/libnl-1.1.4/build/lib
CFLAGS += -I/home/linux/Tools/openssl-1.0.2q/build/include
LIBS += -L/home/linux/Tools/openssl-1.0.2q/build/lib
CC=arm-linux-gcc
然后make编译,得到hostapd 和 hostapd_cli 还有配置文件 hostapd.conf
有的要去掉IPV6,因为有的嵌入式设备不支持IPV6也没有这个环境,执行程序时会报 ‘in6addr_any’ 的错
#CONFIG_IPV6=y
wpa_supplicant -B -Dwext -iwlan0 -c /etc/wpa_supplicant.conf
wpa_supplicant命令的参数如下:
drivers:
wext = Linux wireless extensions (generic)
options:
-b = optional bridge interface name
-B = run daemon in the background
-c = Configuration file
-C = ctrl_interface parameter (only used if -c is not)
-i = interface name
-d = increase debugging verbosity (-dd even more)
-D = driver name (can be multiple drivers: nl80211,wext)
-g = global ctrl_interface
-K = include keys (passwords, etc.) in debug output
-t = include timestamp in debug messages
-h = show this help text
-L = show license (GPL and BSD)
-o = override driver parameter for new interfaces
-O = override ctrl_interface parameter for new interfaces
-p = driver parameters
-P = PID file
-q = decrease debugging verbosity (-qq even less)
-v = show version
-W = wait for a control interface monitor before starting
-N = start describing new interface
example:
wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf
/etc/wpa_supplicant.conf这个文件就是我们保存的wifi账号和密码,其实在Android手机中如果要看你连接过的WiFi和密码,就是看这个文件
内容如下:
ctrl_interface=/var/run/wpa_supplicant
eapol_version=1
ap_scan=1
fast_reauth=1
blob-base64-exampleblob={
SGVsbG8gV29ybGQhCg==
}
network={
ssid="wifi_test"
scan_ssid=1
psk="1234567890"
priority=5
}
wpa_cli 这个程序相对复杂一点,参数比较多,命令更多,这里只列出常用的这几个
wpa_cli [-p] [-i] [-hvB] [-a] \
[-P] [-g] [-G] [command..]
-h = help (show this usage text)
-v = shown version information
-a = run in daemon mode executing the action file based on events from
wpa_supplicant
-B = run a daemon in the background
default path: /var/run/wpa_supplicant
default interface: first interface found in socket path
commands:
scan = request new BSS scan
scan_results = get latest scan results
add_network = add a network
select_network = select a network (disable others)
enable_network = enable a network
disable_network = disable a network
remove_network = remove a network
set_network = set network variables (shows
list of variables when run without arguments)
wpa_cli是可以进入交互模式,在这中可以通过命令来连接网络和具体配置,但是一般的,我们都是直接使用命令,放在脚本或程序中去执行的
#wpa_cli
>add_network (It will display a network id for you, assume it returns 0)
>set_network 0 ssid "wifi_test"
>set_network 0 key_mgmt NONE
>enable_network 0
>quit
scan是扫描网络
scan_results 是列出扫描的网络状态列表
wpa_cli -iwlan0 -p /var/run/wpa_supplicant scan
wpa_cli -iwlan0 -p /var/run/wpa_supplicant scan_reault
这两句一般是连着使用
然后就是使用add_network添加一个网络
wpa_cli -iwlan0 -p /var/run/wpa_supplicant add_network
这里会返回一个ID,后边的操作都是用这个ID去识别的这里假设是0
之后就是去操作新添加的这个网络,从而完成联网操作
set_network 是设置网络的相关信息,如ssid,加密方式及密码
如果要连接加密方式是[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS] (wpa加密)
wpa_cli -iwlan0 -p /var/run/wpa_supplicant set_network 0 ssid '"name"'
wpa_cli -iwlan0 -p /var/run/wpa_supplicant set_network 0 psk '"psk"'
如果要连接加密方式是[WEP][ESS] (wep加密),wifi名称是name,wifi密码是wep_key0
wpa_cli -iwlan0 -p /var/run/wpa_supplicant set_network 0 ssid '"name"'
wpa_cli -iwlan0 -p /var/run/wpa_supplicant set_network 0 key_mgmt NONE
wpa_cli -iwlan0 -p /var/run/wpa_supplicant set_network 0 wep_key0 '"psk"'
如果要连接加密方式是[ESS] (无加密),wifi名称是name
wpa_cli -iwlan0 -p /var/run/wpa_supplicant set_network 0 ssid '"name"'
wpa_cli -iwlan0 -p /var/run/wpa_supplicant set_network 0 key_mgmt NONE
wpa_cli -iwlan0 -p /var/run/wpa_supplicant select_network 0
wpa_cli -iwlan0 -p /var/run/wpa_supplicant enable_network 0
wpa_cli -iwlan0 -p /var/run/wpa_supplicant disable_network 0
wpa_cli -iwlan0 -p /var/run/wpa_supplicant remove_network 0
可以使用udhcpc自动获取IP也可以手动配置固定IP
udhcpc -i wlan0 -q
或
ifconfig wlan0 192.168.101.12
hostapd是一个用户态用于AP和认证服务器的守护进程,Linux下支持的驱动有:Host AP,madwifi,基于mac80211的驱动
usage: hostapd [-hdBKtv] [-P ]
options:
-h show this usage
-d show more debug messages (-dd for even more)
-B run daemon in the background
-P PID file
-K include key data in debug messages
-t include timestamps in some debug messages
-v show hostapd version
hostapd -d /etc/hostapd.conf -B
hostapd.conf配置文件如下,这个文件中的内容也比较多,但是很多都是默认的,详细的可以看源码中提供的hostapd.conf
##### hostapd configuration file ##############################################
interface=wlan0
ctrl_interface=/var/run/hostapd
ssid=LP_WIFI
channel=6
wpa=2
wpa_passphrase=963852741
#bridge=br0
##### default configuration #######################################
driver=rtl871xdrv
beacon_int=100
hw_mode=g
ieee80211n=1
wme_enabled=1
ht_capab=[SHORT-GI-20][SHORT-GI-40][HT40+]
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
max_num_sta=8
wpa_group_rekey=8640
开启hostapd让模块工作在AP模式,开启后其他设备能够搜索到该热点,但是无法获取到IP地址,仍然无法连接
此时就需要启动udhcpd服务(这是嵌入式设备上的,PC上应该是dhcp),用于分配IP地址
该程序在busybox编译的时候可以配置生成的,如果没有则需要编译源码来移植该程序
下载 udhcp-0.9.8.tar.gz
修改Makefile
CROSS_COMPILE=arm-linux
make
即可编译得到udhcpc 和udhcpd
复制源码下的 samples/udhcpd.conf 到ARM板/etc/udhcpd.conf下
基本配置如下,具体上网的IP、DNS这些都在这里修改
# The start and end of the IP lease block
start 192.168.0.20#default: 192.168.0.20
end 192.168.0.254 #default: 192.168.0.254
# The interface that udhcpd will use
interface wlan0 #default: eth0
#Examles
opt router 192.168.0.1
opt dns 192.168.10.2 192.168.10.10
option subnet 255.255.255.0
#optwins192.168.10.10
option dns 129.219.13.81 # appened to above DNS servers for a total of 3
option domain local
option lease 864000 # 10 days of seconds
配置完之后,在板子上执行udhcpd就可以了
udhcpd &
我写的启动AP服务的脚本:
insmod /opt/vendor/8188eu.ko
sleep 2
ifconfig wlan0 up
ifconfig wlan0 192.168.0.1
hostapd -d /etc/hostapd.conf -B
touch /var/lib/misc/udhcpd.leases
udhcpd &
这里的192.168.0.1 这个IP是等于当前wlan0的IP
在嵌入式设备中使用时往往是需要WiFi模块既能上网也能做一个热点,可能用于web配置,或者控制一些子模块,就像物联网的一些WiFi芯片ESP32、ESP8266
而且在安卓手机中很多的设备也是同时支持者两种模式的(后期很多厂家给阉割了)
所以WiFi模块同事支持这两种工作模式还是很有必要的
其实也很简单,只需要修改驱动配置文件,重新编译ko文件即可
修改驱动配置文件
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
重新加载8188eu.ko模块后,内核中就会多一个设备节点wlan1(安卓可能是p2p0),如果没有请使用ifconfig
ifconfig wlan0 up
ifconfig wlan1 up
如果还没有,说明你的驱动文件编译的有问题,还是没有支持共存
在之前AP和STA模式工作的时候都是使用接口wlan0,所以两个模式是不可能共存,要能共存,必须要让内核虚拟出更多的设备节点,其实底层的物理硬件是同一个,这里就是驱动做的事了
当有了wlan1后,我们就让station模式在wlan0上干活,让AP模式在wlan1上工作
所以这里就要修改AP模式的两个配置文件
修改之前使用的两个配置文件,将wlan0修改成wlan1即可
/etc/hostapd.conf
interface=wlan1
/etc/udhcpd.conf
interface wlan1 #default: eth0
然后脚本也得改改
insmod /opt/vendor/8188eu.ko
sleep 2
ifconfig wlan0 up
ifconfig wlan1 up
ifconfig wlan1 192.168.0.1
hostapd -d /etc/hostapd.conf -B
touch /var/lib/misc/udhcpd.leases
udhcpd &