Browse Source

P2P NFC: Optimize join-a-group operation based on NFC information

When the NFC connection handover message received from a peer indicates
that the peer is operating as a GO on a specific channel, use that
information to avoid having to go through full scan. In addition, skip
the separate join-a-group scan since we already know the operating
channel, GO P2P Device Address, and SSID.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen 11 years ago
parent
commit
23318bea94

+ 15 - 5
src/p2p/p2p.c

@@ -4493,12 +4493,17 @@ int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
 	if (freq < 0) {
 		p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
 		return -1;
-	} else {
-		p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq);
-		dev->oob_go_neg_freq = freq;
 	}
+	role = msg.oob_go_neg_channel[5];
 
-	if (!params->sel) {
+	if (role == P2P_GO_IN_A_GROUP) {
+		p2p_dbg(p2p, "Peer OOB GO operating channel: %u MHz", freq);
+		params->go_freq = freq;
+	} else
+		p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq);
+	dev->oob_go_neg_freq = freq;
+
+	if (!params->sel && role != P2P_GO_IN_A_GROUP) {
 		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 		if (freq < 0) {
@@ -4509,7 +4514,12 @@ int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
 		dev->oob_go_neg_freq = freq;
 	}
 
-	role = msg.oob_go_neg_channel[5];
+	if (msg.group_id) {
+		os_memcpy(params->go_dev_addr, msg.group_id, ETH_ALEN);
+		params->go_ssid_len = msg.group_id_len - ETH_ALEN;
+		os_memcpy(params->go_ssid, msg.group_id + ETH_ALEN,
+			  params->go_ssid_len);
+	}
 
 	p2p_parse_free(&msg);
 

+ 4 - 0
src/p2p/p2p.h

@@ -1919,6 +1919,10 @@ struct p2p_nfc_params {
 	u8 oob_dev_pw[WPS_OOB_PUBKEY_HASH_LEN + 2 +
 		      WPS_OOB_DEVICE_PASSWORD_LEN];
 	size_t oob_dev_pw_len;
+	int go_freq;
+	u8 go_dev_addr[ETH_ALEN];
+	u8 go_ssid[32];
+	size_t go_ssid_len;
 };
 
 int p2p_process_nfc_connection_handover(struct p2p_data *p2p,

+ 2 - 1
wpa_supplicant/ctrl_iface.c

@@ -813,7 +813,8 @@ static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
 	else if (hwaddr_aton(cmd, bssid))
 		return -1;
 
-	return wpas_wps_start_nfc(wpa_s, _bssid, NULL, 0, 0, NULL, NULL, 0);
+	return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
+				  0);
 }
 
 

+ 57 - 25
wpa_supplicant/p2p_supplicant.c

@@ -103,13 +103,15 @@ static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
 static struct wpa_supplicant *
 wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
 			 int go);
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+			       const u8 *ssid, size_t ssid_len);
 static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
 				   const u8 *ssid, size_t ssid_len);
 static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
 			 const u8 *dev_addr, enum p2p_wps_method wps_method,
-			 int auto_join, const u8 *ssid, size_t ssid_len);
+			 int auto_join, int freq,
+			 const u8 *ssid, size_t ssid_len);
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -580,6 +582,10 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
 		bssid = wpa_s->bssid;
 
 	bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
+	if (bss == NULL && wpa_s->go_params &&
+	    !is_zero_ether_addr(wpa_s->go_params->peer_device_addr))
+		bss = wpa_bss_get_p2p_dev_addr(
+			wpa_s, wpa_s->go_params->peer_device_addr);
 	if (bss == NULL) {
 		u8 iface_addr[ETH_ALEN];
 		if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
@@ -1101,8 +1107,10 @@ static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
 static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
 				    struct p2p_go_neg_results *res)
 {
-	wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
-		   MAC2STR(res->peer_interface_addr));
+	wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR
+		   " dev_addr " MACSTR,
+		   MAC2STR(res->peer_interface_addr),
+		   MAC2STR(res->peer_device_addr));
 	wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
 			  res->ssid, res->ssid_len);
 	wpa_supplicant_ap_deinit(wpa_s);
