本文为《深入理解Android Wi-Fi、NFC和GPS卷》读书笔记,Android源码为Android 5.1
P2pStateMachine收到P2P_PROV_DISC_PBC_RSP_EVENT消息后,将在ProvisionDiscoveryState中调用p2pConnectWithPinDisplay,该函数内部将发送P2P_CONNECT命令给WPAS。来看该命令的处理流程。
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
android-5.1/external/wpa_supplicant_8/wpa_supplicant/ctrl_iface.c
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, persistent_id = -1;
int join;
int auth;
int automatic;
int go_intent = -1;
int freq = 0;
int pd;
int ht40, vht;
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
* [ht40] [vht] */
if (hwaddr_aton(cmd, addr))
return -1;
pos = cmd + 17;
if (*pos != ' ')
return -1;
pos++;
persistent_group = os_strstr(pos, " persistent") != NULL;
pos2 = os_strstr(pos, " persistent=");
if (pos2) {
struct wpa_ssid *ssid;
persistent_id = atoi(pos2 + 12);
ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
if (ssid == NULL || ssid->disabled != 2 ||
ssid->mode != WPAS_MODE_P2P_GO) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
"SSID id=%d for persistent P2P group (GO)",
persistent_id);
return -1;
}
}
join = os_strstr(pos, " join") != NULL;
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
pos2 += 11;
go_intent = atoi(pos2);
if (go_intent < 0 || go_intent > 15)
return -1;
}
pos2 = os_strstr(pos, " freq=");
if (pos2) {
pos2 += 6;
freq = atoi(pos2);
if (freq <= 0)
return -1;
}
if (os_strncmp(pos, "pin", 3) == 0) {
/* Request random PIN (to be displayed) and enable the PIN */
wps_method = WPS_PIN_DISPLAY;
} else if (os_strncmp(pos, "pbc", 3) == 0) {
wps_method = WPS_PBC;
} else {
pin = pos;
pos = os_strchr(pin, ' ');
wps_method = WPS_PIN_KEYPAD;
if (pos) {
*pos++ = '\0';
if (os_strncmp(pos, "display", 7) == 0)
wps_method = WPS_PIN_DISPLAY;
}
if (!wps_pin_str_valid(pin)) {
os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
return 17;
}
}
//参数处理,最终调用的函数为 wpas_p2p_connect
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, persistent_id, pd,
ht40, vht);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
}
if (new_pin == -3) {
os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
return 25;
}
if (new_pin < 0)
return -1;
if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
ret = os_snprintf(buf, buflen, "%08d", new_pin);
if (ret < 0 || (size_t) ret >= buflen)
return -1;
return ret;
}
os_memcpy(buf, "OK\n", 3);
return 3;
}
android-5.1/external/wpa_supplicant_8/wpa_supplicant/p2p_supplicant.c
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 auto_join, int join, int auth,
int go_intent, int freq, int persistent_id, int pd,
int ht40, int vht)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
enum wpa_driver_if_type iftype;
const u8 *if_addr;
struct wpa_ssid *ssid = NULL;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
if (persistent_id >= 0) {
ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
if (ssid == NULL || ssid->disabled != 2 ||
ssid->mode != WPAS_MODE_P2P_GO)
return -1;
}
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
wpa_s->global->p2p_fail_on_wps_complete = 0;
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
if (!auth)
wpa_s->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
wpa_s->p2p_persistent_group = !!persistent_group;
wpa_s->p2p_persistent_id = persistent_id;
wpa_s->p2p_go_intent = go_intent;
wpa_s->p2p_connect_freq = freq;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->p2p_pd_before_go_neg = !!pd;
wpa_s->p2p_go_ht40 = !!ht40;
wpa_s->p2p_go_vht = !!vht;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
else if (wps_method == WPS_PIN_DISPLAY) {
ret = wps_generate_pin();
os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
ret);
wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
wpa_s->p2p_pin);
} else
wpa_s->p2p_pin[0] = '\0';
if (join || auto_join) {
u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
if (auth) {
wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
"connect a running group from " MACSTR,
MAC2STR(peer_addr));
os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
return ret;
}
os_memcpy(dev_addr, peer_addr, ETH_ALEN);
if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr,
iface_addr) < 0) {
os_memcpy(iface_addr, peer_addr, ETH_ALEN);
p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
dev_addr);
}
if (auto_join) {
os_get_reltime(&wpa_s->p2p_auto_started);
wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
"%ld.%06ld",
wpa_s->p2p_auto_started.sec,
wpa_s->p2p_auto_started.usec);
}
wpa_s->user_initiated_pd = 1;
if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
auto_join, freq, NULL, 0) < 0)
return -1;
return ret;
}
res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
go_intent == 15);
if (res)
return res;
wpas_p2p_set_own_freq_preference(wpa_s,
force_freq ? force_freq : pref_freq);
//注意下面这个 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条件
/* Prepare to add a new interface for the group */
iftype = WPA_IF_P2P_GROUP; //设置Interface type
if (go_intent == 15) //本例 go_intent为7
iftype = WPA_IF_P2P_GO;
//下面这个函数将创建此 Virtual Interface,并获取其Interface Address。
//wpas_p2p_add_group_interface内部将调用 driver_nl80211.c的wpa_driver_nl80211_if_add函数。
if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
"interface for the group");
return -1;
}
if_addr = wpa_s->pending_interface_addr;
} else
if_addr = wpa_s->own_addr;
if (auth) {
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr,
force_freq, persistent_group, ssid,
pref_freq) < 0)
return -1;
return ret;
}
//下面这个函数内部将调用p2p_connect,我们将直接分析。
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr, force_freq,
persistent_group, ssid, pref_freq) < 0) {
if (wpa_s->create_p2p_iface)
wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
}
return ret;
}
android-5.1/external/wpa_supplicant_8/src/p2p/p2p.c
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,
const u8 *force_ssid, size_t force_ssid_len,
int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
{
struct p2p_device *dev;
p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
" wps_method=%d persistent_group=%d pd_before_go_neg=%d "
"oob_pw_id=%u",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
wps_method, persistent_group, pd_before_go_neg, oob_pw_id);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR,
MAC2STR(peer_addr));
return -1;
}
//如果指定了工作频段,则需要判断是否支持该工作频段
if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
go_intent == 15) < 0)
return -1;
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
" that is in a group and is not discoverable",
MAC2STR(peer_addr));
return -1;
}
if (dev->oper_freq <= 0) {
p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
" with incomplete information",
MAC2STR(peer_addr));
return -1;
}
/*
* First, try to connect directly. If the peer does not
* acknowledge frames, assume it is sleeping and use device
* discoverability via the GO at that point.
*/
}
p2p->ssid_set = 0;
if (force_ssid) {
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
force_ssid, force_ssid_len);
os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
p2p->ssid_len = force_ssid_len;
p2p->ssid_set = 1;
}
dev->flags &= ~P2P_DEV_NOT_YET_READY;
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
if (pd_before_go_neg)
dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
else {
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
/*
* Assign dialog token and tie breaker here to use the same
* values in each retry within the same GO Negotiation exchange.
*/
dev->dialog_token++;
if (dev->dialog_token == 0)
dev->dialog_token = 1;
dev->tie_breaker = p2p->next_tie_breaker;
p2p->next_tie_breaker = !p2p->next_tie_breaker;
}
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
p2p_set_dev_persistent(dev, persistent_group);
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);
if (p2p->after_scan_tx) {
/*
* We need to drop the pending frame to avoid issues with the
* new GO Negotiation, e.g., when the pending frame was from a
* previous attempt at starting a GO Negotiation.
*/
p2p_dbg(p2p, "Dropped previous pending Action frame TX that was waiting for p2p_scan completion");
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
}
dev->wps_method = wps_method;
dev->oob_pw_id = oob_pw_id;
dev->status = P2P_SC_SUCCESS;
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan running - delay connect send");
//如果当前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);
}
android-5.1/external/wpa_supplicant_8/src/p2p/p2p_go_neg.c
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
{
struct wpabuf *req;
int freq;
if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
u16 config_method;
p2p_dbg(p2p, "Use PD-before-GO-Neg workaround for " MACSTR,
MAC2STR(dev->info.p2p_device_addr));
if (dev->wps_method == WPS_PIN_DISPLAY)
config_method = WPS_CONFIG_KEYPAD;
else if (dev->wps_method == WPS_PIN_KEYPAD)
config_method = WPS_CONFIG_DISPLAY;
else if (dev->wps_method == WPS_PBC)
config_method = WPS_CONFIG_PUSHBUTTON;
else
return -1;
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
config_method, 0, 0, 1);
}
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
if (dev->oob_go_neg_freq > 0)
freq = dev->oob_go_neg_freq;
if (freq <= 0) {
p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
MACSTR " to send GO Negotiation Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
req = p2p_build_go_neg_req(p2p, dev);
if (req == NULL)
return -1;
p2p_dbg(p2p, "Sending GO Negotiation Request");
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++;
//发送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), 500) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
/* Use P2P find to recover and retry */
p2p_set_timeout(p2p, 0, 0);
} else
dev->go_neg_req_sent++;
wpabuf_free(req);
return 0;
}
GON Response帧处理流程
根据前面对Action帧接收流程的分析可知,收到GON Response帧将在 p2p_process_go_neg_resp 函数中被处理:
android-5.1/external/wpa_supplicant_8/src/p2p/p2p_go_neg.c
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;
int go = -1;
struct p2p_message msg;
u8 status = P2P_SC_SUCCESS;
int freq;
p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR
" (freq=%d)", MAC2STR(sa), rx_freq);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
dev != p2p->go_neg_peer) {
p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
return;
}
//解析GON Response帧
if (p2p_parse(data, len, &msg))
return;
//一系列参数检测
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) {
p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore");
p2p_parse_free(&msg);
return;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
if (msg.dialog_token != dev->dialog_token) {
p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
return;
}
if (!msg.status) {
p2p_dbg(p2p, "No Status attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (*msg.status) {
p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
dev->go_neg_req_sent = 0;
if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
dev->flags |= P2P_DEV_NOT_YET_READY;
os_get_reltime(&dev->go_neg_wait_started);
if (p2p->state == P2P_CONNECT_LISTEN)
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
else
p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
p2p_set_timeout(p2p, 0, 0);
} else {
p2p_dbg(p2p, "Stop GO Negotiation attempt");
p2p_go_neg_failed(p2p, dev, *msg.status);
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_parse_free(&msg);
return;
}
if (!msg.capability) {
p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
#endif /* CONFIG_P2P_STRICT */
}
if (!msg.p2p_device_info) {
p2p_dbg(p2p, "Mandatory P2P Device Info attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
#endif /* CONFIG_P2P_STRICT */
}
if (!msg.intended_addr) {
p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (!msg.go_intent) {
p2p_dbg(p2p, "No GO Intent attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
*msg.go_intent >> 1);
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
//下面这个函数将计算谁来扮演GO。返回值大于0,表示本机扮演GO,返回-1表示双方都想成为GO,返回值为0,表示对端扮演GO。我们假设GO为本机设备。
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
if (go < 0) {
p2p_dbg(p2p, "Incompatible GO Intent");
status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
goto fail;
}
if (!go && msg.group_id) {
/* Store SSID for Provisioning step */
p2p->ssid_len = msg.group_id_len - ETH_ALEN;
os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
} else if (!go) {
p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Response");
p2p->ssid_len = 0;
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (!msg.config_timeout) {
p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
#endif /* CONFIG_P2P_STRICT */
} else {
dev->go_timeout = msg.config_timeout[0];
dev->client_timeout = msg.config_timeout[1];
}
if (!msg.operating_channel && !go) {
/*
* Note: P2P Client may omit Operating Channel attribute to
* indicate it does not have a preference.
*/
p2p_dbg(p2p, "No Operating Channel attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (!msg.channel_list) {
p2p_dbg(p2p, "No Channel List attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (p2p_peer_channels(p2p, dev, msg.channel_list,
msg.channel_list_len) < 0) {
p2p_dbg(p2p, "No common channels found");
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
if (msg.operating_channel) {
dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
msg.operating_channel[4]);
p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
dev->oper_freq);
} else
dev->oper_freq = 0;
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
p2p_dbg(p2p, "PIN from peer Display");
if (dev->wps_method != WPS_PIN_KEYPAD) {
p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_USER_SPECIFIED:
p2p_dbg(p2p, "Peer entered PIN on Keypad");
if (dev->wps_method != WPS_PIN_DISPLAY) {
p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_PUSHBUTTON:
p2p_dbg(p2p, "Peer using pushbutton");
if (dev->wps_method != WPS_PBC) {
p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
default:
if (msg.dev_password_id &&
msg.dev_password_id == dev->oob_pw_id) {
p2p_dbg(p2p, "Peer using NFC");
if (dev->wps_method != WPS_NFC) {
p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
}
p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
goto fail;
p2p_set_state(p2p, P2P_GO_NEG);//设置P2P模块的状态为P2P_GO_NEG
p2p_clear_timeout(p2p);
p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
fail:
/* Store GO Negotiation Confirmation to allow retransmission */
wpabuf_free(dev->go_neg_conf);
//构造GON Confirmation帧
dev->go_neg_conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token,
status, msg.operating_channel,
go);
p2p_parse_free(&msg);
if (dev->go_neg_conf == NULL)
return;
p2p_dbg(p2p, "Sending GO Negotiation Confirm");
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
} else
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (rx_freq > 0)
freq = rx_freq;
else
freq = dev->listen_freq;
dev->go_neg_conf_freq = freq;
dev->go_neg_conf_sent = 0;
//发送GON Confirmation帧
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
wpabuf_head(dev->go_neg_conf),
wpabuf_len(dev->go_neg_conf), 200) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
p2p_go_neg_failed(p2p, dev, -1);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
} else
dev->go_neg_conf_sent++;
if (status != P2P_SC_SUCCESS) {
p2p_dbg(p2p, "GO Negotiation failed");
p2p_go_neg_failed(p2p, dev, status);
}
}
当GON Confirmation帧发送出去后,wifi driver将向WPAS发送一个NL80211_CMD_FRAME_TX_STATUS消息,而该消息将导致driver wrapper发送 EVENT_TX_STATUS 消息给 WPAS。下面来看 EVENT_TX_STATUS 的处理流程。
在event.c中,和P2P以及 EVENT_TX_STATUS相关的处理函数是 offchannel_send_action_tx_status :
android-5.1/external/wpa_supplicant_8/wpa_supplicant/offchannel.c
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)
{
if (wpa_s->pending_action_tx == NULL) {
wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
"no pending operation");
return;
}
if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
"unknown destination address");
return;
}
/* Accept report only if the contents of the frame matches */
if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 ||
os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx),
wpabuf_len(wpa_s->pending_action_tx)) != 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
"mismatching contents with pending frame");
wpa_hexdump(MSG_MSGDUMP, "TX status frame data",
data, data_len);
wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
wpa_s->pending_action_tx);
return;
}
wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
result, wpa_s->pending_action_tx_status_cb);
//注意函数指针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);
}
if (wpa_s->p2p_long_listen > 0) {
/* Continue the listen */
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
}
}
android-5.1/external/wpa_supplicant_8/wpa_supplicant/p2p_supplicant.c
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;
wpas_p2p_action_tx_clear(wpa_s);
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return;
switch (result) {
case OFFCHANNEL_SEND_ACTION_SUCCESS:
res = P2P_SEND_ACTION_SUCCESS;
break;
case OFFCHANNEL_SEND_ACTION_NO_ACK:
res = P2P_SEND_ACTION_NO_ACK;
break;
case OFFCHANNEL_SEND_ACTION_FAILED:
res = P2P_SEND_ACTION_FAILED;
break;
}
p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
wpa_s->pending_pd_before_join &&
(os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
wpa_s->p2p_fallback_to_go_neg) {
wpa_s->pending_pd_before_join = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
"during p2p_connect-auto");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
return;
}
}
android-5.1/external/wpa_supplicant_8/src/p2p/p2p.c
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;
p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
" src=" MACSTR " bssid=" MACSTR " result=%d",
p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
MAC2STR(bssid), result);
success = result == P2P_SEND_ACTION_SUCCESS;
//pending_action_state应该是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:
if (p2p->send_action_in_progress) {
p2p->send_action_in_progress = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
}
if (p2p->after_scan_tx_in_progress) {
p2p->after_scan_tx_in_progress = 0;
if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
p2p_run_after_scan(p2p))
break;
if (p2p->state == P2P_SEARCH) {
p2p_dbg(p2p, "Continue find after after_scan_tx completion");
p2p_continue_find(p2p);
}
}
break;
case P2P_PENDING_GO_NEG_REQUEST:
//当发送完GON Request帧后,此函数也会触发
p2p_go_neg_req_cb(p2p, success);
break;
case P2P_PENDING_GO_NEG_RESPONSE:
p2p_go_neg_resp_cb(p2p, success);
break;
case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
p2p_go_neg_resp_failure_cb(p2p, success, dst);
break;
case P2P_PENDING_GO_NEG_CONFIRM:
p2p_go_neg_conf_cb(p2p, result);
break;
case P2P_PENDING_SD:
p2p_sd_cb(p2p, success);
break;
case P2P_PENDING_PD:
p2p_prov_disc_cb(p2p, success);
break;
case P2P_PENDING_INVITATION_REQUEST:
p2p_invitation_req_cb(p2p, success);
break;
case P2P_PENDING_INVITATION_RESPONSE:
p2p_invitation_resp_cb(p2p, success);
break;
case P2P_PENDING_DEV_DISC_REQUEST:
p2p_dev_disc_req_cb(p2p, success);
break;
case P2P_PENDING_DEV_DISC_RESPONSE:
p2p_dev_disc_resp_cb(p2p, success);
break;
case P2P_PENDING_GO_DISC_REQ:
p2p_go_disc_req_cb(p2p, success);
break;
}
p2p->after_scan_tx_in_progress = 0;
}
android-5.1/external/wpa_supplicant_8/src/p2p/p2p.c
static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
enum p2p_send_action_result result)
{
struct p2p_device *dev;
p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
if (result == P2P_SEND_ACTION_FAILED) {
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
return;
}
dev = p2p->go_neg_peer;
if (result == P2P_SEND_ACTION_NO_ACK) {
/*
* Retry GO Negotiation Confirmation
* P2P_GO_NEG_CNF_MAX_RETRY_COUNT times if we did not receive
* ACK for confirmation.
*/
if (dev && dev->go_neg_conf &&
dev->go_neg_conf_sent <= P2P_GO_NEG_CNF_MAX_RETRY_COUNT) {
p2p_dbg(p2p, "GO Negotiation Confirm retry %d",
dev->go_neg_conf_sent);
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
if (p2p_send_action(p2p, dev->go_neg_conf_freq,
dev->info.p2p_device_addr,
p2p->cfg->dev_addr,
dev->info.p2p_device_addr,
wpabuf_head(dev->go_neg_conf),
wpabuf_len(dev->go_neg_conf), 0) >=
0) {
dev->go_neg_conf_sent++;
return;
}
p2p_dbg(p2p, "Failed to re-send Action frame");
/*
* Continue with the assumption that the first attempt
* went through and just the ACK frame was lost.
*/
}
/*
* It looks like the TX status for GO Negotiation Confirm is
* often showing failure even when the peer has actually
* received the frame. Since the peer may change channels
* immediately after having received the frame, we may not see
* an Ack for retries, so just dropping a single frame may
* trigger this. To allow the group formation to succeed if the
* peer did indeed receive the frame, continue regardless of
* the TX status.
*/
p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
}
//send_action_done真实函数是 wpas_send_action_done
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (dev == NULL)
return;
p2p_go_complete(p2p, dev);
}
android-5.1/external/wpa_supplicant_8/src/p2p/p2p.c
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_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
os_memset(&res, 0, sizeof(res));
res.role_go = go;
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
res.wps_method = peer->wps_method;
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
res.persistent_group = 2;
else
res.persistent_group = 1;
}
if (go) {
/* Setup AP mode for WPS provisioning */
res.freq = p2p_channel_to_freq(p2p->op_reg_class,
p2p->op_channel);
os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
res.ssid_len = p2p->ssid_len;
p2p_random(res.passphrase, p2p->cfg->passphrase_len);
} else {
res.freq = peer->oper_freq;
if (p2p->ssid_len) {
os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
res.ssid_len = p2p->ssid_len;
}
}
p2p_channels_dump(p2p, "own channels", &p2p->channels);
p2p_channels_dump(p2p, "peer channels", &peer->channels);
p2p_channels_intersect(&p2p->channels, &peer->channels,
&intersection);
if (go) {
p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
p2p_channels_dump(p2p, "intersection after no-GO removal",
&intersection);
}
freqs = 0;
for (i = 0; i < intersection.reg_classes; i++) {
struct p2p_reg_class *c = &intersection.reg_class[i];
if (freqs + 1 == P2P_MAX_CHANNELS)
break;
for (j = 0; j < c->channels; j++) {
int freq;
if (freqs + 1 == P2P_MAX_CHANNELS)
break;
freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
if (freq < 0)
continue;
res.freq_list[freqs++] = freq;
}
}
res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
p2p_clear_timeout(p2p);
p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
peer->wps_method = WPS_NOT_READY;
peer->oob_pw_id = 0;
wpabuf_free(peer->go_neg_conf);
peer->go_neg_conf = NULL;
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);
}
android-5.1/external/wpa_supplicant_8/wpa_supplicant/p2p_supplicant.c
static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_drv_cancel_remain_on_channel(wpa_s);
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = 0;
}
if (res->status) {
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_GO_NEG_FAILURE "status=%d",
res->status);
wpas_notify_p2p_go_neg_completed(wpa_s, res);
wpas_p2p_remove_pending_group_interface(wpa_s);
return;
}
if (wpa_s->p2p_go_ht40)
res->ht40 = 1;
if (wpa_s->p2p_go_vht)
res->vht = 1;
//下面这个函数将导致P2pStateMachine受到 P2P_GO_NEGOTIATION_SUCCESS_EVENT消息
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
"freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
" wps_method=%s",
res->role_go ? "GO" : "client", res->freq, res->ht40,
MAC2STR(res->peer_device_addr),
MAC2STR(res->peer_interface_addr),
p2p_wps_method_text(res->wps_method));
wpas_notify_p2p_go_neg_completed(wpa_s, res);
if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
struct wpa_ssid *ssid;
ssid = wpa_config_get_network(wpa_s->conf,
wpa_s->p2p_persistent_id);
if (ssid && ssid->disabled == 2 &&
ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) {
size_t len = os_strlen(ssid->passphrase);
wpa_printf(MSG_DEBUG, "P2P: Override passphrase based "
"on requested persistent group");
os_memcpy(res->passphrase, ssid->passphrase, len);
res->passphrase[len] = '\0';
}
}
if (wpa_s->create_p2p_iface) {
//再创建一个wpa_supplicant对象。其内部将调用 wpa_supplicant_add_iface函数
struct wpa_supplicant *group_wpa_s =
wpas_p2p_init_group_interface(wpa_s, res->role_go);
if (group_wpa_s == NULL) {
wpas_p2p_remove_pending_group_interface(wpa_s);
eloop_cancel_timeout(wpas_p2p_long_listen_timeout,
wpa_s, NULL);
wpas_p2p_group_formation_failed(wpa_s);
return;
}
if (group_wpa_s != wpa_s) {
os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
sizeof(group_wpa_s->p2p_pin));
group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
}
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
wpa_s->pending_interface_name[0] = '\0';
group_wpa_s->p2p_in_provisioning = 1;
//如果本机扮演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);
} else {
wpa_s->p2p_in_provisioning = 1;
wpa_s->global->p2p_group_formation = wpa_s;
if (res->role_go)
wpas_start_wps_go(wpa_s, res, 1);
else
wpas_start_wps_enrollee(ctx, 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,此处有几点请注意:
一个Interface对应一个wpa_supplicant对象
此处新创建的wpa_supplicant对象用于GO,即扮演AP的角色,专门处理和P2P Group相关的事情,其MAC地址为P2P Interface Address。
之前使用的wpa_supplicant用于非P2P Group操作,其MAC地址为P2P Device Address。