首先來看WPAS中P2P相關模塊的初始化。該初始化工作我們在第4章4.3.4中“wpa_supplicant_init_iface分析之五”曾提到過,其對應的函數wpas_p2p_init,馬上來看它
**p2p_supplicant.c::wpas_p2p_init**
~~~
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
{
struct p2p_config p2p; //p2p變量指向一個p2p_config對象,代表P2P模塊的配置信息
unsigned int r; int i;
//①WPA_DRIVER_FLAGS_P2P_CAPABLE:代表Wifi驅動對P2P支持的能力,詳情見下文解釋
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)) return 0;
if (global->p2p) return 0;
//如果wifi driver能完成P2P功能,就不用勞駕WPAS了
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {......}
//②初始化并設置p2p_config對象
os_memset(&p2p, 0, sizeof(p2p));
p2p.msg_ctx = wpa_s; p2p.cb_ctx = wpa_s;
p2p.p2p_scan = wpas_p2p_scan; //P2P對應的掃描函數
.......//設置一些回調函數
p2p.get_noa = wpas_get_noa; p2p.go_connected = wpas_go_connected;
//設置P2P Device address。
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
//設置P2P模塊配置信息,包括device name,model name,uuid等
p2p.dev_name = wpa_s->conf->device_name;
p2p.manufacturer = wpa_s->conf->manufacturer;
p2p.model_name = wpa_s->conf->model_name;
p2p.model_number = wpa_s->conf->model_number;
p2p.serial_number = wpa_s->conf->serial_number;
if (wpa_s->wps) {
os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
p2p.config_methods = wpa_s->wps->config_methods;
}
//設置Operation Channel信息和listen channel信息
if (wpa_s->conf->p2p_listen_reg_class &&
wpa_s->conf->p2p_listen_channel) {
p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
p2p.channel = wpa_s->conf->p2p_listen_channel;
} else {
......//設置默認值
}
......
//設置國家碼
if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
os_memcpy(p2p.country, wpa_s->conf->country, 2);
p2p.country[2] = 0x04;
} else//配置文件中沒有設置國家,所以取值為"XX\x04"
os_memcpy(p2p.country, "XX\x04", 3);//讀者可回顧圖7-7
//判斷wifi 驅動是否支持配置文件中設置的operationg channel和listen channel
if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {......}
os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,WPS_DEV_TYPE_LEN);
p2p.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
os_memcpy(p2p.sec_dev_type, wpa_s->conf->sec_device_type,
p2p.num_sec_dev_types * WPS_DEV_TYPE_LEN);
//是否支持concurrent operation
p2p.concurrent_operations = !!(wpa_s->drv_flags&WPA_DRIVER_FLAGS_P2P_CONCURRENT);
p2p.max_peers = 100;//最多能保存100個對端P2P Device信息
//配置文件中沒有設置p2p_ssid_postfix,但P2pStateMachine在initializeP2pSettings函數中
//將設置P2P SSID后綴。以筆者的Galaxy Note2為例,其P2P SSID后綴為“Android_4aa9”
if (wpa_s->conf->p2p_ssid_postfix) {......}
p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
//③global->p2p指向一個p2p_data結構體,它是WPAS中P2P模塊的代表
global->p2p = p2p_init(&p2p);
......
for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {//拷貝vendor廠商特定的WSC屬性信息
if (wpa_s->conf->wps_vendor_ext[i] == NULL) continue;
p2p_add_wps_vendor_extension(global->p2p, wpa_s->conf->wps_vendor_ext[i]);
}
return 0;
}
~~~
由上述代碼可知,wpas_p2p_init的工作非常簡單,主要內容包括:
初始化一個p2p_config對象,然后根據p2p_supplicant.conf文件的信息來設置其中的內容,同時還需要為P2P模塊設置一些回調函數。
調用p2p_init函數以初始化P2P模塊。
下面來介紹上述代碼中涉及到的一些知識。
**1、Driver Flags和重要數據結構介紹**
先來看上述代碼中提到的drv_flags變量。WPAS中,Wifi驅動對P2P功能的支持情況就是由它來表達的。筆者的Galaxy Note2中該變量取值為0x2EAC0,其表達的含義如下:
**driver.h**
~~~
#define WPA_DRIVER_FLAGS_AP 0x00000040 //Wifi driver支持AP。它使得P2P設備能扮演GO
/*
標志標明association成功后,kernel driver需要設置WEP key
這個標志出現的原因是由于kernel API發生了變動,使得只能在關聯成功后才能設置key
*/
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080
#define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200 //Wifi驅動支持STA和P2P的并發運行
#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800 //Wifi驅動支持P2P
/*
7.2.2.1.2“Probe Request幀設置”一節曾提到過說P2P包含Device Address和Interface Address
兩種類型的地址。在實際實現過程中,這兩個地址分別代表兩個virtual interface。顯然,P2P中第一個和一直
存在的是擁有Device Address的vitural interface。下面這個標志表示該virtual interface可以參與
P2P管理(除P2P Group Operation之外的工作)工作以及非P2P相關的工作(例如利用這個virtual
interface 加入到一個BSS)
*/
#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 0x00002000
/*
該標志主要針對associate操作。當關聯操作失敗后,如果driver支持該選項,則表明driver能處理失敗之
后的各種收尾工作(Key、timeout等工作)。否則,WPAS需要自己處理這些事情
*/
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
//下面這個標志和off channel機制有關。讀者可參考第4章4.3.4中“capability介紹”一節。當802.11
//MAC幀通過off channel發送的話,下面這個標志表示driver會反饋一個發送情況(TX Report)消息給WPAS
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
//下面這兩個標志表示kernel中的driver是否能反饋Deauthentication/Disassociation幀
//發送情況(TX Report)
#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000
~~~
下面來看wpas_p2p_init中出現的幾個重要數據結構,首先是p2p_config和p2p_data,它們的成員如圖7-29所示:
:-: 
圖7-29 p2p_config和p2p_data結構示意圖
圖7-29展示了p2p_config和p2p_data兩個數據結構中一些重要的成員。其中:
* p2p_config定義了20個回調函數。這些回調函數定義了P2P模塊和外界交互的接口。在wpas_p2p_init中,這些回調函數均指向p2p_supplicant.c中對應的函數,例如p2p_scan指向wpas_p2p_scan,dev_lost指向wpas_dev_lost。另外,由于回調函數的參數比較復雜,所以圖中均省略了參數信息。
* p2p_data指向一個p2p_config對象。
下面來看另外幾個重要數據結構的內容圖7-30展示了五種數據結構,其中:
* p2p_device代表一個P2P設備。其中一些諸如設備名,Device CapabilityBitmap等信息保存在一個類型為p2p_peer_info的對象中。
* p2p_group代表一個P2P Group的信息,其內部包含一個p2p_group_config對象和一個p2p_group_member鏈表。p2p_group_config表示該Group的配置信息,p2p_group_member代表Group Member即P2P Client的信息。
下面來看另外幾個重要數據結構的內容,如圖7-30所示:
:-: 
圖7-30 p2p_device及其他數據結構示意圖
>[info] 提示: WPAS中定義了非常多的數據結構類型,這極大增加了初學者的學習難度。根據筆者自己的經驗,建議讀者在學習過程中先簡單了解這些數據結構的名字及作用,然后在具體代碼分析時再結合代碼邏輯來了解這些數據結構及其內部各個成員變量的具體作用。
下面來看p2p_init函數。
**2、p2p_init函數**
p2p_init函數將初始化WPAS中的P2P模塊,其代碼如下所示。
**p2p.c::p2p_init**
~~~
struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
......
/*
從下面這行代碼可看出,一個p2p_data對象的內存分布,該內存將包含一個p2p_data的所有信息以及一個
p2p_config對象的所有信息。
*/
p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));
// 將p2p_data的cfg成員變量指向保存p2p_config信息的那塊內存地址
p2p->cfg = (struct p2p_config *) (p2p + 1);
os_memcpy(p2p->cfg, cfg, sizeof(*cfg)); // 拷貝傳入的p2p_config信息
if (cfg->dev_name) p2p->cfg->dev_name = os_strdup(cfg->dev_name);
......// 其他信息拷貝
#ifdef ANDROID_P2P
p2p->min_disc_int = 2; // listen state的最小時間為200毫秒
p2p->sd_dev_list = NULL;
#else
p2p->min_disc_int = 1;
#endif
p2p->max_disc_int = 3;
// 隨機獲取next_tie_breaker的初值
// 第二個參數1表示next_tie_breaker的字節長度,其類型是u8
os_get_random(&p2p->next_tie_breaker, 1);
p2p->next_tie_breaker &= 0x01;
// 設置本機P2P Device的device capability信息
if (cfg->sd_request) p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
p2p->dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
if (cfg->concurrent_operations)// 支持concurrent功能
p2p->dev_capab |= P2P_DEV_CAPAB_CONCURRENT_OPER;
p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
dl_list_init(&p2p->devices);
// 注冊一個超時時間(如果定義了ANDROID_P2P宏,該時間為30ms)
// 用來檢測是否有不活躍的p2p_device
eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,p2p_expiration_timeout, p2p, NULL);
return p2p;
}
~~~
p2p模塊初始化還算比較簡單。
**3、注冊Action幀監聽事件**
4.3.4節分析wpa_driver_nl80211_finish_drv_init時曾介紹過,wpa_driver_nl80211_set_mode函數和P2P關系較大。為什么這么說呢?相信代碼能給出最直接的解釋。
**driver_nl80211.c::wpa_driver_nl80211_set_mode**
~~~
static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode)
{
// 注意,在wpa_driver_nl80211_finish_drv_init函數中,nlmode被設置為NL80211_IFTYPE_STATION
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1; int i;
/*
drv->nlmode的類型為enum nl80211_iftype,4.3.4節關于wpa_driver_nl80211_finish_drv_init
的分析中有對該變量的解釋。drv->nlmode只有為NL80211_IFTYPE_AP或NL80211_IFTYPE_P2P_GO時,
is_ap_interface函數才返回非0值。很顯然此時virtual interface的類型不可能是GO。
*/
int was_ap = is_ap_interface(drv->nlmode);
int res;
// 設置虛擬interface的類型為NL80211_IFTYPE_STATION
res = nl80211_set_mode(drv, drv->ifindex, nlmode);
if (res == 0) {
drv->nlmode = nlmode;
ret = 0;
goto done;// 設置成功,直接跳轉到done處
}
......
done:
......
if (is_ap_interface(nlmode)) {
nl80211_mgmt_unsubscribe(bss, "start AP");
if (nl80211_setup_ap(bss)) return -1;
} else if (was_ap) {
nl80211_teardown_ap(bss);
} else {
// 本例將執行下面這個函數以取消監聽Action幀事件
// 由于之前并未注冊,所以此時執行這個函數將沒有實際作用
nl80211_mgmt_unsubscribe(bss, "mode change");
}
if (!is_ap_interface(nlmode) &&
nl80211_mgmt_subscribe_non_ap(bss) < 0)// 注冊對Action幀的監聽事件
wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
"frame processing - ignore for now");
return 0;
}
~~~
nl80211_mgmt_subscribte_non_ap將注冊對Action幀的監聽事件,其作用就是當設備收到Action幀后,Wi-Fi驅動將發送對應的netlink消息給WPAS。來看nl80211_mgmt_subscribte_non_ap函數,代碼如下所示。
**driver_nl80211.c::nl80211_mgmt_subscribte_non_ap**
~~~
static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
/*
下面這個函數將注冊libnl回調事件到event loop。在4.3.4節關于
wpa_driver_nl80211_init_nl與nl80211_init_bss分析中曾詳細介紹過該函數。
總之,當WPAS收到對應的netlink消息后,process_bss_event函數將被調用。
*/
if (nl80211_alloc_mgmt_handle(bss))
return -1;
#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
......// 注冊對GAS Public Action幀的監聽,Service Discovery和它有關
#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
#ifdef CONFIG_P2P
/*
注冊對P2P Public Action幀的監聽,第二個參數中的04-09-50-6F-9A-09指明了P2P Public Action
幀Frame Body的Category、Action Field、OUI、OUI-Type(參考表7-3)的取值。即只有收到的
Frame Body對應字段分別等于上述指定值的Action幀,Wi-Fi驅動才會發送netlink消息給WPAS。
*/
if (nl80211_register_action_frame(bss, (u8 *) "\x04\x09\x50\x6f\x9a\x09",6) < 0)
return -1;
/*
注冊對P2P Action幀的監聽,第二個參數中7F-50-6F-9A-09指明了Action幀Frame Body的
Category和OUI。根據802.11規范,7F代表Vendor Specific,50-6F-9A是WFA的OUI,最后一個
09代表P2P。
*/
if (nl80211_register_action_frame(bss,(u8 *)"\x7f\x50\x6f\x9a\x09",5) < 0)
return -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_IEEE80211W
......
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_TDLS
......
#endif /* CONFIG_TDLS */
......// 其他感興趣幀的注冊
return 0;
}
~~~
由上述代碼可知nl80211_mgmt_subscribe_non_ap在P2P方面注冊了兩種類型的幀監聽事件。
* P2P Public Action幀監聽事件:根據P2P規范,目前使用的均是802.11 Public Action幀,即Category的值為0x04。目前GON、P2P Invitation、Provision Discovery以及Device Discoverability使用P2P Public Action幀。
* P2P Action幀監聽事件:這種類型的幀屬于802.11 Action幀的一種,其Category取值為0x7F,OUI指定為WFA的OUI(即50-6F-9A),而OUI-Type指定為P2P(取值為0x09)。目前Noticeof Absence、P2P Presence、GO Discoverability使用P2P Action幀。
>[info] 注意 上述注冊的Action幀監聽事件對應的處理函數是process_bss_event。
至此,P2P模塊以及Action幀監聽事件注冊等工作都已完成,WPAS馬上可為WifiP2pService提供P2P相關的服務了。下面將結合7.2節中介紹的如下幾個重要的P2P工作流程來分析代碼。
* 搜索周圍的P2P設備。
* 向某個P2P設備發起Provision Discovery流程。
* 對端設備開展Group Formation流程,重點關注其中的Group Negotiation。
>[info] 提示 GON結束后,如果本機設備扮演Client,則后續工作包括Provisioning(即WSC安全配置協商,本機充當Enrollee,參考第6章)和加入Group(類似STA加入AP,參考第4章)。如果本機扮演GO,則后續工作也分為Provisioning(充當Registrar)和處理Client加入Group(扮演AP的角色)。本書不討論和GO相關的知識,請讀者在閱讀完相關章節基礎上自行研究它們。
- 前言
- 第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 參考資料說明
- 附錄