P2pStateMachine收到P2P_PROV_DISC_PBC_RSP_EVENT消息后,將在ProvisionDiscoveryState中調用p2pConnectWithPinDisplay,該函數內部將發送P2P_CONNECT命令給WPAS。馬上來看該命令的處理流程。
**1、P2P_CONNECT處理流程**
P2P_CONNECT命令的參數比較多,而本例中P2pStateMachine發送的命令格式如下。
~~~
P2P_CONNECT 8a:32:9b:6c:d1:80 pbc go_intent=7
//其中,"8a:32:9b:6c:d1:80"代表對端P2P設備地址
//"pbc"指定了WSC配置方法為PBC,"go_intent=7"設置GO Intent值為7
~~~
P2P_CONNECT對應的處理函數為p2p_ctrl_connect,其代碼如下所示。
**ctrl_iface.c::p2p_ctrl_connect**
~~~
static int p2p_ctrl_connect(struct wpa_supplicant*wpa_s,
char *cmd,char *buf, size_t buflen)
{
u8 addr[ETH_ALEN];
char *pos, *pos2;
char *pin = NULL;
enum p2p_wps_method wps_method;
int new_pin;
int ret;
int persistent_group;
int join;
int auth;
int go_intent = -1;
int freq = 0;
if (hwaddr_aton(cmd, addr))
return -1;
......// 參數處理,最終調用的函數為wpas_p2p_connect
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, join, auth, go_intent,freq);
......
os_memcpy(buf, "OK\n", 3);
return 3;
}
~~~
wpas_p2p_connect的代碼如下所示。
**p2p_supplicant.c::wpas_p2p_connect**
~~~
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int join, int auth, int go_intent,int freq)
{
int force_freq = 0, oper_freq = 0;
u8 bssid[ETH_ALEN];
int ret = 0;
enum wpa_driver_if_type iftype;
const u8 *if_addr;
......
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
wpa_s->p2p_wps_method = wps_method;
wpa_s->p2p_pin[0] = '\0';
// 本例中,由于GON還未完成,GO角色未能確定,所以join為0
if (join) {......}
......// 頻段設置
/*
注意下面這個wpas_p2p_create_iface函數,它將判斷是否需要創建一個新的virtual interface,還記得
7.4.1節介紹Driver Flags和重要數據結構時提到的WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P
標志嗎?就本例而言,wifi driver flags中包含了該標志,所以下面這個函數的返回值為1,表示需要單獨創建
一個新的virtual interface供P2P使用。這個virtual interface的地址應該就是P2P Interface Address。
*/
wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
if (wpa_s->create_p2p_iface) { // 本例滿足此if條件
iftype = WPA_IF_P2P_GROUP; // 設置interface type
if (go_intent == 15) iftype = WPA_IF_P2P_GO; // 本例的go_intent為7
/*
下面這個函數將創建此virtual interface,并獲取其interface address。以Galaxy Note 2
為例。P2P Device Address是“92:18:7c:69:88:e2”,而P2P Interface Address是
“92:18:7c:69:08:e2”。
wpas_p2p_add_group_interface內部將調用driver_nl80211.c的wpa_driver_nl80211_if_add
函數。感興趣的讀者不妨自行研究。
*/
if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0)
return -1;
if_addr = wpa_s->pending_interface_addr;
} else
if_addr = wpa_s->own_addr;
.......
// 下面這個函數內部將調用p2p_connect,我們將直接分析
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr, force_freq,persistent_group) < 0) {......}
return ret;
}
~~~
**2、GON Request發送流程**
來看p2p_connect函數,其代碼如下所示。
**p2p.c::p2p_connect**
~~~
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq,
int persistent_group)
{
struct p2p_device *dev;
// 如果指定了工作頻段,則需要判斷是否支持該工作頻段
if (p2p_prepare_channel(p2p, force_freq) < 0)
return -1;
p2p->ssid_set = 0;
dev = p2p_get_device(p2p, peer_addr);
......// 設置dev的一些信息
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
// 如果P2P模塊的狀態不為P2P_IDLE,則先停止find工作
if (p2p->state != P2P_IDLE)
p2p_stop_find(p2p);
......
dev->wps_method = wps_method;
dev->status = P2P_SC_SUCCESS;
......
if (p2p->p2p_scan_running) {
/*
如果當前P2P還在掃描過程中,則設置start_after_scan為P2P_AFTER_SCAN_CONNECT標志,
當scan結束后,在掃描結果處理流程中,該標志將通知P2P進入connect處理流程。
*/
p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT;
os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
return 0;
}
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
// 下面這個函數將發送GON Request幀,直接來看該函數
return p2p_connect_send(p2p, dev);
}
~~~
**p2p_go_neg.c::p2p_connect_send**
~~~
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
{
struct wpabuf *req; int freq;
......
req = p2p_build_go_neg_req(p2p, dev);
p2p_set_state(p2p, P2P_CONNECT); // 設置P2P模塊的狀態為P2P_CONNECT
// 設置pending_action_state為P2P_PENDING_GO_NEG_REQUEST
p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
p2p->go_neg_peer = dev; // 設置GON對端設備
dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->connect_reqs++;
#ifdef ANDROID_P2P
dev->go_neg_req_sent++;
#endif
// 發送GON Request幀
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0) {......}
......
return 0;
}
~~~
至此,GON Request幀就將發送給對端P2P設備。圖7-36描述了P2P_CONNECT命令的處理流程。
:-: 
圖7-36 P2P_CONNECT命令處理流程
**3、GON Response幀處理流程**
根據前面對Action幀接收流程的分析可知,收到的GON Response幀將在p2p_process_go_neg_resp函數中被處理。該函數的代碼如下所示。
**p2p_go_neg.c::p2p_process_go_neg_resp**
~~~
void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
struct p2p_device *dev;
struct wpabuf *conf;
int go = -1;
struct p2p_message msg; u8 status = P2P_SC_SUCCESS;
int freq;
dev = p2p_get_device(p2p, sa);
// 解析GON Response幀
if (p2p_parse(data, len, &msg))
return;
......// 參數檢查
/*
下面這個函數將利用圖7-13計算誰來扮演GO。返回值大于0,表示本機扮演GO,
返回-1表示雙方都想成為GO,返回值為0,表示對端扮演GO。本例中,假設GO為本機設備。
*/
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
......// 參數檢查,內容比較繁雜,感興趣的讀者請自行研究
if (go) {
......
// 處理工作頻段
}
p2p_set_state(p2p, P2P_GO_NEG);// 設置P2P模塊的狀態為P2P_GO_NEG
p2p_clear_timeout(p2p);
......
fail:
// 構造GON Confirmation幀
conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status,
msg.operating_channel, go);
p2p_parse_free(&msg);
.......
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;// 本機扮演GO
} else
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
......
// 發送GON Confirmation幀
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {......}
wpabuf_free(conf);
}
~~~
p2p_process_go_neg_resp實際的代碼比較復雜,建議初學者先了解上面代碼所涉及的大體流程。
當GON Confirmation幀發送出去后,wifi driver將向WPAS發送一個NL80211_CMD_FRAME_TX_STATUS消息,而該消息將導致driver wrapper發送EVENT_TX_STATUS消息給WPAS。下面我們直接來看EVENT_TX_STATUS的處理流程。
**4、EVENT_TX_STATUS處理流程**
在events.c中,和P2P以及EVENT_TX_STATUS相關的處理函數是offchannel_send_action_tx_status,該函數的代碼如下所示。
**offchannel.c::offchannel_send_action_tx_status**
~~~
void offchannel_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
const u8 *data,size_t data_len, enum offchannel_send_action_result result)
{
......// 參數檢查
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
/*
注意下面這個pending_action_tx_status_cb參數,它是一個函數指針,P2P每次發送Action的時候,
都會設置該變量。其真實的函數為wpas_p2p_send_action_tx_status(在wpas_send_action
函數中設置)
*/
if (wpa_s->pending_action_tx_status_cb) {
wpa_s->pending_action_tx_status_cb( wpa_s, wpa_s->pending_action_freq,
wpa_s->pending_action_dst, wpa_s->pending_action_src,
wpa_s->pending_action_bssid, data, data_len, result);
}
}
~~~
來看wpas_p2p_send_action_tx_status,其代碼如下所示。
**p2p_supplicant.c::wpas_p2p_send_action_tx_status**
~~~
static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq,const u8 *dst, const u8 *src, const u8 *bssid,
const u8 *data, size_t data_len, enum offchannel_send_action_result result)
{
enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
......
// 重要函數:p2p_send_action_cb
p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
......
}
~~~
p2p_send_action_cb的代碼如下所示。
**p2p.c::p2p_send_action_cb**
~~~
void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,enum p2p_send_action_result result)
{
enum p2p_pending_action_state state;
int success;
success = result == P2P_SEND_ACTION_SUCCESS;
// 讀者還記得該變量的值嗎?它應該是P2P_PENDING_GO_NEG_CONFIRM
state = p2p->pending_action_state;
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
switch (state) {
case P2P_NO_PENDING_ACTION:
break;
case P2P_PENDING_GO_NEG_REQUEST:
// 讀者可自行研究此函數。當發送完GON Request幀后,此函數也會被觸發
p2p_go_neg_req_cb(p2p, success);
break;
......
case P2P_PENDING_GO_NEG_CONFIRM:
p2p_go_neg_conf_cb(p2p, result);// 分析這個函數
break;
......// 其他case處理
}
}
~~~
來看p2p_go_neg_conf_cb函數,代碼如下所示。
**p2p.c::p2p_go_neg_conf_cb**
~~~
static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
enum p2p_send_action_result result)
{
struct p2p_device *dev;
/*
每次收到TX Report后,都需要調用send_action_cb,其對應的真實函數是wpas_send_action_done。
*/
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
......
dev = p2p->go_neg_peer;
if (dev == NULL)
return;
p2p_go_complete(p2p, dev);
}
~~~
p2p_go_complete函數比較簡單,其代碼如下所示。
**p2p.c::p2p_go_complete**
~~~
void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
{
struct p2p_go_neg_results res;
int go = peer->go_state == LOCAL_GO;
struct p2p_channels intersection;
int freqs;
size_t i, j;
......// 設置頻段等參數
p2p_set_state(p2p, P2P_PROVISIONING);// 進入Group Formation的Provisioning階段
// go_neg_completed對應的函數是wpas_go_neg_completed
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
}
~~~
**p2p_supplicant.c::wpas_go_neg_compeleted**
~~~
void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
......
// 下面這個函數將導致P2pStateMachine收到P2P_GO_NEGOTIATION_SUCCESS_EVENT消息
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
wpas_notify_p2p_go_neg_completed(wpa_s, res);
if (wpa_s->create_p2p_iface) {// 本例滿足此if條件
/*
再創建一個wpa_supplicant對象。感興趣的讀者可自行研究下面這個函數。其內部將調用4.4.3節
分析的wpa_supplicant_add_iface函數。
*/
struct wpa_supplicant *group_wpa_s =
wpas_p2p_init_group_interface(wpa_s, res->role_go);
......
// 如果本機扮演GO,則啟動WSC Registrar功能,否則啟動Enrollee功能
// 下面這兩個函數留給讀者自行分析
if (res->role_go)
wpas_start_wps_go(group_wpa_s, res, 1);
else
wpas_start_wps_enrollee(group_wpa_s, res);
} ......
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
// Group Formation的超時時間為15秒左右
eloop_register_timeout(15 + res->peer_config_timeout / 100,
(res->peer_config_timeout % 100) * 10000,
wpas_p2p_group_formation_timeout, wpa_s, NULL);
}
~~~
當Group Negotiation完成后,WPAS將新創建一個wpa_supplicant對象,它將用于管理和操作專門用于P2P Group的virtual interface,此處有幾點請讀者注意。
* 4.3.1節中介紹過,一個interface對應一個wpa_supplicant對象。
* 此處新創建的wpa_supplicant對象用于GO,即扮演AP的角色,專門處理和P2P Group相關的事情,其MAC地址為P2P Interface Address。
* 之前使用的wpa_supplicant用于非P2P Group操作,其MAC地址為P2P Device Address。
至此,整個EVENT_TX_STATUS處理流程就分析完畢了,其內容比較復雜。圖7-37整理了此過程中一些重要的函數調用。
注意,圖7-37實際上描述的是GON Confirmation幀對應的EVENT_TX_STATUS處理流程,和其他EVENT_TX_STATUS處理流程相比,前面7個函數調用都是一樣的。
:-: 
圖7-37 EVENT_TX_STATUS處理流程
- 前言
- 第1章 準備工作
- 1.1 Android系統架構
- 1.2 工具使用
- 1.2.1 Source Insight的使用
- 1.2.2 Eclipse的使用
- 1.2.3 BusyBox的使用
- 1.3 本書資源下載說明
- 第2章 深入理解Netd
- 2.1 概述
- 2.2 Netd工作流程
- 2.2.1 main函數分析
- 2.2.2 NetlinkManager分析
- 2.2.3 CommandListener分析
- 2.2.4 DnsProxyListener分析
- 2.2.5 MDnsSdListener分析
- 2.3 CommandListener中的命令
- 2.3.1 iptables、tc和ip命令
- 2.3.2 CommandListener構造函數和測試工具ndc
- 2.3.3 InterfaceCmd命令
- 2.3.4 IpFwd和FirewallCmd命令
- 2.3.5 ListTtysCmd和PppdCmd命令
- 2.3.6 BandwidthControlCmd和IdletimerControlCmd命令
- 2.3.7 NatCmd命令
- 2.3.8 TetherCmd和SoftapCmd命令
- 2.3.9 ResolverCmd命令
- 2.4 NetworkManagementService介紹
- 2.4.1 create函數詳解
- 2.4.2 systemReady函數詳解
- 2.5 本章總結和參考資料說明
- 2.5.1 本章總結
- 2.5.2 參考資料說明
- 第3章 Wi-Fi基礎知識
- 3.1 概述
- 3.2 無線電頻譜和802.11協議的發展歷程
- 3.2.1 無線電頻譜知識
- 3.2.2 IEEE 802.11發展歷程
- 3.3 802.11無線網絡技術
- 3.3.1 OSI基本參考模型及相關基本概念
- 3.3.2 802.11知識點導讀
- 3.3.3 802.11組件
- 3.3.4 802.11 Service介紹
- 3.3.5 802.11 MAC服務和幀
- 3.3.6 802.11 MAC管理實體
- 3.3.7 無線網絡安全技術知識點
- 3.4 Linux Wi-Fi編程API介紹
- 3.4.1 Linux Wireless Extensions介紹
- 3.4.2 nl80211介紹
- 3.5 本章總結和參考資料說明
- 3.5.1 本章總結
- 3.5.2 參考資料說明
- 第4章 深入理解wpa_supplicant
- 4.1 概述
- 4.2 初識wpa_supplicant
- 4.2.1 wpa_supplicant架構
- 4.2.2 wpa_supplicant編譯配置
- 4.2.3 wpa_supplicant命令和控制API
- 4.2.4 git的使用
- 4.3 wpa_supplicant初始化流程
- 4.3.1 main函數分析
- 4.3.2 wpa_supplicant_init函數分析
- 4.3.3 wpa_supplicant_add_iface函數分析
- 4.3.4 wpa_supplicant_init_iface函數分析
- 4.4 EAP和EAPOL模塊
- 4.4.1 EAP模塊分析
- 4.4.2 EAPOL模塊分析
- 4.5 wpa_supplicant連接無線網絡分析
- 4.5.1 ADD_NETWORK命令處理
- 4.5.2 SET_NETWORK命令處理
- 4.5.3 ENABLE_NETWORK命令處理
- 4.6 本章總結和參考資料說明
- 4.6.1 本章總結
- 4.6.2 參考資料說明
- 第5章 深入理解WifiService
- 5.1 概述
- 5.2 WifiService的創建及初始化
- 5.2.1 HSM和AsyncChannel介紹
- 5.2.2 WifiService構造函數分析
- 5.2.3 WifiStateMachine介紹
- 5.3 加入無線網絡分析
- 5.3.1 Settings操作Wi-Fi分析
- 5.3.2 WifiService操作Wi-Fi分析
- 5.4 WifiWatchdogStateMachine介紹
- 5.5 Captive Portal Check介紹
- 5.6 本章總結和參考資料說明
- 5.6.1 本章總結
- 5.6.2 參考資料說明
- 第6章 深入理解Wi-Fi Simple Configuration
- 6.1 概述
- 6.2 WSC基礎知識
- 6.2.1 WSC應用場景
- 6.2.2 WSC核心組件及接口
- 6.3 Registration Protocol詳解
- 6.3.1 WSC IE和Attribute介紹
- 6.3.2 802.11管理幀WSC IE設置
- 6.3.3 EAP-WSC介紹
- 6.4 WSC代碼分析
- 6.4.1 Settings中的WSC處理
- 6.4.2 WifiStateMachine的處理
- 6.4.3 wpa_supplicant中的WSC處理
- 6.4.4 EAP-WSC處理流程分析
- 6.5 本章總結和參考資料說明
- 6.5.1 本章總結
- 6.5.2 參考資料說明
- 第7章 深入理解Wi-Fi P2P
- 7.1 概述
- 7.2 P2P基礎知識
- 7.2.1 P2P架構
- 7.2.2 P2P Discovery技術
- 7.2.3 P2P工作流程
- 7.3 WifiP2pSettings和WifiP2pService介紹
- 7.3.1 WifiP2pSettings工作流程
- 7.3.2 WifiP2pService工作流程
- 7.4 wpa_supplicant中的P2P
- 7.4.1 P2P模塊初始化
- 7.4.2 P2P Device Discovery流程分析
- 7.4.3 Provision Discovery流程分析
- 7.4.4 GO Negotiation流程分析
- 7.5 本章總結和參考資料說明
- 7.5.1 本章總結
- 7.5.2 參考資料說明
- 第8章 深入理解NFC
- 8.1 概述
- 8.2 NFC基礎知識
- 8.2.1 NFC概述
- 8.2.2 NFC R/W運行模式
- 8.2.3 NFC P2P運行模式
- 8.2.4 NFC CE運行模式
- 8.2.5 NCI原理
- 8.2.6 NFC相關規范
- 8.3 Android中的NFC
- 8.3.1 NFC應用示例
- 8.3.2 NFC系統模塊
- 8.4 NFC HAL層討論
- 8.5 本章總結和參考資料說明
- 8.5.1 本章總結
- 8.5.2 參考資料說明
- 第9章 深入理解GPS
- 9.1 概述
- 9.2 GPS基礎知識
- 9.2.1 衛星導航基本原理
- 9.2.2 GPS系統組成及原理
- 9.2.3 OMA-SUPL協議
- 9.3 Android中的位置管理
- 9.3.1 LocationManager架構
- 9.3.2 LocationManager應用示例
- 9.3.3 LocationManager系統模塊
- 9.4 本章總結和參考資料說明
- 9.4.1 本章總結
- 9.4.2 參考資料說明
- 附錄