@@ -1111,7 +1119,8 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
 		wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
 #ifdef CONFIG_WPS_NFC
 	} else if (res->wps_method == WPS_NFC) {
-		wpas_wps_start_nfc(wpa_s, res->peer_interface_addr,
+		wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
+				   res->peer_interface_addr,
 				   wpa_s->parent->p2p_oob_dev_pw,
 				   wpa_s->parent->p2p_oob_dev_pw_id, 1,
 				   wpa_s->parent->p2p_oob_dev_pw_id ==
@@ -2821,7 +2830,7 @@ static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
 		wpa_s->pending_pd_before_join = 0;
 		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
 			   "join-existing-group operation");
-		wpas_p2p_join_start(wpa_s);
+		wpas_p2p_join_start(wpa_s, 0, NULL, 0);
 		return;
 	}
 
@@ -2865,7 +2874,7 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
 		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
 			   "join-existing-group operation (no ACK for PD "
 			   "Req attempts)");
-		wpas_p2p_join_start(wpa_s);
+		wpas_p2p_join_start(wpa_s, 0, NULL, 0);
 		return;
 	}
 
@@ -3034,7 +3043,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
-				      wpa_s->p2p_wps_method, 0,
+				      wpa_s->p2p_wps_method, 0, op_freq,
 				      ssid, ssid_len);
 		}
 		return;
@@ -4283,7 +4292,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 
 start:
 	/* Start join operation immediately */
-	wpas_p2p_join_start(wpa_s);
+	wpas_p2p_join_start(wpa_s, 0, NULL, 0);
 }
 
 
@@ -4384,11 +4393,12 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
 
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
 			 const u8 *dev_addr, enum p2p_wps_method wps_method,
-			 int auto_join, const u8 *ssid, size_t ssid_len)
+			 int auto_join, int op_freq,
+			 const u8 *ssid, size_t ssid_len)
 {
 	wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
-		   MACSTR " dev " MACSTR ")%s",
-		   MAC2STR(iface_addr), MAC2STR(dev_addr),
+		   MACSTR " dev " MACSTR " op_freq=%d)%s",
+		   MAC2STR(iface_addr), MAC2STR(dev_addr), op_freq,
 		   auto_join ? " (auto_join)" : "");
 	if (ssid && ssid_len) {
 		wpa_printf(MSG_DEBUG, "P2P: Group SSID specified: %s",
@@ -4405,12 +4415,13 @@ static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
 	wpas_p2p_stop_find(wpa_s);
 
 	wpa_s->p2p_join_scan_count = 0;
-	wpas_p2p_join_scan_req(wpa_s, 0, ssid, ssid_len);
+	wpas_p2p_join_scan_req(wpa_s, op_freq, ssid, ssid_len);
 	return 0;
 }
 
 
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+			       const u8 *ssid, size_t ssid_len)
 {
 	struct wpa_supplicant *group;
 	struct p2p_go_neg_results res;
@@ -4438,17 +4449,25 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
 	group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
 
 	os_memset(&res, 0, sizeof(res));
+	os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN);
 	os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
 		  ETH_ALEN);
 	res.wps_method = wpa_s->pending_join_wps_method;
-	bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
-	if (bss) {
-		res.freq = bss->freq;
-		res.ssid_len = bss->ssid_len;
-		os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
-		wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency "
-			   "from BSS table: %d MHz (SSID %s)", bss->freq,
-			   wpa_ssid_txt(bss->ssid, bss->ssid_len));
+	if (freq && ssid && ssid_len) {
+		res.freq = freq;
+		res.ssid_len = ssid_len;
+		os_memcpy(res.ssid, ssid, ssid_len);
+	} else {
+		bss = wpa_bss_get_bssid_latest(wpa_s,
+					       wpa_s->pending_join_iface_addr);
+		if (bss) {
+			res.freq = bss->freq;
+			res.ssid_len = bss->ssid_len;
+			os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+			wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)",
+				   bss->freq,
+				   wpa_ssid_txt(bss->ssid, bss->ssid_len));
+		}
 	}
 
 	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
@@ -4660,7 +4679,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		}
 		wpa_s->user_initiated_pd = 1;
 		if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
-				  auto_join, NULL, 0) < 0)
+				  auto_join, freq, NULL, 0) < 0)
 			return -1;
 		return ret;
 	}
