Browse Source

P2P: Add automatic GO Negotiation vs. join-a-group selection

p2p_connect command can now be used with an optional "auto" parameter
to request wpa_supplicant to determine automatically whether to use
join-a-group operation (if the peer is operating as a GO) or group
formation. This makes it easier for external programs to handle
connection type selection by offloading this to wpa_supplicant. The
previously used p2p_connect join commands can be replaced with
p2p_connect auto to use this new mechanism.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen 13 years ago
parent
commit
b31be3a0fd

+ 4 - 2
wpa_supplicant/ctrl_iface.c

@@ -2858,6 +2858,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
 	int persistent_group;
 	int join;
 	int auth;
+	int automatic;
 	int go_intent = -1;
 	int freq = 0;
 
@@ -2875,6 +2876,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
 	persistent_group = os_strstr(pos, " persistent") != NULL;
 	join = os_strstr(pos, " join") != NULL;
 	auth = os_strstr(pos, " auth") != NULL;
+	automatic = os_strstr(pos, " auto") != NULL;
 
 	pos2 = os_strstr(pos, " go_intent=");
 	if (pos2) {
@@ -2909,8 +2911,8 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
 	}
 
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
-				   persistent_group, join, auth, go_intent,
-				   freq);
+				   persistent_group, automatic, join,
+				   auth, go_intent, freq);
 	if (new_pin == -2) {
 		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
 		return 25;

+ 1 - 1
wpa_supplicant/dbus/dbus_new_handlers_p2p.c

@@ -508,7 +508,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
 		goto inv_args;
 
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
-				   persistent_group, join, authorize_only,
+				   persistent_group, 0, join, authorize_only,
 				   go_intent, freq);
 
 	if (new_pin >= 0) {

+ 69 - 12
wpa_supplicant/p2p_supplicant.c

@@ -55,7 +55,8 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
 static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
 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);
+			 const u8 *dev_addr, enum p2p_wps_method wps_method,
+			 int auto_join);
 static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
 					    void *timeout_ctx);
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
@@ -1969,7 +1970,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
 				wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
 		} else if (bssid) {
 			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
-				      wpa_s->p2p_wps_method);
+				      wpa_s->p2p_wps_method, 0);
 		}
 		return;
 	}
@@ -2647,6 +2648,31 @@ static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
 }
 
 
+static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
+			    const u8 *peer_dev_addr)
+{
+	struct wpa_bss *bss;
+	int updated;
+
+	bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
+	if (bss == NULL)
+		return 0;
+	if (bss->last_update_idx < wpa_s->bss_update_idx) {
+		wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
+			   "last scan");
+		return 0;
+	}
+
+	updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
+	wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
+		   "%ld.%06ld (%supdated in last scan)",
+		   bss->last_update.sec, bss->last_update.usec,
+		   updated ? "": "not ");
+
+	return updated;
+}
+
+
 static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 				   struct wpa_scan_results *scan_res)
 {
@@ -2659,12 +2685,29 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 	if (wpa_s->global->p2p_disabled)
 		return;
 
-	wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join",
-		   scan_res ? (int) scan_res->num : -1);
+	wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin",
+		   scan_res ? (int) scan_res->num : -1,
+		   wpa_s->p2p_auto_join ? "auto_" : "");
 
 	if (scan_res)
 		wpas_p2p_scan_res_handler(wpa_s, scan_res);
 
+	if (wpa_s->p2p_auto_join) {
+		if (!wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr)) {
+			wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
+				   "running a GO -> use GO Negotiation");
+			wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
+					 wpa_s->p2p_pin, wpa_s->p2p_wps_method,
+					 wpa_s->p2p_persistent_group, 0, 0, 0,
+					 wpa_s->p2p_go_intent,
+					 wpa_s->p2p_connect_freq);
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO -> try "
+			   "to join the group");
+	}
+
 	freq = p2p_get_oper_freq(wpa_s->global->p2p,
 				 wpa_s->pending_join_iface_addr);
 	if (freq < 0 &&
@@ -2836,12 +2879,15 @@ 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)
+			 const u8 *dev_addr, enum p2p_wps_method wps_method,
+			 int auto_join)
 {
 	wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
-		   MACSTR " dev " MACSTR ")",
-		   MAC2STR(iface_addr), MAC2STR(dev_addr));
+		   MACSTR " dev " MACSTR ")%s",
+		   MAC2STR(iface_addr), MAC2STR(dev_addr),
+		   auto_join ? " (auto_join)" : "");
 
+	wpa_s->p2p_auto_join = !!auto_join;
 	os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
 	os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
 	wpa_s->pending_join_wps_method = wps_method;
@@ -2912,6 +2958,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
  * @peer_addr: Address of the peer P2P Device
  * @pin: PIN to use during provisioning or %NULL to indicate PBC mode
  * @persistent_group: Whether to create a persistent group
+ * @auto_join: Whether to select join vs. GO Negotiation automatically
  * @join: Whether to join an existing group (as a client) instead of starting
  *	Group Owner negotiation; @peer_addr is BSSID in that case
  * @auth: Whether to only authorize the connection instead of doing that and
@@ -2924,8 +2971,8 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
  */
 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 join, int auth, int go_intent,
-		     int freq)
+		     int persistent_group, int auto_join, int join, int auth,
+		     int go_intent, int freq)
 {
 	int force_freq = 0, oper_freq = 0;
 	u8 bssid[ETH_ALEN];
@@ -2943,6 +2990,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		wpa_s->p2p_long_listen = 0;
 
 	wpa_s->p2p_wps_method = wps_method;
+	wpa_s->p2p_persistent_group = !!persistent_group;
+	wpa_s->p2p_go_intent = go_intent;
+	wpa_s->p2p_connect_freq = freq;
 
 	if (pin)
 		os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -2955,7 +3005,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 	} else
 		wpa_s->p2p_pin[0] = '\0';
 
-	if (join) {
+	if (join || auto_join) {
 		u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
 		if (auth) {
 			wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
@@ -2971,8 +3021,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 			p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
 					 dev_addr);
 		}
-		if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
-		    0)
+		if (auto_join) {
+			os_get_time(&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);
+		}
+		if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
+				  auto_join) < 0)
 			return -1;
 		return ret;
 	}

+ 2 - 2
wpa_supplicant/p2p_supplicant.h

@@ -19,8 +19,8 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit_global(struct wpa_global *global);
 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 join, int auth, int go_intent,
-		     int freq);
+		     int persistent_group, int auto_join, int join,
+		     int auth, int go_intent, int freq);
 void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 				   unsigned int freq, unsigned int duration);
 void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,

+ 5 - 0
wpa_supplicant/wpa_supplicant_i.h

@@ -508,6 +508,11 @@ struct wpa_supplicant {
 	} removal_reason;
 
 	unsigned int p2p_cb_on_scan_complete:1;
+	unsigned int p2p_auto_join:1;
+	unsigned int p2p_persistent_group:1;
+	int p2p_go_intent;
+	int p2p_connect_freq;
+	struct os_time p2p_auto_started;
 #endif /* CONFIG_P2P */
 
 	struct wpa_ssid *bgscan_ssid;