从这里开始,就正式进入到主题了,笔者分几节来介绍如何一点点实现基于wpa_supplicant库的WIFI连接功能。最终实现的就是类似于智能手机上的wifi连接界面功能。开发平台是linux3.2.0+qt4.5.2,硬件平台不再说明,假定读者已经做好了硬件的驱动适配和wpa_supplicant库移植,这部分笔者先不做记录,主要是wifi驱动笔者还没研究好,作为以后的研究点吧。下面笔者先对wpa_supplicant和wpa_cli进行简单介绍并解析其命令,因为最终程序就是依赖于这些命令实现的。
先给大家推荐一本书:深入理解Android:WiFi模块 NFC和GPS卷,这本书作者绝对是无线方面高手,如果想全面了解WIFI相关知识,建议阅读此书。市面上讲linux WIFI的书很少,这本不管是对理论还是代码分析,都比较细致。笔者后面讲解内容核心点都是围绕如何去实现最终功能,所以没办法面面俱到,如果某个点读者想深入了解,就从上面的书上去找。
wpa_supplicant是一个开源软件项目,它实现了Station对无线网络进行管理和控制的功能。wpa_supplicant有两个版本,分别是6和8。版本6中没有网卡作为Soft AP相关源码。目录结构如下:
·hostapd:当手机进入Soft AP模式时,手机将扮演AP的角色,故需要hostapd来提供AP的功能。
·wpa_supplicant:Station模式,也叫Managed模式。
·src:hostapd和wpa_supplicant中都包含了一些通用的数据结构和处理方法,这些内容都放在此src目录中。
以下凡是对wpa_supplicant都简称为WPAS
WPAS是C/S结构中的Server端,Linux/UNIX平台中,Client端利用Unix域socket与其通信。linux平台目前常用的Client端wpa_cli(无界面的命令行程序)和wpa_gui(UI用Qt实现)。
我们就是仿照wpa_cli来做我们自己的连接程序。下面就来看看wpa_cli是如何工作的。
ctrl_interface=/var/run/wpa_supplicant
启动成功后就可以执行wpa_cli客户端了。
wpa_cli支持两种模式:交互模式和命令行模式
交互模式就是直接执行wpa_cli,然后输入各种命令即可
root@am335x:~# wpa_cli
wpa_cli v0.6.9
Copyright (c) 2004-2009, Jouni Malinen and contributors
This program is free software. You can distribute it and/or modify it
under the terms of the GNU General Public License version 2.
Alternatively, this software may be distributed under the terms of the
BSD license. See README and COPYING for more details.
Selected interface 'wlan0'
Interactive mode
> status
bssid=74:1f:4a:b2:e5:b3
ssid=QK-2
id=2
pairwise_cipher=WEP-104
group_cipher=WEP-104
key_mgmt=NONE
wpa_state=COMPLETED
ip_address=192.168.100.13
>
每次输入完毕后只需要敲回车就能执行命令,然后又可以输入新的命令。
命令行模式就是我们普遍使用的模式,比如:
root@am335x:~# wpa_cli status
Selected interface 'wlan0'
bssid=74:1f:4a:b2:e5:b3
ssid=QK-2
id=2
pairwise_cipher=WEP-104
group_cipher=WEP-104
key_mgmt=NONE
wpa_state=COMPLETED
ip_address=192.168.100.13
root@am335x:~#
我们先来看下都有什么命令:执行help后可以看到一堆命令,笔者仅挑选我们需要的命令进行列举:
1.status [verbose] = get current WPA/EAPOL/EAP status
此命令是用来得到当前WPAS的状态,比如是扫描状态还是连接状态等等。
2.list_networks = list configured networks
列出所有保存的AP信息,这个要注意,执行此命令得到的配置信息并非配置文件中的AP列表,可以理解为当前内存中保存的配置列表。首先启动WPAS后,WPAS会从配置文件读取已经有的配置信息进行初始化,比如笔者现在配置文件如下:
root@am335x:~# vi /etc/wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
update_config=1
network={
ssid="coff_tes"
psk="1234567890"
disabled=1
}
network={
ssid="QK-1"
psk="1234567890"
disabled=1
}
那么此时用list得到信息如下:
> list
network id / ssid / bssid / flags
0 coff_tes any [DISABLED]
1 QK-1 any [DISABLED]
>
这是初始化状态,如果后面我们用了连接命令,这个时候再list会发现配置项增多,而配置文件在执行save_config之前是不会改变的。后边笔者会再列出来。
3.add_network = add a network
增加一个配置项,这个命令只会增加一个配置项ID,但是配置还并没有任何内容,相当于占位。
> list
network id / ssid / bssid / flags
0 coff_tes any [DISABLED]
1 QK-1 any [DISABLED]
> add_network
2
> list
network id / ssid / bssid / flags
0 coff_tes any [DISABLED]
1 QK-1 any [DISABLED]
2 any [DISABLED]
>
此时就多了一个2号配置项,但是还没有任何内容
4.set_network
这个命令非常重要,使用了设置配置的ssid、密码等信息,假如2号我们想设置成一个名为“test2”,加密方式为WPA方式的AP,密码为“1234567890”。那么可以这么写:
set_network 2 ssid "test2"
set_network 2 psk "1234567890"
此时再执行list发现有了ssid配置
> list
network id / ssid / bssid / flags
0 coff_tes any [DISABLED]
1 QK-1 any [DISABLED]
2 test2 any [DISABLED]
这里必须要简单讲下WIFI的加密了,想要详细了解的读者还是建议去读《深入理解Android:WiFi模块》。我们在设置路由时候通常会看到有个加密项,加密选项分为:NONE/WEP/WPA(WPA2)三种方式,现在普通路由一般只有两个了,WEP基本已经不适用了,读者可以用手机作为WIFI热点测试下。这里不去讲述三种加密方式的概念和原理,而是分别就每种加密方式列出其连接方式。
NONE方式
当所需要连接的AP加密方式为NONE时候,不需要密码设置,此时假如已经执行了add_network命令添加了新的配置项且index=2,需要连接的AP名称为”coffee”,首先增加配置项的ssid:
set_network 2 ssid “coffee”
然后指明此配置项属于NONE方式加密:
**set_network 2 key_mgmt
WPA(WPA2)方式
这是我们现在最常用的方式,也是最安全的加密方式。这个上面已经提到了,此方式需要设置ssid和密码。
set_network 2 ssid “coffee” //设置ssid
set_network 2 psk “1234567890” //设置密码
5.select_network
这个命令就相当于连接命令了,当用前面的“添加”和“配置”命令完成AP的配置后,就可以用这个命令来连接想要连接的AP了。比如上面增加了2号AP后,直接用下面命令就可以连接新的AP。
select_network 2
当然,只要配置项有的都可以连接,并不是只能连接新加的AP。看下此命令的帮助信息:
select_network = select a network (disable others)
注意括号内容,也就说执行此命令后,WPAS会开始尝试连接选定的AP,并且会把配置项中其它的AP disable,为什么这么做呢,笔者在编写连接程序时曾经尝试使用此命令后立马使能所有配置项中的AP,结果发现想要连接的AP根本连接不上,WPAS会自动连接到其它已经保存的AP上,即使你的密码等配置是正确的。这是因为AP在首次连接的时候,输入密码后会有个客户端和AP“握手”的流程,就是验证身份,但是此过程中WPAS仍然会去尝试连接其它的配置项,而已经保存的配置项会更快的连接到AP,就导致了新加入的AP无法成功连接。
6.scan和scan_results
这两个命令是配合使用的,scan是让硬件执行扫描操作,它会扫描附近所有的AP并把扫描结果存入内存。如果我们要查看扫描结果,需要用scan_results。
> scan
OK
> scan_results<2>CTRL-EVENT-SCAN-RESULTS
bssid / frequency / signal level / flags / ssid
74:1f:4a:b2:e5:b2 2412 100 [WPA-PSK-TKIP][WPA2-PSK-TKIP] QK-1
bc:ae:c5:a5:8c:14 2432 100 [WPA-PSK-TKIP][WPS] QK-WIFI
50:bd:5f:75:5e:42 2462 100 [WPA-PSK-CCMP][WPA2-PSK-CCMP] caiyiwang
e8:4e:06:21:d4:fe 2437 100 [WPA2-PSK-CCMP] cmcc-coffee
20:f4:1b:10:6c:b1 2412 95 [WPA2-PSK-CCMP] 8899
cc:af:78:08:da:3c 2462 84 [WPA2-PSK-CCMP] ALB-gl
8c:be:be:1d:6c:00 2412 74 [WPA2-PSK-CCMP] 1-Xiaomi
00:36:76:08:03:2d 2437 72 [WPA-PSK-CCMP][WPA2-PSK-CCMP]
64:d9:54:bb:3d:15 2412 60 [WPA-PSK-CCMP][WPA2-PSK-CCMP] Baidu1788
d8:49:2f:b9:1c:01 2422 60 [WPA2-PSK-CCMP] B91C01-MG2900series
a2:18:28:21:cc:0b 2437 69 [WPA2-PSK-CCMP] ___fan______ iPhone
c0:61:18:9c:6e:3a 2462 47 [WPA2-PSK-CCMP] TP-LINK_6E3A
d8:5d:4c:36:b0:6a 2452 46 [WPA-PSK-CCMP][WPA2-PSK-CCMP][WPS] heshangda1
c0:61:18:5d:75:4a 2462 46 [WPA-PSK-CCMP][WPA2-PSK-CCMP] aotai
00:36:76:59:59:97 2462 43 [WPA-PSK-CCMP][WPA2-PSK-CCMP] GUANGFU
0c:72:2c:4a:f7:6a 2462 43 [WPA-PSK-CCMP][WPA2-PSK-CCMP][WPS] SSDZ
74:1f:4a:b2:e5:b3 2412 100 [WEP] QK-2
>
扫描的AP信息包括:AP的MAC地址、信道、信号强度、加密方式、SSID
其它命令不再列出,可以查看帮助信息自行测试,下一节我们就要借助这些命令来实现我们的WIFI连接程序了,所以搞清楚这些命令的使用流程是非常有必要的。