Patchwork [1/4] hostapd: allow configuring driver to VHT

login
register
mail settings
Submitter Johannes Berg
Date Dec. 28, 2012, 2:32 p.m.
Message ID <1356705152-3549-1-git-send-email-johannes@sipsolutions.net>
Download mbox | patch
Permalink /patch/208490/
State Accepted
Headers show

Comments

Johannes Berg - Dec. 28, 2012, 2:32 p.m.
From: Johannes Berg <johannes.berg@intel.com>

Signed-hostap: Johannes Berg <johannes.berg@intel.com>
---
 src/ap/ap_drv_ops.c          | 67 ++++++++++++++++++++++++++++++++++++++++----
 src/ap/ap_drv_ops.h          |  4 ++-
 src/ap/hostapd.c             |  6 +++-
 src/common/ieee802_11_defs.h |  6 ++++
 src/drivers/driver.h         |  9 ++++++
 5 files changed, 85 insertions(+), 7 deletions(-)
Johannes Berg - Dec. 28, 2012, 2:34 p.m.
On Fri, 2012-12-28 at 15:32 +0100, Johannes Berg wrote:

> +	/*
> +	 * This validation code is probably misplaced, maybe it should be
> +	 * in src/ap/hw_features.c and check the hardware support as well.
> +	 */

This is a concern, but the kernel also validates. Not sure if you want
to apply it anyway.

> +	if (data.vht_enabled) switch (vht_oper_chwidth) {
> +	case VHT_CHANWIDTH_USE_HT:
> +		if (center_segment1)
> +			return -1;
> +		if (5000 + center_segment0 * 5 != data.center_freq1)
> +			return -1;

I decided not to introduce anything but "5000" here, the value is used
in a bunch of other places in the code just like this as well and
there's no support for other starting frequencies afaict.

johannes
Johannes Berg - Dec. 28, 2012, 2:35 p.m.
On Fri, 2012-12-28 at 15:32 +0100, Johannes Berg wrote:

> +	/*
> +	 * This validation code is probably misplaced, maybe it should be
> +	 * in src/ap/hw_features.c and check the hardware support as well.
> +	 */

This is a concern, but the kernel also validates. Not sure if you want
to apply it anyway.

> +	if (data.vht_enabled) switch (vht_oper_chwidth) {
> +	case VHT_CHANWIDTH_USE_HT:
> +		if (center_segment1)
> +			return -1;
> +		if (5000 + center_segment0 * 5 != data.center_freq1)
> +			return -1;

I decided not to introduce a constant for "5000" here, the value is used
in a bunch of other places in the code just like this as well and
there's no support for other starting frequencies afaict.

johannes
Jouni Malinen - Dec. 28, 2012, 3:36 p.m.
Thanks! I applied all four patches into the new devel branch. As such,
these are subject to change and rebasing as needed and can go into the
master branch once 2.0 has been released.

Patch

diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 02da25b..355df15 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -454,19 +454,76 @@  int hostapd_flush(struct hostapd_data *hapd)
 
 
 int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int sec_channel_offset)
+		     int channel, int ht_enabled, int vht_enabled,
+		     int sec_channel_offset, int vht_oper_chwidth,
+		     int center_segment0, int center_segment1)
 {
 	struct hostapd_freq_params data;
-	if (hapd->driver == NULL)
-		return 0;
-	if (hapd->driver->set_freq == NULL)
-		return 0;
+	int tmp;
+
 	os_memset(&data, 0, sizeof(data));
 	data.mode = mode;
 	data.freq = freq;
 	data.channel = channel;
 	data.ht_enabled = ht_enabled;
+	data.vht_enabled = vht_enabled;
 	data.sec_channel_offset = sec_channel_offset;
+	data.center_freq1 = freq + sec_channel_offset * 10;
+	data.center_freq2 = 0;
+	data.bandwidth = sec_channel_offset ? 40 : 20;
+
+	/*
+	 * This validation code is probably misplaced, maybe it should be
+	 * in src/ap/hw_features.c and check the hardware support as well.
+	 */
+	if (data.vht_enabled) switch (vht_oper_chwidth) {
+	case VHT_CHANWIDTH_USE_HT:
+		if (center_segment1)
+			return -1;
+		if (5000 + center_segment0 * 5 != data.center_freq1)
+			return -1;
+		break;
+	case VHT_CHANWIDTH_80P80MHZ:
+		if (center_segment1 == center_segment0 + 4 ||
+		    center_segment1 == center_segment0 - 4)
+			return -1;
+		data.center_freq2 = 5000 + center_segment1 * 5;
+		/* fall through */
+	case VHT_CHANWIDTH_80MHZ:
+		data.bandwidth = 80;
+		if (vht_oper_chwidth == 1 && center_segment1)
+			return -1;
+		if (vht_oper_chwidth == 3 && !center_segment1)
+			return -1;
+		if (!sec_channel_offset)
+			return -1;
+		/* primary 40 part must match the HT configuration */
+		tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
+		tmp /= 2;
+		if (data.center_freq1 != 5000 +
+					 center_segment0 * 5 - 20 + 40 * tmp)
+			return -1;
+		data.center_freq1 = 5000 + center_segment0 * 5;
+		break;
+	case VHT_CHANWIDTH_160MHZ:
+		data.bandwidth = 160;
+		if (center_segment1)
+			return -1;
+		if (!sec_channel_offset)
+			return -1;
+		/* primary 40 part must match the HT configuration */
+		tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
+		tmp /= 2;
+		if (data.center_freq1 != 5000 +
+					 center_segment0 * 5 - 60 + 40 * tmp)
+			return -1;
+		data.center_freq1 = 5000 + center_segment0 * 5;
+		break;
+	}
+	if (hapd->driver == NULL)
+		return 0;
+	if (hapd->driver->set_freq == NULL)
+		return 0;
 	return hapd->driver->set_freq(hapd->drv_priv, &data);
 }
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 9c53b99..768a0ba 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -55,7 +55,9 @@  int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
 		       const u8 *addr, int idx, u8 *seq);
 int hostapd_flush(struct hostapd_data *hapd);
 int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int sec_channel_offset);
