Browse Source

P2P: Reject multi-channel concurrent operations depending on driver

The driver wrapper can now indicate whether the driver supports
concurrent operations on multiple channels (e.g., infra STA connection
on 5 GHz channel 36 and P2P group on 2.4 GHz channel 1). If not,
P2P_CONNECT commands will be rejected if they would require
multi-channel concurrency.

The new failure codes for P2P_CONNECT:

FAIL-CHANNEL-UNAVAILABLE:
The requested/needed channel is not currently available (i.e., user has
an option of disconnecting another interface to make the channel
available).

FAIL-CHANNEL-UNSUPPORTED:
The request channel is not available for P2P.
Jouni Malinen 14 years ago
parent
commit
d054a4622c
5 changed files with 74 additions and 12 deletions
  1. 2 0
      src/drivers/driver.h
  2. 8 0
      src/p2p/p2p.h
  3. 11 0
      src/p2p/p2p_utils.c
  4. 8 0
      wpa_supplicant/ctrl_iface.c
  5. 45 12
      wpa_supplicant/p2p_supplicant.c

+ 2 - 0
src/drivers/driver.h

@@ -542,6 +542,8 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
 /* This interface is P2P capable (P2P Device, GO, or P2P Client */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
+/* Driver supports concurrent operations on multiple channels */
+#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT	0x00001000
 	unsigned int flags;
 
 	int max_scan_ssids;

+ 8 - 0
src/p2p/p2p.h

@@ -1255,4 +1255,12 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
  */
 void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
 
+/**
+ * p2p_supported_freq - Check whether channel is supported for P2P
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
+
 #endif /* P2P_H */

+ 11 - 0
src/p2p/p2p_utils.c

@@ -258,3 +258,14 @@ int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
 	}
 	return 0;
 }
+
+
+int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
+{
+	u8 op_reg_class, op_channel;
+	if (p2p_freq_to_channel(p2p->cfg->country, freq,
+				&op_reg_class, &op_channel) < 0)
+		return 0;
+	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+				     op_channel);
+}

+ 8 - 0
wpa_supplicant/ctrl_iface.c

@@ -1975,6 +1975,14 @@ 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);
+	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) {

+ 45 - 12
wpa_supplicant/p2p_supplicant.c

@@ -2532,14 +2532,16 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
  *	initiating Group Owner negotiation
  * @go_intent: GO Intent or -1 to use default
  * @freq: Frequency for the group or 0 for auto-selection
- * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on failure
+ * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
+ *	failure, -2 on failure due to channel not currently available,
+ *	-3 if forced channel is not supported
  */
 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 force_freq = 0;
+	int force_freq = 0, oper_freq = 0;
 	u8 bssid[ETH_ALEN];
 	int ret = 0;
 	enum wpa_driver_if_type iftype;
@@ -2585,21 +2587,52 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		return ret;
 	}
 
-	if (freq > 0)
-		force_freq = freq;
-	else if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-		 wpa_s->assoc_freq)
-		force_freq = wpa_s->assoc_freq;
+	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+	    wpa_s->assoc_freq)
+		oper_freq = wpa_s->assoc_freq;
 	else {
-		force_freq = wpa_drv_shared_freq(wpa_s);
-		if (force_freq < 0)
-			force_freq = 0;
+		oper_freq = wpa_drv_shared_freq(wpa_s);
+		if (oper_freq < 0)
+			oper_freq = 0;
 	}
 
-	if (force_freq > 0) {
+	if (freq > 0) {
+		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+				   "(%u MHz) is not supported for P2P uses",
+				   freq);
+			return -3;
+		}
+
+		if (oper_freq > 0 && freq != oper_freq &&
+		    !(wpa_s->drv_flags &
+		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+				   "on %u MHz while connected on another "
+				   "channel (%u MHz)", freq, oper_freq);
+			return -2;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+			   "requested channel (%u MHz)", freq);
+		force_freq = freq;
+	} else if (oper_freq > 0 &&
+		   !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
+		if (!(wpa_s->drv_flags &
+		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+				   "while connected on non-P2P supported "
+				   "channel (%u MHz)", oper_freq);
+			return -2;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+			   "(%u MHz) not available for P2P - try to use "
+			   "another channel", oper_freq);
+		force_freq = 0;
+	} else if (oper_freq > 0) {
 		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
 			   "channel we are already using (%u MHz) on another "
-			   "interface", force_freq);
+			   "interface", oper_freq);
+		force_freq = oper_freq;
 	}
 
 	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);