🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
1. 命令介绍 由图4-1的介绍可知,WPAS对外通过控制接口模块与客户端通信。在Android平台中,WPAS的客户端是位于Framework中的WifiService。用户在Settings界面进行Wi-Fi相关的操作最终都会经由WifiService通过发送命令的方式转交给wpa_supplicant去执行。 WPAS定义了许多命令,常见的: * **PING**:心跳检测命令。客户端用它判断WPAS是否工作正常。WPAS收到”PING”命令后需要回复“PONG”。 * **MIB**:客户端用该命令获取设备的MIB信息。 * **STATUS**:客户端用该命令来获取WPAS的工作状态。 * **ADD_NETWORK**:为WPAS添加一个新的无线网络。它将返回此新无线网络的id(从0开始)。注意:此network id非常重要,客户端后续将通过它来指明自己想操作的无线网络。 * **SET_NETWORK** `<network id> <variable> <value>`:network id是无线网络的id。此命令用于设置指定无线网络的信息。其中variable为参数名,value为参数的值。 * **ENABLE_NETWORK** `<network id>`:使能某个无线网络。此命令最终将促使WPAS发起一系列操作以加入该无线网络。 除了接收来自Client的命令外,WPAS也会主动给Client发送命令。例如,WPAS需用户为某个无线网络输入密码。这类命令称之为Interactive Request,其格式如下。 WPAS向客户端发送的命令遵循以下格式: `CTRL-REQ-<field name>-<network id>-<human readable text>`格式。 如CTRL-REQ-PASSWORD-0-Passwork needed for SSID test-network。这条命令表示需要用户为0号网络输入密码。 客户端处理完后,需回复`CTRL-RSP-<field name>-<network id>-<value>`。 目前支持的field包括PASSWORD、IDENTITY(EAP中的identity或者用户名)、PIN等。 最后,WPAS还可通过形如“`CTRL-EVENT-<field>-<text>`”的命令向客户端通知一些事情。 **提示**:除了“CTRL-EVENT-XXX”之外,WPAS还支持形如“WPA:XXX”和“WPS-XXX”的通知事件。这些事件和WPA和WPS有关。下一章分析WifiService时我们还能见到它们。 图4-2所示为笔者利用wpa_cli测试status命令得到的结果。 :-: ![](http://img.blog.csdn.net/20140309205109171?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSW5ub3N0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 图4-2 wpa_cli命令测试示意 图4-2所示为status命令的结果。图中最后几行显示WPAS向wpa_cli返回了两个CTRL-EVENT信息。 2. 控制API介绍 Android平台中WifiService是WPAS的客户端,它和WPAS交互时必须使用wpa_supplicant提供的API。这些API声明于wpa_ctrl.h中,其用法如下: ~~~ //必须包含此头文件,链接时需包含libwpa_client.so动态库 #include “wpa_ctrl.h” ~~~ 客户端使用wpa_ctrl时首先要分配控制对象。下面两个API用于创建和销毁控制对象wpa_ctrl: ~~~ //创建一个wpa控制端对象wpa_ctrl。Android平台中,参数ctrl_path代表unix域socket的位置 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); void wpa_ctrl_close(struct wpa_ctrl *ctrl);//注销wpa_ctrl控制对象 ~~~ 下面这个函数用于发送命令给WPAS。 ~~~ //客户端发送命令给wpa_supplicant,回复的消息保存在reply中 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)); ~~~ msg_cb是一个回调函数,该参数的设置和WPAS中C/S通信机制的设计有关: 从Client角度来看,它发送给WPAS的命令所对应的回复属于solicited event(意为有请求的事件),而前面所提到的CTRL-EVENT事件(用于通知事件)对应为unsolicited event(意为未请求的事件)。当Client在等待某个命令的回复时,WPAS同时可能有些通知事件要发送给客户端,这些通知事件不是该命令的回复,所以不能通过wpa_ctrl_request的reply参数返回。 为了防止丢失这些通知事件,wpa_cli设计了一个msg_cb回调用于客户端在等待命令回复的时候处理那些unsolicited event。 这种一个函数完成两样完全不同的功能的设计实在有些特别,所以wpa_supplicant规定只有打开通知事件监听功能的wpa_ctrl对象才能在wpa_ctrl_request中通过msg_cb获取通知事件。而打开通知事件监听功能相关的API如下所示。 ~~~ //打开通知事件监听功能 int wpa_ctrl_attach(struct wpa_ctrl *ctrl); //打开通知事件监听功能的wpa_ctrl对象能直接调用下面的函数来接收unsolicited event int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); ~~~ 如果客户端并不发送命令,而只是想接收Unsolicited event的话,可通过wpa_ctrl_recv函数来达到此目的。 综上所述,单独使用wpa_ctrl_recv和wpa_ctrl_request都不方便。所以,一种常见的用法是:客户端创建两个wpa_ctrl对象来简化自己的逻辑处理: * 一个打开了通知事件监听功能的wpa_ctrl对象将只通过wpa_ctrl_recv来接收通知事件。 * 另外一个wpa_ctrl专职用于发送命令和接收回复。由于没有调用wpa_ctrl_attach,故它不会收到通知事件。 **提示**:下一章分析WifiService时将见到这种创建两个wpa_ctrl对象的做法。