diff mbox

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

Message ID 1438025074-23392-12-git-send-email-ilan.peer@intel.com
State Changes Requested
Headers show

Commit Message

Ilan Peer July 27, 2015, 7:24 p.m. UTC
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@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(-)

Comments

Jouni Malinen Aug. 14, 2015, 9:32 p.m. UTC | #1
On Mon, Jul 27, 2015 at 10:24:28PM +0300, Ilan Peer wrote:
> Enable using additional frequencies for P2P GO and P2P Client.

Have you considered the impacts of these changes to hostapd and
wpa_supplicant non-P2P AP use cases?

> diff --git 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_NO_IR) &&
> +				   !(feature->channels[j].flag &
> +				     (HOSTAPD_CHAN_INDOOR_ONLY |
> +				      HOSTAPD_CHAN_GO_CONCURRENT))) {
> +					feature->channels[j].flag |=
> +						HOSTAPD_CHAN_DISABLED;
>  			}

This would seem to leave no-IR channels enabled if they happen to have
INDOOR_ONLY or GO_CONCURRENT flag. Why would INDOOR_ONLY allow no-IR to
be ignored? There were no other changes in src/ap/* so this would change
hostapd behavior if we had any NO-OUTDOOR + NO-IR channels. Though, the
current wireless-regdb db.txt has no such combination. Nor does it have
any sign of "GO concurrent" (IR_CONCURRENT in current nl80211.h).

How is this supposed to be usable with the current wireless-regdb? Are
there some pending changes to it (and CRDA?) to start using the new
flags? If not, I'm not sure why hostapd/wpa_supplicant should be changed
either in this way.

For me to take this change, I think would need to be able to run a hwsim
test case that shows how this behaves, i.e., that wireless-regdb change
would be needed..
Ilan Peer Aug. 16, 2015, 1:37 p.m. UTC | #2
Hi Jouni,

> -----Original Message-----
> From: Jouni Malinen [mailto:j@w1.fi]
> Sent: Saturday, August 15, 2015 00:33
> To: Peer, Ilan
> Cc: hostap@lists.shmoo.com
> Subject: Re: [PATCH 11/17] P2P: Allow additional operating channels for P2P
> GO and client
> 
> On Mon, Jul 27, 2015 at 10:24:28PM +0300, Ilan Peer wrote:
> > Enable using additional frequencies for P2P GO and P2P Client.
> 
> Have you considered the impacts of these changes to hostapd and
> wpa_supplicant non-P2P AP use cases?

Not really ...

> 
> > diff --git 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_NO_IR) &&
> > +				   !(feature->channels[j].flag &
> > +				     (HOSTAPD_CHAN_INDOOR_ONLY |
> > +				      HOSTAPD_CHAN_GO_CONCURRENT))) {
> > +					feature->channels[j].flag |=
> > +						HOSTAPD_CHAN_DISABLED;
> >  			}
> 
> This would seem to leave no-IR channels enabled if they happen to have
> INDOOR_ONLY or GO_CONCURRENT flag. Why would INDOOR_ONLY allow no-
> IR to be ignored?

It should not its own. The implementation is in complete, i.e., buggy .. :)

There were no other changes in src/ap/* so this would
> change hostapd behavior if we had any NO-OUTDOOR + NO-IR channels.
> Though, the current wireless-regdb db.txt has no such combination. Nor does
> it have any sign of "GO concurrent" (IR_CONCURRENT in current nl80211.h).
> 

We did not intend to add this to wireless regdb. We are using this regulatory relaxation features with hw based regulatory.

> How is this supposed to be usable with the current wireless-regdb? Are there
> some pending changes to it (and CRDA?) to start using the new flags? If not,
> I'm not sure why hostapd/wpa_supplicant should be changed either in this
> way.
> 

I do not think that this should mandate changes in regdb, as this can be still used by hw based regulatory configuration.

> For me to take this change, I think would need to be able to run a hwsim test
> case that shows how this behaves, i.e., that wireless-regdb change would be
> needed..
> 

This can also be done with custom regdomain.

Anyway, this would need more work, so please drop these patches from your queue for now.

Thanks again,

Ilan.
diff mbox

Patch

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,