本文为《深入理解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 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模块配置信息
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 channel
if (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 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 Note 2为例,其P2P SSID 后缀为Android_4aa9
if (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;
else
p2p.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主要包括:
/* 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
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));
} else
p2p->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的字节长度,其类型是u8
if (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_device
eloop_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帧监听事件
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_STATION
struct 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_STATION
mode_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_TDLS
if ((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;
else
drv->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方面注册了两种类型的帧监听事件。