Patchwork [9/9] p2p: add vht support

login
register
mail settings
Submitter Eliad Peller
Date Oct. 17, 2013, 8:03 a.m.
Message ID <1381997026-2324-10-git-send-email-eliad@wizery.com>
Download mbox | patch
Permalink /patch/284120/
State Accepted
Commit ca9bc5b5666a08c741ddd21c451ecb92aa33a11a
Headers show

Comments

Eliad Peller - Oct. 17, 2013, 8:03 a.m.
From: Eliad Peller <eliad@wizery.com>

start GO with vht support if vht option was requested
and the appropriate channels are available.

Signed-hostap: Eliad Peller <eliadx.peller@intel.com>
---
 src/p2p/p2p_go_neg.c            |   13 +++++++
 src/p2p/p2p_utils.c             |    4 +++
 src/utils/common.h              |    4 +++
 wpa_supplicant/ap.c             |   27 ++++++++++++++
 wpa_supplicant/p2p_supplicant.c |   75 ++++++++++++++++++++++++++++++++++++++-
 wpa_supplicant/p2p_supplicant.h |    2 ++
 6 files changed, 124 insertions(+), 1 deletion(-)

Patch

diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 491a3d0..8099eb5 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -403,6 +403,19 @@  void p2p_reselect_channel(struct p2p_data *p2p,
 		}
 	}
 
+	/* Try a channel where we might be able to use VHT */
+	for (i = 0; i < intersection->reg_classes; i++) {
+		struct p2p_reg_class *c = &intersection->reg_class[i];
+		p2p_dbg(p2p, "(reg class: %d)", c->reg_class);
+		if (c->reg_class == 128) {
+			p2p_dbg(p2p, "Pick possible VHT channel (reg_class %u channel %u) from intersection",
+				c->reg_class, c->channel[0]);
+			p2p->op_reg_class = c->reg_class;
+			p2p->op_channel = c->channel[0];
+			return;
+		}
+	}
+
 	/* Try a channel where we might be able to use HT40 */
 	for (i = 0; i < intersection->reg_classes; i++) {
 		struct p2p_reg_class *c = &intersection->reg_class[i];
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index deb7aa9..c01447e 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -94,6 +94,10 @@  int p2p_channel_to_freq(int op_class, int channel)
 		if (channel < 149 || channel > 161)
 			return -1;
 		return 5000 + 5 * channel;
+	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80MHz */
+		if (channel < 36 || channel > 161)
+			return -1;
+		return 5000 + 5 * channel;
 	}
 	return -1;
 }
diff --git a/src/utils/common.h b/src/utils/common.h
index fad24fd..ef4ee89 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -432,6 +432,10 @@  void perror(const char *s);
 #define BIT(x) (1 << (x))
 #endif
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
 /*
  * Definitions for sparse validation
  * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index fdbe248..0435ac0 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -41,6 +41,28 @@ 
 static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 #endif /* CONFIG_WPS */
 
+static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+			     struct hostapd_config *conf,
+			     struct hostapd_hw_modes *mode)
+{
+	u8 center_chan = 0;
+	u8 channel = conf->channel;
+
+	if (!conf->secondary_channel)
+		goto no_vht;
+
+	center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+	if (!center_chan)
+		goto no_vht;
+
+	/* use 80mhz channel */
+	conf->vht_oper_chwidth = 1;
+	conf->vht_oper_centr_freq_seg0_idx = center_chan;
+	return;
+no_vht:
+	conf->vht_oper_centr_freq_seg0_idx =
+		channel + conf->secondary_channel * 2;
+}
 
 static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid,
@@ -114,6 +136,11 @@  static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 				 HT_CAP_INFO_SHORT_GI40MHZ |
 				 HT_CAP_INFO_RX_STBC_MASK |
 				 HT_CAP_INFO_MAX_AMSDU_SIZE);
+
+			if (mode->vht_capab && ssid->vht) {
+				conf->ieee80211ac = 1;
+				wpas_conf_ap_vht(wpa_s, conf, mode);
+			}
 		}
 	}
 #endif /* CONFIG_IEEE80211N */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 60a549c..7deacaf 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3039,7 +3039,7 @@  struct p2p_oper_class_map {
 	u8 min_chan;
 	u8 max_chan;
 	u8 inc;
-	enum { BW20, BW40PLUS, BW40MINUS } bw;
+	enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
 };
 
 static struct p2p_oper_class_map op_class[] = {
@@ -3054,9 +3054,70 @@  static struct p2p_oper_class_map op_class[] = {
 	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
 	{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+
+	/*
+	 * The draft (Table E-4) actually talks about center freq
+	 * 42, 58, 106, 122, 138, 155 with channel spacing of 80,
+	 * but currently use the following definition for simplicity
+	 * (these center freqs are not actual channels, which
+	 * make has_channel() fail). wpas_p2p_verify_80mhz() should
+	 * take care of removing invalid channels.
+	 */
+	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
 	{ -1, 0, 0, 0, 0, BW20 }
 };
 
+static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
+				     struct hostapd_hw_modes *mode,
+				     u8 channel)
+{
+	u8 center_channels[] = {42, 58, 106, 122, 138, 155};
+	int i;
+
+	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+		/*
+		 * in 80mhz, the bandwidth "spans" 12 channels (e.g. 36-48),
+		 * so the center channel is 6 channels away from the start/end.
+		 */
+		if (channel >= center_channels[i] - 6 &&
+		    channel <= center_channels[i] + 6)
+			return center_channels[i];
+
+	return 0;
+}
+
+static int wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
+				 struct hostapd_hw_modes *mode,
+				 u8 channel, u8 bw)
+{
+	u8 center_chan;
+	int i, flags;
+
+	center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+	if (!center_chan)
+		return 0;
+
+	/* check all the channels are available */
+	for (i = 0; i < 4; i++) {
+		int adj_chan = center_chan - 6 + i*4;
+
+		if (!has_channel(wpa_s->global, mode, adj_chan, &flags))
+			return 0;
+
+		if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
+			return 0;
+		else if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+			return 0;
+		else if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+			return 0;
+		else if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))
+			return 0;
+	}
+	return 1;
+}
 
 static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
 				   struct hostapd_hw_modes *mode,
@@ -3074,6 +3135,10 @@  static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
 	    (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
 	     !has_channel(wpa_s->global, mode, channel + 4, NULL)))
 		return 0;
+	if (bw == BW80 &&
+	    !wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw))
+		return 0;
+
 	return 1;
 }
 
@@ -3151,6 +3216,14 @@  int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 	return 0;
 }
 
+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))
+		return 0;
+
+	return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+}
 
 static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
 			size_t buf_len)
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index c0ad29e..785062d 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -152,6 +152,8 @@  void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
 int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 			   struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+			      struct hostapd_hw_modes *mode, u8 channel);
 unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
 void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
 			 const u8 *p2p_dev_addr,