本文为《深入理解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_connectnew_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);} elsewpa_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 typeif (go_intent == 15)        //本例 go_intent为7iftype = 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;} elseif_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;elsereturn -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_REQUESTp2p->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);} elsedev->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);elsep2p_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_STRICTstatus = 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_STRICTstatus = 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_STRICTstatus = 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);} elsedev->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_NEGp2p_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;} elsep2p->pending_action_state = P2P_NO_PENDING_ACTION;if (rx_freq > 0)freq = rx_freq;elsefreq = 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);} elsedev->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_resultresult)
{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_CONFIRMstate = 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_donep2p->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;elseres.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_completedp2p->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);elsewpas_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);elsewpas_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。

GO Negotiation流程分析相关推荐

  1. 【转载】csr8670--sink工程的大致工作流程分析(以speaker为例)二

    csr8670--sink工程的大致工作流程分析(以speaker为例)二 1.编解码任务的初始化 继续接着流程一分析: 1.1 当连接初始化完成之后,如下所示会调用编解码的初始化任务:这个编解码的任 ...

  2. Android -- Wifi启动流程分析

    Android -- Wifi启动流程分析 Android网络各个模式中,Wifi应该是目前最常用的一种网络方式了:下面就简单介绍下Android中Wifi的启动流程. 当我在Setting菜单里点击 ...

  3. VLC架构及流程分析

    0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...

  4. 动态执行流程分析和性能瓶颈分析的利器——gperftools的Cpu Profiler

    在<动态执行流程分析和性能瓶颈分析的利器--valgrind的callgrind>中,我们领略了valgrind对流程和性能瓶颈分析的强大能力.本文将介绍拥有相似能力的gperftools ...

  5. 动态执行流程分析和性能瓶颈分析的利器——valgrind的callgrind

    在<内存.性能问题分析的利器--valgrind>一文中我们简单介绍了下valgrind工具集,本文将使用callgrind工具进行动态执行流程分析和性能瓶颈分析.(转载请指明出于brea ...

  6. 解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  7. Java多线程- 线程池的基本使用和执行流程分析 - ThreadPoolExecutor

    线程池的实现原理 池化技术 一说到线程池自然就会想到池化技术. 其实所谓池化技术,就是把一些能够复用的东西放到池中,避免重复创建.销毁的开销,从而极大提高性能. 常见池化技术的例如: 线程池 内存池 ...

  8. Android 7.0 WifiMonitor工作流程分析

    2019独角兽企业重金招聘Python工程师标准>>> 在wifi启动扫描的分析过程中,出现了多次WifiMonitor的操作,在此分析一下这个函数是如何工作的. 在Android的 ...

  9. 转:Android之 MTP框架和流程分析

    2019独角兽企业重金招聘Python工程师标准>>> 转载:http://www.cnblogs.com/skywang12345/p/3474206.html 概要 本文的目的是 ...

最新文章

  1. Spring学习-理解IOC和依赖注入
  2. Work with Alexa :Echo匹配连接到Alexa
  3. Spring Boot并不重复“造轮子”
  4. python【力扣LeetCode算法题库】面试题 01.06-字符串压缩
  5. 5页面如何切图_如何让你的设计稿做到95%还原?
  6. KVM虚拟机获取所有IP(shell)
  7. python求高阶导数_TensorFlow:计算Hessian矩阵(和高阶导数)
  8. linux下搭建博客day3-git安装
  9. HR别掉坑里了,送你最精确的计薪算法!
  10. 2022超级好看动态视频官网HTML源码
  11. 渗透工具-masscan
  12. 第三方登陆--狸菇凉_
  13. 红帽子linux转中文后乱码,安装redhat时中文显示乱码(小方框)解决方法
  14. 高斯投影正反算C语言程序代码,高斯投影正反算c代码
  15. 更改计算机网络,终于理会如何更改计算机网络ip
  16. 昆石VOS3000/VOS2009 Web手机管理说明
  17. 一文读懂 NMEA-0183 协议数据
  18. HDU5015 233 Matrix
  19. 时尚穿越html5游戏,时尚穿越之旅
  20. 3.2 回溯法—N皇后问题

热门文章

  1. python 怎样使list 里面的数据相加
  2. RPC(远程过程调用协议)介绍
  3. [转]几种最短路径算法的比较
  4. C# window服务操作
  5. 【WinForm】“System.Data.SqlClient.SqlConnection”的类型初始值设定项引发异常
  6. ERROR 1366 (HY000): Incorrect string value: '\xD5\xC5\xC8\xFD' for column 'name' at row 1
  7. Test on 11/10/2016
  8. MPC8313ERDB不新鲜pkg包裹,把文件放进Ramdisk
  9. 消除 activity 启动时白屏、黑屏问题
  10. sql查询返回xml数据之应用【转载】