[PATCH 11/17] P2P: Allow additional operating channels for P2P GO and client

Ilan Peer ilan.peer
Mon Jul 27 12:24:28 PDT 2015


Enable using additional frequencies for P2P GO and P2P Client.

1. Allow using indoor channels iff allowed.
2. If indoor channels are not allowed, do not allow them even for
   P2P client usage.
3. Allow using a channel for P2P GO iff there is an additional station
   interface associated on that channel.
4. On relevant wpa_supplicant interface state change, update the P2P
   device with the new allowed frequency configuration.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/hw_features.c            |  11 ++-
 wpa_supplicant/p2p_supplicant.c | 175 +++++++++++++++++++++++++++++++++-------
 wpa_supplicant/p2p_supplicant.h |   1 +
 3 files changed, 154 insertions(+), 33 deletions(-)

diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 7cb7e88..8b8787f 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -118,11 +118,16 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
 			} else if (((feature->channels[j].flag &
 				     HOSTAPD_CHAN_RADAR) &&
 				    !(iface->drv_flags &
-				      WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
-				   (feature->channels[j].flag &
-				    HOSTAPD_CHAN_NO_IR)) {
+				      WPA_DRIVER_FLAGS_DFS_OFFLOAD))) {
 				feature->channels[j].flag |=
 					HOSTAPD_CHAN_DISABLED;
+			} else if ((feature->channels[j].flag &
+				    HOSTAPD_CHAN_NO_IR) &&
+				   !(feature->channels[j].flag &
+				     (HOSTAPD_CHAN_INDOOR_ONLY |
+				      HOSTAPD_CHAN_GO_CONCURRENT))) {
+					feature->channels[j].flag |=
+						HOSTAPD_CHAN_DISABLED;
 			}
 
 			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index b52580a..af5b916 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3157,34 +3157,97 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
 
 
 enum chan_allowed {
-	NOT_ALLOWED, NO_IR, ALLOWED
+	NOT_ALLOWED, NO_IR, INDOOR_ONLY, ALLOWED
 };
 
+static int wpas_p2p_get_unii(int freq)
+{
+	/* UNII-1 */
+	if (freq >= 5150 && freq <= 5250)
+		return 0;
+
+	/* UNII-2A */
+	if (freq > 5250 && freq <= 5350)
+		return 1;
+
+	/* UNII-2B */
+	if (freq > 5350 && freq <= 5470)
+		return 2;
+
+	/* UNII-2C */
+	if (freq > 5470 && freq <= 5725)
+		return 3;
+
+	/* UNII-3 */
+	if (freq > 5725 && freq <= 5825)
+		return 4;
+
+	return -1;
+}
+
+
+static unsigned int wpas_p2p_same_unii(int freq1, int freq2)
+{
+	int r1 = wpas_p2p_get_unii(freq1);
+	int r2 = wpas_p2p_get_unii(freq2);
+
+	return (r1 != -1 && r1 == r2) ? 1 : 0;
+}
+
+
 static int has_channel(struct wpa_global *global,
-		       struct hostapd_hw_modes *mode, u8 chan, int *flags)
+		       struct hostapd_hw_modes *mode,
+		       u8 chan, int *flags,
+		       struct wpa_used_freq_data *freqs,
+		       unsigned int num)
 {
-	int i;
-	unsigned int freq;
+	int i, freq;
+	unsigned int j, is_shared_freq;
 
 	freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
 		chan * 5;
 	if (wpas_p2p_disallowed_freq(global, freq))
 		return NOT_ALLOWED;
 
+	/* Consider a frequency as usable for the GO_CONCURRENT relaxation iff
+	 * the frequency is used by a BSS in 2.4 or is in the same UNII band as
+	 * as a freq used by the BSS
+	 */
+	for (j = 0, is_shared_freq = 0; freqs && j < num; j++) {
+		if ((freqs[j].freq == freq ||
+		     wpas_p2p_same_unii(freqs[j].freq, freq)) &&
+		    freqs[j].flags & WPA_FREQ_USED_BY_INFRA_STATION) {
+			is_shared_freq = 1;
+			break;
+		}
+	}
+
 	for (i = 0; i < mode->num_channels; i++) {
-		if (mode->channels[i].chan == chan) {
-			if (flags)
-				*flags = mode->channels[i].flag;
-			if (mode->channels[i].flag &
-			    (HOSTAPD_CHAN_DISABLED |
-			     HOSTAPD_CHAN_RADAR))
-				return NOT_ALLOWED;
-			if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+		if (mode->channels[i].chan != chan)
+			continue;
+
+		if (flags)
+			*flags = mode->channels[i].flag;
+		if (mode->channels[i].flag & (HOSTAPD_CHAN_DISABLED |
+					      HOSTAPD_CHAN_RADAR))
+			return NOT_ALLOWED;
+
+		if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR) {
+			if (is_shared_freq && (mode->channels[i].flag &
+					       HOSTAPD_CHAN_GO_CONCURRENT))
+				return ALLOWED;
+			else if (mode->channels[i].flag &
+				 HOSTAPD_CHAN_INDOOR_ONLY)
+				return INDOOR_ONLY;
+			else
 				return NO_IR;
-			return ALLOWED;
 		}
-	}
 
+		if (mode->channels[i].flag & HOSTAPD_CHAN_INDOOR_ONLY)
+			return INDOOR_ONLY;
+
+		return ALLOWED;
+	}
 	return NOT_ALLOWED;
 }
 
@@ -3251,7 +3314,9 @@ static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
 
 static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
 					       struct hostapd_hw_modes *mode,
