Patchwork [04/23] P2P: allow additional operating channels for P2P GO and client

login
register
mail settings
Submitter Ilan Peer
Date July 7, 2014, 11:20 a.m.
Message ID <1404732076-32252-5-git-send-email-ilan.peer@intel.com>
Download mbox | patch
Permalink /patch/367507/
State New
Headers show

Comments

Ilan Peer - July 7, 2014, 11:20 a.m.
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.

Change-Id: I45483a670ceda6d358783292d1d5a0d96d1d4042
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
---
 src/ap/hw_features.c            |   11 ++-
 wpa_supplicant/p2p_supplicant.c |  180 +++++++++++++++++++++++++++++++--------
 2 files changed, 153 insertions(+), 38 deletions(-)

Patch

diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index db0f7ae..23f0eae 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -117,11 +117,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 a51b56c..2a8a88f 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3410,34 +3410,95 @@  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;
 }
 
@@ -3502,7 +3563,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;
@@ -3518,9 +3581,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;
 
@@ -3540,26 +3606,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;
@@ -3572,6 +3648,8 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 {
 	struct hostapd_hw_modes *mode;
 	int cla, op, cli_cla;
+	struct wpa_used_freq_data *freqs;
+	unsigned int num = wpa_s->num_multichan_concurrent;
 
 	if (wpa_s->hw.modes == NULL) {
 		wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
@@ -3580,6 +3658,10 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 		return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
 	}
 
+	/* Note: the flow can still be handled even if the allocation fails */
+	freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
+	num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+
 	cla = cli_cla = 0;
 
 	for (op = 0; op_class[op].op_class; op++) {
@@ -3592,7 +3674,8 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 			continue;
 		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",
@@ -3629,6 +3712,7 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 	chan->reg_classes = cla;
 	cli_chan->reg_classes = cli_cla;
 
+	os_free(freqs);
 	return 0;
 }
 
@@ -3637,8 +3721,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++) {
 		struct p2p_oper_class_map *o = &op_class[op];
 		u8 ch;
@@ -3647,19 +3738,33 @@  int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			if (o->mode != HOSTAPD_MODE_IEEE80211A ||
 			    o->bw == BW20 || 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);
@@ -7848,15 +7953,20 @@  void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
 
-	/*
-	 * If possible, optimize the Listen channel to be a channel that is
-	 * already used by one of the other interfaces.
-	 */
-	if (!wpa_s->conf->p2p_optimize_listen_chan)
+	/* 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;
+	}
 
-	if (!wpa_s->current_ssid || wpa_s->wpa_state != WPA_COMPLETED)
-		return;
+	wpas_p2p_update_channel_list(wpa_s);
 
 	freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
 	if (!freqs)