(1)通过adb命令行,可以直接打开supplicant,从而运行wpa_cli,可以解决客户没有显示屏而无法操作WIFI的问题,还可以避免UI的问题带到driver。进一步来说,可以用在很多没有键盘输入和LCD输出的安卓终端产品的操作上。
wpa_supplicant包含两个主要的可执行工具:wpa_supplicant和wpa_cli。wpa_supplicant是核心程序, 它和wpa_cli的关系就是服务和客户端的关系:后台运行wpa_supplicant,使用wpa_cli来搜索、设置、和连接网络。
(2)在wpa_cli交互模式下可以执行很多命令,列表如下:
Full command | Short command | Description |
status | stat | displays the current connection status |
disconnect | disc | prevents wpa_supplicant from connecting to any access point |
quit | q | exits wpa_cli |
terminate | term | kills wpa_supplicant |
reconfigure | recon | reloads wpa_supplicant with the configuration file supplied (-c parameter) |
scan | scan | scans for available access points (only scans it, doesn't display anything) |
scan_result | scan_r | displays the results of the last scan |
list_networks | list_n | displays a list of configured networks and their status (active or not, enabled or disabled) |
select_network | select_n | select a network among those defined to initiate a connection (ie select_network 0) |
enable_network | enable_n | makes a configured network available for selection (ie enable_network 0) |
disable_network | disable_n | makes a configured network unavailable for selection (ie disable_network 0) |
remove_network | remove_n | removes a network and its configuration from the list (ie remove_network 0) |
add_network | add_n | adds a new network to the list. Its id will be created automatically |
set_network | set_n | shows a very short list of available options to configure a network when supplied with no parameters. See next section for a list of extremely useful parameters to be used with set_network and get_network. |
get_network | get_n | displays the required parameter for the specified network. See next section for a list of parameters |
save_config | save_c | saves the configuration |
A,首先保证ADB连入,且能运行adb remount,这样避免系统文件只读。然后设置wpa_cli和wpa_supplicant有较强权限。
B,运行echo 1 > /dev/wmtWifi,启动WIFI驱动。但是这个使能不会表现在安卓界面上层,默认是要在启动安卓时开启WIFI模块的,也即设置中的WIFI要默认ON。
C,进入/system/bin目录,首先运行服务端wpa_supplicant。
./wpa_supplicant -iwlan0 -Dnl80211 -c/system/etc/wifi/wpa_supplicant.conf
正常启动后的回显如下:
不可收入态表明该服务端已经在运行了(也可能是可输入状态,只要后面的wpa_cali可连接就行)。-i -D -c的参数意义可直接在Help中查询,具体有些参数可能因平台不同而有差异。
D,另开启一个ADB SHELL,作客户端运行wpa_cali。如下:
cd /system/bin
wpa_cli -p /data/misc/wpa_supplicant
回显如下说明正常并处于交互模式:
E,执行一系列命令看看
scan
scan_results
F,连WIFI的命令行,有以下几种:
for AP that doesn`t have encryption
>add_network (It will display a network id for you, assume it returns 0)
>set_network 0 ssid “666”
>set_network 0 key_mgmt NONE
>enable_network 0
>quit
for AP that has WEP
>add_network (assume returns 1)
>set_network 1 ssid “666”
>set_network 1 key_mgmt NONE
>set_network 1 wep_key0 “your ap passwork”(if usting ASCII, it need
double quotation marks, if using hex, then don`t need the double quotation
marks)
>set_network 1 wep_tx_keyidx 0
>select_network 1 (optional, remember, if you are connecting with another
AP, you should select it to disable the another)
>enable_network 1
for AP that has WPA-PSK/WPA2-PSK
>add_network (assume returns 2)
>set_network 2 ssid “666”
>set_network 2 psk “your pre-shared key”
>select_network 2 (optional, remember, if you are connecting with another
AP, you should select it to disable the another)
>enable_network 2
我自己的实验图如下:
以上过程就说明联网OK,可以上网了。
参考原文:http://cache.baiducontent.com /c?m=9f65cb4a8c8507ed4fece7631046893b4c4380146d96864968d4e414c42246100024b8ed7a66471980853a3c50f11e41bca770216c5d61aa9bc98b4addb9922b3bcd7a742613d51742c419de8a1c729f7e875a98ea42b3e1&p=8b2a975bcd8711a052eedb2f4a4c&newp=8b2a971f81822dec08e29e7d495d92695c02dc3051dcd14f2895ff0b&user=baidu&fm=sc&query=adb+shell+wifi&qid=&p1=4
参考原文:http://blog.sina.com.cn/s/blog_55465b470100l73l.html
Android系统中对于WIFI的设置集成到了“设置”中,其实跟手动设置差不多。这里介绍下如何手动连接WIFI,以方便以后调试WIFI。
第一步要做的就是要加载WIFI模块驱动了。当然如果你的WIFI是编译到内核里面的,就不需要的。我们的WIFI芯片用的是BCM4330,编译为模块。
insmod /system/lib/modules/kernel/drivers/net/wireless/bcm4330/bcm4330.ko firmware_path=/system/vendor/firmware/bcm4330.bin \ nvram_path=/system/vendor/firmware/nvram.txt
这样驱动模块加载后,需要启动wpa_supplicant
root@android:/ # wpa_supplicant -Dwext -iwlan0 -C/data/system/wpa_supplicant -c/data/misc/wifi/wpa_supplicant.conf &
然后ps|grep wpa看看有没有起来,在wifi工作过程中,这个进程要始终都在的。
接着启动客户端wpa_cli进行配置并连接wifi热点
130|root@android:/ # wpa_cli -p/data/system/wpa_supplicant -iwlan0
wpa_cli v0.8.x
Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> 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.
Interactive mode
>
其中/data/system/wpa_supplicant 是刚刚启动wpa_supplicant的时候创建的一个套接字
接着进行搜索wifi
> scan
OK
<3>CTRL-EVENT-SCAN-RESULTS
查看搜到的有哪些热点
> scan_result
bssid / frequency / signal level / flags / ssid
40:16:9f:67:0f:00 2462 -42 [WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS] HHCN-NET
b0:48:7a:49:44:68 2437 -58 [WPA2-PSK-CCMP][WPS][ESS] HHTech.Arch
e0:05:c5:97:d8:5a 2412 -71 [WPA-PSK-CCMP][WPA2-PSK-CCMP-preauth][ESS] 1103-5
40:16:9f:67:0c:a6 2412 -74 [WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS] hardware
b0:48:7a:49:65:54 2437 -58 [WPA-PSK-CCMP][WPA2-PSK-CCMP][WPS][ESS] Dept_driver
接着设置wifi,就连接Dept_driver这个热点吧
> add_net
3
> set_net 3 ssid "Dept_driver"
OK
Dept_driver的加密方式是WPA2-PSK
> set_net 3 psk "password"
OK
> select_net 3
OK
<3>CTRL-EVENT-STATE-CHANGE id=0 state=0 BSSID=00:00:00:00:0[ 2752.332061] dhd_aoe_hostip_clr failed code -23
0:00
<3>CTR[ 2752.337768] dhd_aoe_arp_clr failed code 1
L-EVENT-STATE-CHANGE id=-1 state=3 BSSID=00:00:00:00:00:00
<3>CTRL-EVENT-DISCONNECTED bssid=00:00:00:00:00:00 reason=0
<3>CTRL-EVENT-STATE-CHANGE id=-1 state=0 BSSID=00:00:00:00:00:00
<3>CTRL-EVENT-STATE-CHANGE id=-1 state=3 BSSID=00:00:00:00:00:00
<3>CTRL-EVENT-SCAN-RESULTS
<3>WPS-AP-AVAILABLE
<3>Trying to associate with b0:48:7a:49:65:54 (SSID='Dept_driver' freq=2437 MHz)
<3>CTRL-EVENT-STATE-CHANGE id=-1 state=5 BSSID=b0:48:7a:49:65:54
[ 2753.153717] wl_iw_set_essid: join SSID=Dept_driver ch=6
<3>CTRL-EVENT-STATE-CHANGE id=3 state=6 BSSID=b0:48:7a:49:65:54
<3>Associated with b0:48:7a:49:65:54
<3>CTRL-EVENT-STATE-CHANGE id=3 state=7 BSSID=00:00:00:00:00:00
<3>CTRL-EVENT-STATE-CHANGE id=3 state=8 BSSID=00:00:00:00:00:00
<3>WPA: Key negotiation completed with b0:48:7a:49:65:54 [PTK=CCMP GTK=CCMP]
<3>CTRL-EVENT-CONNECTED - Connection to b0:48:7a:49:65:54 completed (reauth) [id=3 id_str=]
<3>CTRL-EVENT-STATE-CHANGE id=3 state=9 BSSID=00:00:00:00:00:00
> enable_net 3
OK
> q
这样,就都设置好了,接着用dhcpd分配一个IP地址
root@android:/ # dhcpcd wlan0
dhcpcd[3940]: version 5.2.10 starting
dhcpcd[3940]: host does not support a monotonic clock - timing can skew
dhcpcd[3940]: wlan0: rebinding lease of 192.168.1.216
dhcpcd[3940]: wlan0: acknowledged 192.168.1.216 from 192.168.1.1 `�'
dhcpcd[3940]: wlan0: leased 192.168.1.216 for 7200 seconds
dhcpcd[3940]: forked to background, child pid 3971
root@android:/ # busybox ifconfig wlan0
wlan0 Link encap:Ethernet HWaddr AC:E8:7B:89:D3:C0
inet addr:192.168.1.216 Bcast:255.255.255.255 Mask:255.255.255.0
inet6 addr: fe80::aee8:7bff:fe89:d3c0/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6637 errors:0 dropped:25 overruns:0 frame:0
TX packets:4357 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3825961 (3.6 MiB) TX bytes:704832 (688.3 KiB)
这样就完成了。可以上网了。
wpa_supplicant软件架构分析
原文地址:http://blog.csdn.net/fxfzz/article/details/6176414
1. 启动命令
wpa supplicant 在启动时,启动命令可以带有很多参数,目前我们的启动命令如下:
wpa_supplicant /system/bin/wpa_supplicant -Dwext -ieth0 -c/data/wifi/wpa_supplicant.conf -f/data/wifi/wpa_log.txt
wpa_supplicant对于启动命令带的参数,用了两个数据结构来保存,
一个是 wpa_params, 另一个是wpa_interface.
这主要是考虑到wpa_supplicant是可以同时支持多个网络接口的。
wpa_params数据结构主要记录与网络接口无关的一些参数设置。
而每一个网络接口就用一个wpa_interface数据结构来记录。
在启动命令行中,可以用-N来指定将要描述一个新的网络接口,对于一个新的网络接口,可以用下面六个参数描述:
-i<ifname> : 网络接口名称
-c<conf>: 配置文件名称
-C<ctrl_intf>: 控制接口名称
-D<driver>: 驱动类型
-p<driver_param>: 驱动参数
-b<br_ifname>: 桥接口名称
2. wpa_supplicant 初始化流程
2.1. main()函数:
在这个函数中,主要做了四件事。
a. 解析命令行传进的参数。
b. 调用wpa_supplicant_init()函数,做wpa_supplicant的初始化工作。
c. 调用wpa_supplicant_add_iface()函数,增加网络接口。
d. 调用wpa_supplicant_run()函数,让wpa_supplicant真正的run起来。
2.2. wpa_supplicant_init()函数:
a. 打开debug 文件。
b. 注册EAP peer方法。
c. 申请wpa_global内存,该数据结构作为统领其他数据结构的一个核心, 主要包括四个部分:
wpa_supplicant *ifaces /*每个网络接口都有一个对应的wpa_supplicant数据结构,该指针指向最近加入的一个,在wpa_supplicant数据结构中有指针指向next*/
wpa_params params /*启动命令行中带的通用的参数*/
ctrl_iface_global_priv *ctrl_iface /*global 的控制接口*/
ctrl_iface_dbus_priv *dbus_ctrl_iface /*dbus 的控制接口*/
d. 设置wpa_global中的wpa_params中的参数。
e. 调用eloop_init函数将全局变量eloop中的user_data指针指向wpa_global。
f. 调用wpa_supplicant_global_ctrl_iface_init函数初始化global 控制接口。
g. 调用wpa_supplicant_dbus_ctrl_iface_init函数初始化dbus 控制接口。
h. 将该daemon的pid写入pid_file中。
2.3. wpa_supplicant_add_iface()函数:
该函数根据启动命令行中带有的参数增加网络接口, 有几个就增加几个。
a. 因为wpa_supplicant是与网络接口对应的重要的数据结构,所以,首先分配一个wpa_supplicant数据结构的内存。
b. 调用wpa_supplicant_init_iface() 函数来做网络接口的初始工作,主要包括:
设置驱动类型,默认是wext;
读取配置文件,并将其中的信息设置到wpa_supplicant数据结构中的conf 指针指向的数据结构,它是一个wpa_config类型;
命令行设置的控制接口ctrl_interface和驱动参数driver_param覆盖配置文件里设置,命令行中的优先;
拷贝网络接口名称和桥接口名称到wpa_config数据结构;
对于网络配置块有两个链表描述它,一个是 config->ssid,它按照配置 文件中的顺序依次挂载在这个链表上,还有一个是pssid,它是一个二级指针,指向一个指针数组,该指针数组按照优先级从高到底的顺序依次保存 wpa_ssid指针,相同优先级的在同一链表中挂载。
c. 调用wpa_supplicant_init_iface2() 函数,主要包括:
调用wpa_supplicant_init_eapol()函数来初始化eapol;
调用相应类型的driver的init()函数;
设置driver的param参数;
调用wpa_drv_get_ifname()函数获得网络接口的名称,对于wext类型的driver,没有这个接口函数;
调用wpa_supplicant_init_wpa()函数来初始化wpa,并做相应的初始化工作;
调用wpa_supplicant_driver_init()函数,来初始化driver接口参数;在该函数的最后,会
wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
来主动发起scan,
调用wpa_supplicant_ctrl_iface_init()函数,来初始化控制接口;对于UNIX SOCKET这种方式,其本地socket文件是由配置文件里的ctrl_interface参数指定的路径加上网络接口名称;
2.4. wpa_supplicant_run()函数:
初始化完成之后,让wpa_supplicant的main event loop run起来。
在wpa_supplicant中,有许多与外界通信的socket,它们都是需要注册 到eloop event模块中的,具体地说,就是在eloop_sock_table中增加一项记录,其中包括了sock_fd, handle, eloop_data, user_data。
eloop event模块就是将这些socket组织起来,统一管理,然后在eloop_run中利用select机制来管理socket的通信。
3. Wpa_supplicant提供的接口
从通信层次上划分,wpa_supplicant提供向上的控制接口 control interface,用于与其他模块(如UI)进行通信,其他模块可以通过control interface 来获取信息或下发命令。Wpa_supplicant通过socket通信机制实现下行接口,与内核进行通信,获取信息或下发命令。
3.1 上行接口
Wpa_supplicant提供两种方式的上行接口。一种基于传统dbus机制实现与其他进程间的IPC通信;另一种通过Unix domain socket机制实现进程间的IPC通信。
3.1.1 Dbus接口
该接口主要在文件“ctrl_iface_dbus.h”,“ctrl_iface_dbus.c”,“ctrl_iface_dbus_handler.h”和“ctrl_iface_dbus_handler.c”中实现,提供一些基本的控制方法。
DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res);
DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_smartcard_modules(
DBusMessage *message, struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
struct wpa_supplicant *wpa_s);
3.1.2 Unix domain socket 接口
该接口主要在文件“wpa_ctrl.h”,“wpa_ctrl.c”,“ctrl_iface_unix.c”,“ctrl_iface.h”和“ctrl_iface.c”实现。
(1)“wpa_ctrl.h”,“wpa_ctrl.c” 完成对control interface的封装,对外提供统一的接口。其主要的工作是通过Unix domain socket建立一个control interface 的client结点,与作为server的wpa_supplicant结点通信。
主要功能函数:
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
/* 建立并初始化一个Unix domain socket的client结点,并与作为server的wpa_supplicant结点绑定 */
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
/* 撤销并销毁已建立的Unix domain socket的client结点 */
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len));
/* 用户模块直接调用该函数对wpa_supplicant发送命令并获取所需信息
* 可以发送的命令如附件1所示 */
Note:
Wpa_supplicant 提供两种由外部模块获取信息的方式:一种是外部模块通过发送request 命令然后获取response的问答模式,另一种是wpa_supplicant主动向外部发送event事件,由外部模块监听接收。
一般的常用做法是外部模块通过调用wpa_ctrl_open()两次,建立两个control interface接口,一个为ctrl
interface,用于发送命令,获取信息,另一个为monitor interface,用于监听接收来自于wpa_supplicant的event时间。此举可以降低通信的耦合性,避免response和event的相互干扰。
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
/* 注册 某个 control interface 作为 monitor interface */
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
/* 撤销某个 monitor interface 为 普通的 control interface */
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
/* 判断是否有挂起的event 事件 */
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
/* 获取挂起的event 事件 */
(2)“ctrl_iface_unix.c”实现wpa_supplicant的Unix domain socket通信机制中server结点,完成对client结点的响应。
其中最主要的两个函数为:
static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
/* 接收并解析client发送request命令,然后根据不同的命令调用底层不同的处理函数;
* 然后将获得response结果回馈到 client 结点。
*/
static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
int level, const char *buf,
size_t len)
/* 向注册的monitor interfaces 主动发送event事件 */
(3)“ctrl_iface.h”和“ctrl_iface.c”主要实现了各种request命令的底层处理函数。
3.2 下行接口
Wpa_supplicant提供的下行接口主要用于和kernel(driver)进行通信,下发命令和获取信息。
Wpa_supplicant下行接口主要包括三种重要的接口:
1. PF_INET socket接口,主要用于向kernel 发送ioctl命令,控制并获取相应信息。
2. PF_NETLINK socket接口,主要用于接收kernel发送上来的event 事件。
3. PF_PACKET socket接口,主要用于向driver传递802.1X报文。
主要涉及到的文件包 括:“driver.h”,“drivers.c”,“driver_wext.h”,“driver_wext.c”,“l2_packet.h”和 “l2_packet_linux.c”。其中“driver.h”,“drivers.c”,“driver_wext.h”和 “driver_wext.c”实现PF_INET socket接口和PF_NETLINK socket接口;“l2_packet.h”和“l2_packet_linux.c”实现PF_PACKET socket接口。
(1)“driver.h”,“drivers.c” 主要用于封装底层差异对外显示一个相同的wpa_driver_ops接口。Wpa_supplicant可支持atmel, Broadcom, ipw, madwifi, ndis, nl80211, wext等多种驱动。
其中一个最主要的数据结构为wpa_driver_ops, 其定义了driver相关的各种操作接口。
(2)“driver_wext.h”,“driver_wext.c”实现了wext形式的wpa_driver_ops,并创建了PF_INET socket接口和PF_NETLINK socket接口,然后通过这两个接口完成与kernel的信息交互。
Wext提供的一个主要数据结构为:
struct wpa_driver_wext_data {
void *ctx;
int event_sock;
int ioctl_sock;
int mlme_sock;
char ifname[IFNAMSIZ + 1];
int ifindex;
int ifindex2;
int if_removed;
u8 *assoc_req_ies;
size_t assoc_req_ies_len;
u8 *assoc_resp_ies;
size_t assoc_resp_ies_len;
struct wpa_driver_capa capa;
int has_capability;
int we_version_compiled;
/* for set_auth_alg fallback */
int use_crypt;
int auth_alg_fallback;
int operstate;
char mlmedev[IFNAMSIZ + 1];
int scan_complete_events;
};
其中event_sock 为PF_NETLINK socket接口,ioctl_sock为PF_INET socket借口。
Driver_wext.c实现了大量底层处理函数用于实现wpa_driver_ops操作参数,其中比较重要的有:
void * wpa_driver_wext_init(void *ctx, const char *ifname);
/* 初始化wpa_driver_wext_data 数据结构,并创建PF_NETLINK socket和 PF_INET socket 接口 */
void wpa_driver_wext_deinit(void *priv);
/* 销毁wpa_driver_wext_data 数据结构,PF_NETLINK socket和 PF_INET socket 接口 */
static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
void *sock_ctx);
/* 处理kernel主动发送的event事件的 callback 函数 */
最后,将实现的操作函数映射到一个全局的wpa_driver_ops类型数据结构 wpa_driver_wext_ops中。
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
.set_wpa = wpa_driver_wext_set_wpa,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
.set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
.scan = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.disassociate = wpa_driver_wext_disassociate,
.set_mode = wpa_driver_wext_set_mode,
.associate = wpa_driver_wext_associate,
.set_auth_alg = wpa_driver_wext_set_auth_alg,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.add_pmkid = wpa_driver_wext_add_pmkid,
.remove_pmkid = wpa_driver_wext_remove_pmkid,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
};
(3)“l2_packet.h”和“l2_packet_linux.c”主要用于实现PF_PACKET socket接口,通过该接口,wpa_supplicant可以直接将802.1X packet发送到L2层,而不经过TCP/IP协议栈。
其中主要的功能函数为:
struct l2_packet_data * l2_packet_init(
const char *ifname, const u8 *own_addr, unsigned short protocol,
void (*rx_callback)(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len),
void *rx_callback_ctx, int l2_hdr);
/* 创建并初始化PF_PACKET socket接口,其中rx_callback 为从L2接收到的packet 处理callback函数 */
void l2_packet_deinit(struct l2_packet_data *l2);
/* 销毁 PF_PACKET socket接口 */
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
const u8 *buf, size_t len);
/* L2层packet发送函数,wpa_supplicant用此发送L2层 802.1X packet */
static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx);
/* L2层packet接收函数,接收来自L2层数据后,将其发送到上层 */
4. Control interface commands
PING
MIB
STATUS
STATUS-VERBOSE
PMKSA
SET <variable> <valus>
LOGON
LOGOFF
REASSOCIATE
RECONNECT
PREAUTH <BSSID>
ATTACH
DETACH
LEVEL <debug level>
RECONFIGURE
TERMINATE
BSSID <network id> <BSSID>
LIST_NETWORKS
DISCONNECT
SCAN
SCAN_RESULTS
BSS
SELECT_NETWORK <network id>
ENABLE_NETWORK <network id>
DISABLE_NETWORK <network id>
ADD_NETWORK
REMOVE_NETWORK <network id>
SET_NETWORK <network id> <variable> <value>
GET_NETWORK <network id> <variable>
SAVE_CONFIG
本文译至:https://wiki.archlinux.org/index.php/WPA_Supplicant_%28%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%29
wpa_supplicant 是跨平台的 WPAsupplicant,支持 WEP, WPA 和 WPA2 (IEEE 802.11i / RSN (Robust Secure Network)). 可以在桌面、笔记本甚至嵌入式系统中使用。
wpa_supplicant 是在客户端使用的 IEEE 802.1X/WPA 组件, 支持与 WPA Authenticator 的交互,控制漫游和无线驱动的 IEEE 802.11 验证和关联。
安装
从 官方软件仓库 中安装软件包 wpa_supplicant。
此外软件包 wpa_supplicant_gui 提供了图形界面wpa_gui。
启动
本节介绍启动wpa_supplicant的常用方法,选择一个最适合你的。
systemd
wpa_supplicant提供多种服务的文件:
wpa_supplicant.service
- 使用 D-Bus, 推荐 NetworkManager 的用户.wpa_supplicant@.service
- 接受接口名作为参数,并为该接口启动wpa_supplicant守护进程。它读取/etc/wpa_supplicant/wpa_supplicant-interface.conf的配置文件wpa_supplicant-nl80211@.service
- 也是接口特定的,但明确强制nl80211驱动程序 (见下文). 配置文件路径是/etc/wpa_supplicant/wpa_supplicant-nl80211-interface.conf
wpa_supplicant-wired@.service
- 也是接口特定的, 使用wired
驱动. 配置文件路径是/etc/wpa_supplicant/wpa_supplicant-wired-interface.conf
dhcpcd
dhcpcd包含了一个钩子(默认为启用)来自动启动对应无线接口的wpa_supplicant。它只在如下情况下启动:
- 没有wpa_supplicant进程在该接口在监听。
- 存在一个wpa_supplicant的配置文件。dhcpcd 默认检查 /etc/wpa_supplicant.conf 和 /etc/wpa_supplicant/wpa_supplicant.conf,但可以通过在/etc/dhcpcd.conf设置env wpa_supplicant_conf=configuration_file_path来添加自定义路径。
手动
wpa_supplicant接受多个命令行参数,特别是:
-B
- 在后台执行-c 文件名
-路径配置文件-i 接口
- 监听的接口
关于完整的参数列表,参考 man 8 wpa_supplicant。例如,常见的用法是:
# wpa_supplicant -B -i interface -c configuration_file
配置
wpa_supplicant提供了一个参考配置文件/etc/wpa_supplicant/wpa_supplicant.conf,其中包含 了所有可用的选项及其用法和例子的详细文档。考虑先把它备份起来,因为下面描述的自动添加网络配置到wpa_supplicant.conf的方法下删除 了文件中的所有注释。
在其最简单的形式中,一个配置文件,只需要一个网络配置块。例如:
/etc/wpa_supplicant/foobar.conf
network={ ssid="..." }
一旦你有一个配置文件,如前节所述,就可以启动wpa_supplicant守护进程,并使用一个静态IP或DHCP连接到无线网络。
wpa_passphrase
网络配置可以使用wpa_passphrase工具自动生成并添加到配置文件中。这在连接到需要密码的安全网络时是有用的。例如:
$ wpa_passphrase essid passphrase
network={ ssid="essid" #psk="passphrase" psk=f5d1c49e15e679bebe385c37648d4141bc5c9297796a8a185d7bc5ac62f954e3 }
一些异常复杂的口令可能需要从文件输入:
$ wpa_passphrase essid < passphrase.txt
# wpa_supplicant -B -i interface -c <(wpa_passphrase essid passphrase)
指定驱动
您可能需要指定一个驱动来使用。关于支持的驱动程序的列表,请参考wpa_supplicant -h的输出结果。
nl80211
是当前的标准,但不是所有的无线芯片的模块支持。wext
目前已过时,但仍得到广泛支持。
使用 -D
开关来指定驱动:
# wpa_supplicant -B -i interface -c configuration_file -D driver
使用 wpa_cli
wpa_supplicant可以通过使用wpa_cli命令,在运行时手动进行控制。要启用wpa_cli,wpa_supplicant守护进 程必须被配置为通过在wpa_supplicant的配置文件(默认位置:/etc/wpa_supplicant /wpa_supplicant.conf)设置ctrl_interface变量来创建一个“控制接口”(套接字)。
用户也将需要通过指定可以访问它的组来获准访问该套接字。一个新的组可能为此被创建,并且用户添加到它,或已存在的组可以使用 - 通常是 wheel。
下面的设置将在/run/wpa_supplicant/中创建套接字并允许wheel组的成员进行访问:
ctrl_interface=DIR=/run/wpa_supplicant GROUP=wheel
可以通过wpa_cli修改的wpa_supplicant配置文件自身。这在手动添加新的网络到配置文件,而无需重新启动wpa_supplicant守护进程时是有用的。为了实现这一目标,在配置文件中设置update_config变量设置为1:
update_config=1
在wpa_cli开始之前,wpa_supplicant守护进程必须处于运行状态。(见#Starting了解详情)。然后启动
$ wpa_cli
它会寻找配置文件中给定位置的控制套接字,位置也可以使用p选项手动设置)。您可以使用-i选项配置的接口,不然的话将使用wpa_supplicant所管理的第一个被找到的无线接口。
当wpa_cli被调用时,将出现交互式提示符(>)。提示包括tab 补全和已完成命令的说明。
使用wpa_cli添加一个新的网络
扫描可用网络,在>提示符之后输入“scan”。在扫描完成后将显示通知:
> scan OK <3>CTRL-EVENT-SCAN-RESULTS >
然后输入 "scan_results" 来显示结果:
> scan_results bssid / frequency / signal level / flags / ssid 00:00:00:00:00:00 2462 -49 [WPA2-PSK-CCMP][ESS] MYSSID 11:11:11:11:11:11 2437 -64 [WPA2-PSK-CCMP][ESS] ANOTHERSSID >
为了与MYSSID相关联,需要告知wpa_supplicant。在配置文件中的各个网络是以零开始按数值进行索引。如果您添加了一个新的网络,它会被相应地分配一个新数字。
> add_network 0 >
使用这个数字来指定你的设置应用到哪个网络。对于一个新的网络,在引号里设置其SSID:
> set_network 0 ssid "MYSSID" OK >
即使你的无线接入点没有被保护,cli也显式地需要一个PSK,同样在引号内。密码必须是8-63个字符:
> set_network 0 psk "passkey" OK >
使能:
> enable_network 0 OK >
将修改写入配置文件:
> save_config OK >
动作脚本
wpa_cli可以在后台模式下运行,并执行基于wpa_supplicant事件的指定脚本。可以支持两类事件:连接和断开。一些环境变量可用于脚本,细节请参考man 8wpa_cli。
下面的例子将使用桌面通知,通知有关事件的用户:
#!/bin/bash case "$2" in CONNECTED) notify-send "WPA supplicant: connection established"; ;; DISCONNECTED) notify-send "WPA supplicant: connection lost"; ;; esac
记住修改脚本为可执行,然后使用-a来传递脚本路径给wpa_cli:
$ wpa_cli -a path_to_script
另请参阅
目前可以使用wireless-tools 或wpa_supplicant工具来配置无线网络。请记住重要的一点是,对无线网络的配置是全局性的,而非针对具体的接口。
wpa_supplicant是一个较好的选择,但缺点是它不支持所有的驱动。请浏览wpa_supplicant网站获得它所支持的驱动列表。另外,wpa_supplicant目前只能连接到那些你已经配置好ESSID的无线网络。wireless-tools支持几乎所有的无线网卡和驱动,但它不能连接到那些只支持WPA的AP。
经过编译后的wpa_supplicant源程序可以看到两个主要的可执行工具:wpa_supplicant和wpa_cli。wpa_supplicant是核心程序,它和wpa_cli的关系就是服务和客户端的关系:后台运行wpa_supplicant,使用wpa_cli来搜索、设置、和连接网络。
如何用wpa_supplicant使能一个wifi连接?
Step by step:
1、运行wpa_supplicant程序;
执行:/system/bin/wpa_supplicant -d -Dwext -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf
其中:
-d :增加调试信息
-Dwext :wext,驱动名称
-iwlan0 :wlan0,网络接口名称
/system/bin/wpa_supplicant :wpa_supplicant可执行程序path
/data/misc/wifi/wpa_supplicant.conf :wpa_supplicant的配置文件path
2、运行命令行工具wpa_cli ;
执行:wpa_cli -iwlan0 -p/data/system/wpa_supplicant
注,-p/data/system/wpa_supplicant中的wpa_supplicant并不是可执行程序,而是个控制套接字。
此时会进入交互模式。其中交互模式的命令如下表:
Full command | Short command | Description |
status | stat | displays the current connection status |
disconnect | disc | prevents wpa_supplicant from connecting to any access point |
quit | q | exits wpa_cli |
terminate | term | kills wpa_supplicant |
reconfigure | recon | reloads wpa_supplicant with the configuration file supplied (-c parameter) |
scan | scan | scans for available access points (only scans it, doesn't display anything) |
scan_result | scan_r | displays the results of the last scan |
list_networks | list_n | displays a list of configured networks and their status (active or not, enabled or disabled) |
select_network | select_n | select a network among those defined to initiate a connection (ie select_network 0) |
enable_network | enable_n | makes a configured network available for selection (ie enable_network 0) |
disable_network | disable_n | makes a configured network unavailable for selection (ie disable_network 0) |
remove_network | remove_n | removes a network and its configuration from the list (ie remove_network 0) |
add_network | add_n | adds a new network to the list. Its id will be created automatically |
set_network | set_n | shows a very short list of available options to configure a network when supplied with no parameters. See next section for a list of extremely useful parameters to be used with set_network and get_network. |
get_network | get_n | displays the required parameter for the specified network. See next section for a list of parameters |
save_config | save_c | saves the configuration |
设置网络的基本格式:set_network <network id> <key> <parameter> [<parameter>]
显示网络信息的基本格式:get_network <network id> <key>
相应的参数如下表:
Key | Description | Parameters |
ssid | Access point name | string |
id_str | String identifying the network | string |
priority | Connection priority over other APs | number (0 being the default low priority) |
bssid | Mac address of the access point | mac address |
scan_ssid | Enable/disbale ssid scan | 0, 1, 2 |
key_mgmt | Type of key management | WPA-PSK, WPA_EAP, None |
pairwise | Pairwise ciphers for WPA | CCMP, TKIP |
group=TKIP | Group ciphers for WPA | CCMP, TKIP, WEP104, WEP40 |
psk | Pre-Shared Key (clear or encrypted) | string |
wep_key0 | WEP key (up to 4: wep_key[0123]) | string |
eap | Extensible Authentication Protocol | MD5, MSCHAPV2, OTP, GTC, TLS, PEAP, TTLS |
identity | EAP identity string | string |
password | EAP password | string |
ca_cert | Pathname to CA certificate file | /full/path/to/certificate |
client_cert | Pathname to client certificate | /full/path/to/certificate (PEM/DER) |
private_key | Pathname to a client private key file | /full/path/to/private_key (PEM/DER/PFX) |
eg.1、连接无加密的AP
>add_network (It will display a network id for you, assume it returns 0)
>set_network 0 ssid "666"
>set_network 0 key_mgmt NONE
>enable_network 0
>quit
eg.2、连接WEP加密AP
>add_network (assume return 1)
>set_network 1 ssid "666"
>set_network 1 key_mgmt NONE
>set_network 1 wep_key0 "your ap password"
>enable_network 1
eg.3、连接WPA-PSK/WPA2-PSK加密的AP
>add_network (assume return 2)
>set_network 2 ssid "666"
>set_network 2 psk "your pre-shared key"
>enable_network 2
到此,wifi模块就能连接上AP了。
3、以上是通过命令行工具wpa_cli来实现wifi网络的连接。当然,也可以通过wpa_supplicant的配置文件来实现连接。
再回顾下运行wpa_supplicant时执行的命令:
/system/bin/wpa_supplicant -d -Dwext -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf
我们在执行时加上了-c/data/misc/wifi/wpa_supplicant.conf,我们可以将我们要连接的AP的设置以一定的格式写入wpa_supplicant.conf配置文件中即可。
eg.
ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=system update_config=1
network={
ssid="my access point"
proto=WPA
key_mgmt=WPA-PSK
psk="you pass words"