@@ -7100,10 +7119,23 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
 				   struct p2p_nfc_params *params)
 {
 	wpa_printf(MSG_DEBUG, "P2P: Initiate join-group based on NFC "
-		   "connection handover");
+		   "connection handover (freq=%d)",
+		   params->go_freq);
+
+	if (params->go_freq && params->go_ssid_len) {
+		wpa_s->p2p_wps_method = WPS_NFC;
+		wpa_s->pending_join_wps_method = WPS_NFC;
+		os_memset(wpa_s->pending_join_iface_addr, 0, ETH_ALEN);
+		os_memcpy(wpa_s->pending_join_dev_addr, params->go_dev_addr,
+			  ETH_ALEN);
+		return wpas_p2p_join_start(wpa_s, params->go_freq,
+					   params->go_ssid,
+					   params->go_ssid_len);
+	}
+
 	return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
 				WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
-				0, -1, 0, 1, 1);
+				params->go_freq, -1, 0, 1, 1);
 }
 
 

+ 21 - 10
wpa_supplicant/wps_supplicant.c

@@ -911,7 +911,8 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
 
 
 static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
-					      int registrar, const u8 *bssid)
+					      int registrar, const u8 *dev_addr,
+					      const u8 *bssid)
 {
 	struct wpa_ssid *ssid;
 
@@ -931,6 +932,11 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
 		return NULL;
 	}
 
+#ifdef CONFIG_P2P
+	if (dev_addr)
+		os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN);
+#endif /* CONFIG_P2P */
+
 	if (bssid) {
 #ifndef CONFIG_P2P
 		struct wpa_bss *bss;
@@ -1044,7 +1050,7 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 {
 	struct wpa_ssid *ssid;
 	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+	ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
 	if (ssid == NULL)
 		return -1;
 	ssid->temporary = 1;
@@ -1072,7 +1078,8 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
-static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, const u8 *bssid,
+static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
+				 const u8 *dev_addr, const u8 *bssid,
 				 const char *pin, int p2p_group, u16 dev_pw_id,
 				 const u8 *peer_pubkey_hash,
 				 const u8 *ssid_val, size_t ssid_len)
@@ -1083,7 +1090,9 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, const u8 *bssid,
 	char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
 
 	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+	if (bssid && is_zero_ether_addr(bssid))
+		bssid = NULL;
+	ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid);
 	if (ssid == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: Could not add network");
 		return -1;
@@ -1145,8 +1154,8 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, const u8 *bssid,
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		       const char *pin, int p2p_group, u16 dev_pw_id)
 {
-	return wpas_wps_start_dev_pw(wpa_s, bssid, pin, p2p_group, dev_pw_id,
-				     NULL, NULL, 0);
+	return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
+				     dev_pw_id, NULL, NULL, 0);
 }
 
 
@@ -1196,7 +1205,7 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
 	if (!pin)
 		return -1;
 	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 1, bssid);
+	ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid);
 	if (ssid == NULL)
 		return -1;
 	ssid->temporary = 1;
@@ -2118,7 +2127,8 @@ struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
 }
 
 
-int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr,
+		       const u8 *bssid,
 		       const struct wpabuf *dev_pw, u16 dev_pw_id,
 		       int p2p_group, const u8 *peer_pubkey_hash,
 		       const u8 *ssid, size_t ssid_len)
@@ -2173,7 +2183,8 @@ int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 					   wpabuf_head(dev_pw),
 					   wpabuf_len(dev_pw));
 	}
-	return wpas_wps_start_dev_pw(wpa_s, bssid, dev_pw ? pw : NULL,
+	return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid,
+				     dev_pw ? pw : NULL,
 				     p2p_group, dev_pw_id, peer_pubkey_hash,
 				     ssid, ssid_len);
 }
@@ -2484,7 +2495,7 @@ int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
 	wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash",
 		    attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
 
-	ret = wpas_wps_start_nfc(wpa_s, NULL, NULL, dev_pw_id, 0,
+	ret = wpas_wps_start_nfc(wpa_s, NULL, NULL, NULL, dev_pw_id, 0,
 				 attr.oob_dev_password,
 				 attr.ssid, attr.ssid_len);
 

+ 2 - 1
wpa_supplicant/wps_supplicant.h

@@ -64,7 +64,8 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
 struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
 					  int ndef, const char *id_str);
 struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
-int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+		       const u8 *bssid,
 		       const struct wpabuf *dev_pw, u16 dev_pw_id,
 		       int p2p_group, const u8 *peer_pubkey_hash,
 		       const u8 *ssid, size_t ssid_len);