-					       u8 channel, u8 bw)
+					       u8 channel, u8 bw,
+					       struct wpa_used_freq_data *freqs,
+					       unsigned int num)
 {
 	u8 center_chan;
 	int i, flags;
@@ -3267,9 +3332,12 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
 	for (i = 0; i < 4; i++) {
 		int adj_chan = center_chan - 6 + i * 4;
 
-		res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+		res = has_channel(wpa_s->global, mode, adj_chan, &flags, freqs,
+				  num);
 		if (res == NOT_ALLOWED)
 			return NOT_ALLOWED;
+		if (res == INDOOR_ONLY)
+			return INDOOR_ONLY;
 		if (res == NO_IR)
 			ret = NO_IR;
 
@@ -3289,26 +3357,36 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
 
 static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
 						 struct hostapd_hw_modes *mode,
-						 u8 channel, u8 bw)
+						 u8 channel, u8 bw,
+						 struct wpa_used_freq_data *freqs,
+						 unsigned int num)
 {
 	int flag = 0;
 	enum chan_allowed res, res2;
 
-	res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+	res2 = res = has_channel(wpa_s->global, mode, channel, &flag, freqs,
+				 num);
 	if (bw == BW40MINUS) {
 		if (!(flag & HOSTAPD_CHAN_HT40MINUS))
 			return NOT_ALLOWED;
-		res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+		res2 = has_channel(wpa_s->global, mode, channel - 4, NULL,
+				   freqs, num);
 	} else if (bw == BW40PLUS) {
 		if (!(flag & HOSTAPD_CHAN_HT40PLUS))
 			return NOT_ALLOWED;
-		res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+		res2 = has_channel(wpa_s->global, mode, channel + 4, NULL,
+				   freqs, num);
 	} else if (bw == BW80) {
-		res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+		res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw, freqs,
+					     num);
 	}
 
 	if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
 		return NOT_ALLOWED;
+
+	if (res == INDOOR_ONLY || res2 == INDOOR_ONLY)
+		return NOT_ALLOWED;
+
 	if (res == NO_IR || res2 == NO_IR)
 		return NO_IR;
 	return res;
@@ -3343,7 +3421,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 			wpa_s->global->p2p_24ghz_social_channels = 1;
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
 			enum chan_allowed res;
-			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw,
+						      freqs, num);
 			if (res == ALLOWED) {
 				if (reg == NULL) {
 					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
@@ -3388,8 +3467,15 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			   struct hostapd_hw_modes *mode, u8 channel)
 {
 	int op;
-	enum chan_allowed ret;
+	enum chan_allowed res;
+	struct wpa_used_freq_data *freqs;
+	unsigned int num = wpa_s->num_multichan_concurrent;
+	int ret;
 
+	freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
+	num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+
+	ret = 0;
 	for (op = 0; op_class[op].op_class; op++) {
 		const struct p2p_oper_class_map *o = &op_class[op];
 		u8 ch;
@@ -3399,19 +3485,33 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			    (o->bw != BW40PLUS && o->bw != BW40MINUS) ||
 			    ch != channel)
 				continue;
-			ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
-			if (ret == ALLOWED)
-				return (o->bw == BW40MINUS) ? -1 : 1;
+			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw,
+						      freqs, num);
+			if (res == ALLOWED) {
+				ret = (o->bw == BW40MINUS) ? -1 : 1;
+				break;
+			}
 		}
 	}
-	return 0;
+	os_free(freqs);
+	return ret;
 }
 
 
 int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
 			      struct hostapd_hw_modes *mode, u8 channel)
 {
-	if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+	struct wpa_used_freq_data *freqs;
+	unsigned int num = wpa_s->num_multichan_concurrent;
+	int ret;
+
+	freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
+	num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+
+	ret = wpas_p2p_verify_channel(wpa_s, mode, channel, BW80, freqs, num);
+	os_free(freqs);
+
+	if (!ret)
 		return 0;
 
 	return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
@@ -8541,7 +8641,8 @@ static void wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s,
 		 * to move it
 		 */
 		if (wpa_s == ifs &&
-		    (trig == WPAS_P2P_CHANNEL_UPDATE_CS)) {
+		    (trig == WPAS_P2P_CHANNEL_UPDATE_STATE_CHANGE ||
+		     trig == WPAS_P2P_CHANNEL_UPDATE_CS)) {
 			wpa_dbg(wpa_s, MSG_DEBUG,
 				"P2P: GO move - schedule re-consideration");
 			eloop_register_timeout(P2P_RECONSIDER_GO_MOVE_DELAY, 0,
@@ -8560,7 +8661,21 @@ void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
 
-	wpas_p2p_update_channel_list(wpa_s);
+	/* Skip states that do not impact used frequencies */
+	switch (wpa_s->wpa_state) {
+	case WPA_SCANNING:
+	case WPA_AUTHENTICATING:
+	case WPA_ASSOCIATING:
+	case WPA_ASSOCIATED:
+	case WPA_4WAY_HANDSHAKE:
+	case WPA_GROUP_HANDSHAKE:
+		return;
+	default:
+		break;
+	}
+
+	wpas_p2p_update_channel_list(wpa_s,
+				     WPAS_P2P_CHANNEL_UPDATE_STATE_CHANGE);
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index feaf2ca..687c748 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -165,6 +165,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 enum wpas_p2p_channel_update_trig {
 	WPAS_P2P_CHANNEL_UPDATE_ANY = 0,
 	WPAS_P2P_CHANNEL_UPDATE_DRIVER,
+	WPAS_P2P_CHANNEL_UPDATE_STATE_CHANGE,
 	WPAS_P2P_CHANNEL_UPDATE_AVOID,
 	WPAS_P2P_CHANNEL_UPDATE_DISALLOW,
 	WPAS_P2P_CHANNEL_UPDATE_CS,
-- 
1.9.1




More information about the Hostap mailing list