GO Negotiation流程分析
生活随笔
收集整理的這篇文章主要介紹了
GO Negotiation流程分析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文為《深入理解Android Wi-Fi、NFC和GPS卷》讀書筆記,Android源碼為Android 5.1
P2pStateMachine收到P2P_PROV_DISC_PBC_RSP_EVENT消息后,將在ProvisionDiscoveryState中調(diào)用p2pConnectWithPinDisplay,該函數(shù)內(nèi)部將發(fā)送P2P_CONNECT命令給WPAS。來看該命令的處理流程。
P2P_CONNECT 處理流程
P2P_CONNECT命令的參數(shù)比較多,而本例中P2pStateMachine發(fā)送的命令格式如下。
P2P_CONNECT 8a:32:9b:6c:d1:80 pbc go_intent=7
其中 8a:32:9b:6c:d1:80 代表對端P2P設(shè)備地址
pbc指定了WSC配置方法為PBC, go_intent=7 設(shè)置GO Intent值為7
P2P_CONNECT對應(yīng)的處理函數(shù)為 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;}}//參數(shù)處理,最終調(diào)用的函數(shù)為 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);//注意下面這個(gè) wpas_p2p_create_iface函數(shù),它將判斷是否需要?jiǎng)?chuàng)建一個(gè)新的 virtual interface,7.4.1介紹Driver Flags和重要數(shù)據(jù)結(jié)構(gòu)時(shí)提到 WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P標(biāo)志,就本例而言,wifi driver flags 中包含了該標(biāo)志, 所以下面這個(gè)函數(shù)的返回值為1, 表示需要單獨(dú)創(chuàng)建一個(gè)新的Virtual Interface供P2P使用。這個(gè)Virtual Interface的地址應(yīng)該就是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; //設(shè)置Interface typeif (go_intent == 15) //本例 go_intent為7iftype = WPA_IF_P2P_GO;//下面這個(gè)函數(shù)將創(chuàng)建此 Virtual Interface,并獲取其Interface Address。//wpas_p2p_add_group_interface內(nèi)部將調(diào)用 driver_nl80211.c的wpa_driver_nl80211_if_add函數(shù)。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;}//下面這個(gè)函數(shù)內(nèi)部將調(diào)用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模塊的狀態(tài)不為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");//如果當(dāng)前P2P還在掃描過程中,則設(shè)置 start_after_scan 為 P2P_AFTER_SCAN_CONNECT 標(biāo)志,當(dāng)scan結(jié)束后,在掃描結(jié)果處理流程中,該標(biāo)志將通知P2P進(jìn)入 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;//發(fā)送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); //設(shè)置P2P模塊的狀態(tài)為 P2P_CONNECT//設(shè)置pending_action_state為P2P_PENDING_GO_NEG_REQUESTp2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;p2p->go_neg_peer = dev; //設(shè)置GON對端設(shè)備dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;dev->connect_reqs++;//發(fā)送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幀處理流程
根據(jù)前面對Action幀接收流程的分析可知,收到GON Response幀將在 p2p_process_go_neg_resp 函數(shù)中被處理:
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;//一系列參數(shù)檢測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;}//下面這個(gè)函數(shù)將計(jì)算誰來扮演GO。返回值大于0,表示本機(jī)扮演GO,返回-1表示雙方都想成為GO,返回值為0,表示對端扮演GO。我們假設(shè)GO為本機(jī)設(shè)備。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);//設(shè)置P2P模塊的狀態(tài)為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);//構(gòu)造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;//發(fā)送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);}
}當(dāng)GON Confirmation幀發(fā)送出去后,wifi driver將向WPAS發(fā)送一個(gè)NL80211_CMD_FRAME_TX_STATUS消息,而該消息將導(dǎo)致driver wrapper發(fā)送 EVENT_TX_STATUS 消息給 WPAS。下面來看 EVENT_TX_STATUS 的處理流程。
在event.c中,和P2P以及 EVENT_TX_STATUS相關(guān)的處理函數(shù)是 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);//注意函數(shù)指針pending_action_tx_status_cb,P2P每次發(fā)送Action的時(shí)候都會(huì)設(shè)置該變量。其真實(shí)函數(shù)為 wpas_p2p_send_action_tx_status(在 wpas_send_action 函數(shù)中設(shè)置)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應(yīng)該是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://當(dāng)發(fā)送完GON Request幀后,此函數(shù)也會(huì)觸發(fā)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真實(shí)函數(shù)是 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);//進(jìn)入Group Formation的Provisioning階段//go_neg_completed 對應(yīng)的函數(shù)是 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;//下面這個(gè)函數(shù)將導(dǎo)致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) {//再創(chuàng)建一個(gè)wpa_supplicant對象。其內(nèi)部將調(diào)用 wpa_supplicant_add_iface函數(shù)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;//如果本機(jī)扮演GO,則啟動(dòng)WSC Registrar功能,否則啟動(dòng)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的超時(shí)時(shí)間為15秒左右eloop_register_timeout(15 + res->peer_config_timeout / 100,(res->peer_config_timeout % 100) * 10000,wpas_p2p_group_formation_timeout, wpa_s, NULL);
}當(dāng)Group Negotiation完成后,WPAS將新創(chuàng)建一個(gè)wpa_supplicant對象,它將用于管理和操作專門用于P2P Group的Virtual Interface,此處有幾點(diǎn)請注意:
一個(gè)Interface對應(yīng)一個(gè)wpa_supplicant對象
此處新創(chuàng)建的wpa_supplicant對象用于GO,即扮演AP的角色,專門處理和P2P Group相關(guān)的事情,其MAC地址為P2P Interface Address。
之前使用的wpa_supplicant用于非P2P Group操作,其MAC地址為P2P Device Address。
總結(jié)
以上是生活随笔為你收集整理的GO Negotiation流程分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Provision Discovery流
- 下一篇: NetworkManagementSer