P2P模块初始化
本文為《深入理解Android Wi-Fi、NFC和GPS卷》讀書筆記,Android源碼為Android 5.1
android-5.1/external/wpa_supplicant_8/wpa_supplicant/p2p_supplicant.c
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
{struct p2p_config p2p;//p2p變量指向一個p2p_config對象,代表P2P模塊的配置信息int i;if (wpa_s->conf->p2p_disabled)return 0;//WPA_DRIVER_FLAGS_P2P_CAPABLE代表Wifi驅動對P2P支持的能力if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))return 0;if (global->p2p)return 0;//初始化并設置p2p_config 對象os_memset(&p2p, 0, sizeof(p2p));p2p.cb_ctx = wpa_s;p2p.debug_print = wpas_p2p_debug_print;p2p.p2p_scan = wpas_p2p_scan;p2p.send_action = wpas_send_action;p2p.send_action_done = wpas_send_action_done;p2p.go_neg_completed = wpas_go_neg_completed;p2p.go_neg_req_rx = wpas_go_neg_req_rx;p2p.dev_found = wpas_dev_found;p2p.dev_lost = wpas_dev_lost;p2p.find_stopped = wpas_find_stopped;p2p.start_listen = wpas_start_listen;p2p.stop_listen = wpas_stop_listen;p2p.send_probe_resp = wpas_send_probe_resp;p2p.sd_request = wpas_sd_request;p2p.sd_response = wpas_sd_response;p2p.prov_disc_req = wpas_prov_disc_req;p2p.prov_disc_resp = wpas_prov_disc_resp;p2p.prov_disc_fail = wpas_prov_disc_fail;p2p.invitation_process = wpas_invitation_process;p2p.invitation_received = wpas_invitation_received;p2p.invitation_result = wpas_invitation_result;p2p.get_noa = wpas_get_noa;p2p.go_connected = wpas_go_connected;p2p.presence_resp = wpas_presence_resp;p2p.is_concurrent_session_active = wpas_is_concurrent_session_active;p2p.is_p2p_in_progress = _wpas_p2p_in_progress;//設置P2P Device Addressos_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模塊配置信息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;}//判斷wifi驅動是否支持配置文件中設置的operational channel和listen channelif (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {wpa_printf(MSG_ERROR,"P2P: Failed to configure supported channel list");return -1;}//設置Operational 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;p2p.channel_forced = 1;} else {/** Pick one of the social channels randomly as the listen* channel.*/if (p2p_config_get_random_social(&p2p, &p2p.reg_class,&p2p.channel) != 0) {wpa_printf(MSG_ERROR,"P2P: Failed to select random social channel as listen channel");return -1;}p2p.channel_forced = 0;}wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d:%d",p2p.reg_class, p2p.channel);if (wpa_s->conf->p2p_oper_reg_class &&wpa_s->conf->p2p_oper_channel) {p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class;p2p.op_channel = wpa_s->conf->p2p_oper_channel;p2p.cfg_op_channel = 1;wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: ""%d:%d", p2p.op_reg_class, p2p.op_channel);} else {/** Use random operation channel from 2.4 GHz band social* channels (1, 6, 11) or band 60 GHz social channel (2) if no* other preference is indicated.*/if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,&p2p.op_channel) != 0) {wpa_printf(MSG_ERROR,"P2P: Failed to select random social channel as operation channel");return -1;}p2p.cfg_op_channel = 0;wpa_printf(MSG_DEBUG, "P2P: Random operating channel: ""%d:%d", p2p.op_reg_class, p2p.op_channel);}if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) {p2p.pref_chan = wpa_s->conf->p2p_pref_chan;p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan;}//設置國家碼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);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 operationp2p.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 Note 2為例,其P2P SSID 后綴為Android_4aa9if (wpa_s->conf->p2p_ssid_postfix) {p2p.ssid_postfix_len =os_strlen(wpa_s->conf->p2p_ssid_postfix);if (p2p.ssid_postfix_len > sizeof(p2p.ssid_postfix))p2p.ssid_postfix_len = sizeof(p2p.ssid_postfix);os_memcpy(p2p.ssid_postfix, wpa_s->conf->p2p_ssid_postfix,p2p.ssid_postfix_len);}p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;p2p.max_listen = wpa_s->max_remain_on_chan;if (wpa_s->conf->p2p_passphrase_len >= 8 &&wpa_s->conf->p2p_passphrase_len <= 63)p2p.passphrase_len = wpa_s->conf->p2p_passphrase_len;elsep2p.passphrase_len = 8;//global->p2p指向一個p2p_data結構體,它是WPAS中P2P模塊的代表global->p2p = p2p_init(&p2p);if (global->p2p == NULL)return -1;global->p2p_init_wpa_s = wpa_s;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]);}p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);return 0;
}wpas_p2p_init主要包括:
1.初始化一個p2p_config對象,然后根據 p2p_supplicant.conf文件的信息來設置其中的內容,同時還需要為P2P模塊設置一些回調函數
2.調用p2p_init 函數以初始化 P2P模塊
先看 drv_flags 變量。WPAS中,Wi-Fi驅動對P2P功能的支持情況就是由它來表述的。其表達含義如下:
android-5.1/external/wpa_supplicant_8/src/drivers/driver.h
/* Driver supports AP mode */
//wifi driver支持AP。它使得P2P設備能扮演GO
#define WPA_DRIVER_FLAGS_AP		0x00000040
/* Driver needs static WEP key setup after association has been completed */
//標志標明association成功后,Kernel driver需要設置WEP key
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
/* Driver supports concurrent P2P operations */
#define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200	//wifi driver支持STA和P2P的并發運行
/* This interface is P2P capable (P2P GO or P2P Client) */
//wifi driver支持P2P
#define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
/** Driver uses the initial interface for P2P management interface and non-P2P* purposes (e.g., connect to infra AP), but this interface cannot be used for* P2P group operations.*/
//P2P包含Device Address和Interface Address兩種類型的地址。在實際實現過程中,這兩個地址分別代表兩個Virtual Interface。 顯然,P2P中第一個和一直存在的是擁有Device Address的Virtual Interface。下面這個標志表示該Virtual Interface可以參與P2P管理(除P2P Group Operation之外的工作)工作以及非P2P相關的工作(例如利用這個Virtual Interface加入到一個BSS)。
#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P		0x00002000
/** Driver is known to use sane error codes, i.e., when it indicates that* something (e.g., association) fails, there was indeed a failure and the* operation does not end up getting completed successfully later.*/
//該標志主要針對associate操作。當關聯操作失敗后,如果driver支持該選項,則表明driver能處理失敗之后的各種收尾工作(Key、timeout等工作)。否則,WPAS需要自己處理這些事情
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES		0x00004000
/* Driver supports off-channel TX */
//下面這個標志和off channel機制有關。當802.11 MAC幀通過off channel發送,下面這個標志表示driver會反饋一個發送情況(TX Report)消息給WPAS
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
/* Driver indicates TX status events for Deauth/Disassoc frames */
//下面這標志表示Kernel中的driver是否能反饋Deauthentication/Disassociation幀發送情況(TX Report)
#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000下面看數據結構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對象
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的信息。
android-5.1/external/wpa_supplicant_8/src/p2p/p2p.c
struct p2p_data * p2p_init(const struct p2p_config *cfg)
{struct p2p_data *p2p;if (cfg->max_peers < 1 ||cfg->passphrase_len < 8 || cfg->passphrase_len > 63)return NULL;//從下面這行代碼可看出,一個p2p_data對象的內存分布,該內存將包含一個p2p_data的所有信息以及一個p2p_config對象的所有信息。p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));if (p2p == NULL)return NULL;//將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);if (cfg->manufacturer)p2p->cfg->manufacturer = os_strdup(cfg->manufacturer);if (cfg->model_name)p2p->cfg->model_name = os_strdup(cfg->model_name);if (cfg->model_number)p2p->cfg->model_number = os_strdup(cfg->model_number);if (cfg->serial_number)p2p->cfg->serial_number = os_strdup(cfg->serial_number);if (cfg->pref_chan) {p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan *sizeof(struct p2p_channel));if (p2p->cfg->pref_chan) {os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan,cfg->num_pref_chan *sizeof(struct p2p_channel));} elsep2p->cfg->num_pref_chan = 0;}p2p->min_disc_int = 1;p2p->max_disc_int = 3;p2p->max_disc_tu = -1;//隨機獲取next_tie_breaker的初值//第二個參數1表示next_tie_breaker的字節長度,其類型是u8if (os_get_random(&p2p->next_tie_breaker, 1) < 0)p2p->next_tie_breaker = 0;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);//注冊一個超時時間,用來檢測是否有不活躍的p2p_deviceeloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,p2p_expiration_timeout, p2p, NULL);p2p->go_timeout = 100;p2p->client_timeout = 20;p2p->num_p2p_sd_queries = 0;p2p_dbg(p2p, "initialized");p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);return p2p;
}注冊Action幀監聽事件
android-5.1/external/wpa_supplicant_8/src/drivers/driver_nl80211.c
static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,enum nl80211_iftype nlmode)
{return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
}
static int wpa_driver_nl80211_set_mode_impl(struct i802_bss *bss,enum nl80211_iftype nlmode,struct hostapd_freq_params *desired_freq_params)
{
//注意在函數wpa_driver_nl80211_finish_drv_init中,nlmode被設置為NL80211_IFTYPE_STATIONstruct wpa_driver_nl80211_data *drv = bss->drv;int ret = -1;int i;//drv_nlmode的類型為enum nl80211_iftype。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;int mode_switch_res;//設置虛擬interface 的類型為 NL80211_IFTYPE_STATIONmode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))mode_switch_res = 0;if (mode_switch_res == 0) {drv->nlmode = nlmode;ret = 0;goto done;//設置成功,直接跳轉到done處}if (mode_switch_res == -ENODEV)return -1;if (nlmode == drv->nlmode) {wpa_printf(MSG_DEBUG, "nl80211: Interface already in ""requested mode - ignore error");ret = 0;goto done; /* Already in the requested mode */}/* mac80211 doesn't allow mode changes while the device is up, so* take the device down, try to set the mode again, and bring the* device back up.*/wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting ""interface down");for (i = 0; i < 10; i++) {res = i802_set_iface_flags(bss, 0);if (res == -EACCES || res == -ENODEV)break;if (res != 0) {wpa_printf(MSG_DEBUG, "nl80211: Failed to set ""interface down");os_sleep(0, 100000);continue;}/** Setting the mode will fail for some drivers if the phy is* on a frequency that the mode is disallowed in.*/if (desired_freq_params) {res = i802_set_freq(bss, desired_freq_params);if (res) {wpa_printf(MSG_DEBUG,"nl80211: Failed to set frequency on interface");}}/* Try to set the mode again while the interface is down */mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);if (mode_switch_res == -EBUSY) {wpa_printf(MSG_DEBUG,"nl80211: Delaying mode set while interface going down");os_sleep(0, 100000);continue;}ret = mode_switch_res;break;}if (!ret) {wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while ""interface is down");drv->nlmode = nlmode;drv->ignore_if_down_event = 1;}/* Bring the interface back up */res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);if (res != 0) {wpa_printf(MSG_DEBUG,"nl80211: Failed to set interface up after switching mode");ret = -1;}done:if (ret) {wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d ""from %d failed", nlmode, drv->nlmode);return ret;}if (is_p2p_net_interface(nlmode))nl80211_disable_11b_rates(drv, drv->ifindex, 1);else if (drv->disabled_11b_rates)nl80211_disable_11b_rates(drv, drv->ifindex, 0);if (is_ap_interface(nlmode)) {nl80211_mgmt_unsubscribe(bss, "start AP");/* Setup additional AP mode functionality if needed */if (nl80211_setup_ap(bss))return -1;} else if (was_ap) {/* Remove additional AP mode functionality */nl80211_teardown_ap(bss);} else {//本例將執行下面這個函數以取消監聽Action幀事件//由于之前并未注冊,所以此時執行這個函數將沒有實際作用nl80211_mgmt_unsubscribe(bss, "mode change");}if (!bss->in_deinit && !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_subscribe_non_ap 將注冊對Action幀的監聽事件,其作用就是當設備收到Action幀后,Wi-Fi驅動將發送對應的netlink消息給WPAS。 
 
 
static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
{struct wpa_driver_nl80211_data *drv = bss->drv;int ret = 0;//下面這個函數將注冊libnl回調事件到event loop。當WPAS收到對應的netlink消息后,process_bss_event函數將被調用if (nl80211_alloc_mgmt_handle(bss))return -1;wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP ""handle %p", bss->nl_mgmt);if (drv->nlmode == NL80211_IFTYPE_ADHOC) {u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);/* register for any AUTH message */nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);}#ifdef CONFIG_INTERWORKING/* QoS Map Configure */if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)ret = -1;
#endif /* CONFIG_INTERWORKING */
#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)//注冊對GAS Pubic Action幀的監聽,Service Discovery和它有關/* GAS Initial Request */if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)ret = -1;/* GAS Initial Response */if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)ret = -1;/* GAS Comeback Request */if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)ret = -1;/* GAS Comeback Response */if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)ret = -1;/* Protected GAS Initial Request */if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)ret = -1;/* Protected GAS Initial Response */if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)ret = -1;/* Protected GAS Comeback Request */if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)ret = -1;/* Protected GAS Comeback Response */if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)ret = -1;
#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 的取值,即只有收到的Frame Body對應字段分別等于上述指定值的Action幀,Wi-Fi驅動才會發送netlink消息給WPAS。/* P2P Public Action */if (nl80211_register_action_frame(bss,(u8 *) "\x04\x09\x50\x6f\x9a\x09",6) < 0)ret = -1;/* P2P Action *///注冊對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)ret = -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_IEEE80211W/* SA Query Response */if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)ret = -1;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_TDLSif ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {/* TDLS Discovery Response */if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <0)ret = -1;}
#endif /* CONFIG_TDLS *//* FT Action frames */if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)ret = -1;elsedrv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;/* WNM - BSS Transition Management Request */if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)ret = -1;/* WNM-Sleep Mode Response */if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)ret = -1;#ifdef CONFIG_HS20/* WNM-Notification */if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)ret = -1;
#endif /* CONFIG_HS20 */nl80211_mgmt_handle_register_eloop(bss);return ret;
}由上述代碼可知 nl80211_mgmt_subscribe_non_ap在P2P方面注冊了兩種類型的幀監聽事件。
P2P Pubic 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)。 目前Notice of Absence、P2P Presence、GO Discoverability使用P2P Action幀。
總結
                            
                        - 上一篇: WifiP2pService工作流程
 - 下一篇: P2P Device Discovery