+		     int channel, int ht_enabled, int vht_enabled,
+		     int sec_channel_offset, int vht_oper_chwidth,
+		     int center_segment0, int center_segment1);
 int hostapd_set_rts(struct hostapd_data *hapd, int rts);
 int hostapd_set_frag(struct hostapd_data *hapd, int frag);
 int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index cef9daf..92fda56 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -894,7 +894,11 @@  int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
 		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
 				     hapd->iconf->channel,
 				     hapd->iconf->ieee80211n,
-				     hapd->iconf->secondary_channel)) {
+				     hapd->iconf->ieee80211ac,
+				     hapd->iconf->secondary_channel,
+				     hapd->iconf->vht_oper_chwidth,
+				     hapd->iconf->vht_oper_centr_freq_seg0_idx,
+				     hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
 			wpa_printf(MSG_ERROR, "Could not set channel for "
 				   "kernel driver");
 			return -1;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index e873545..f72c0d4 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -712,6 +712,12 @@  struct ieee80211_vht_operation {
 #define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
 #define VHT_CAP_TX_ANTENNA_PATTERN                  ((u32) BIT(29))
 
+/* VHT channel widths */
+#define VHT_CHANWIDTH_USE_HT	0
+#define VHT_CHANWIDTH_80MHZ	1
+#define VHT_CHANWIDTH_160MHZ	2
+#define VHT_CHANWIDTH_80P80MHZ	3
+
 #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
 				* 00:50:F2 */
 #define WPA_IE_VENDOR_TYPE 0x0050f201
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 7ee71aa..62f621f 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -907,10 +907,19 @@  struct hostapd_freq_params {
 	int mode;
 	int freq;
 	int channel;
+	/* for HT */
 	int ht_enabled;
 	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
 				 * secondary channel below primary, 1 = HT40
 				 * enabled, secondary channel above primary */
+
+	/* for VHT */
+	int vht_enabled;
+
+	/* valid for both HT and VHT, center_freq2 is non-zero
+	 * only for bandwidth 80 and an 80+80 channel */
+	int center_freq1, center_freq2;
+	int bandwidth;
 };
 
 enum wpa_driver_if_type {