Patchwork [3/9] hostapd: verify vht capabilities are supported by driver

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

Comments

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

Make sure the defined vht capabilities are supported by
the driver.

Signed-hostap: Eliad Peller <eliadx.peller@intel.com>
---
 src/ap/hw_features.c         |   86 ++++++++++++++++++++++++++++++++++++++++++
 src/common/ieee802_11_defs.h |    3 ++
 src/utils/common.c           |   12 ++++++
 src/utils/common.h           |    1 +
 4 files changed, 102 insertions(+)

Patch

diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8a239f4..d76b569 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -613,6 +613,88 @@  static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
 	return 1;
 }
 
+#ifdef CONFIG_IEEE80211AC
+static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
+{
+	u32 req_cap = conf & cap;
+
+	/*
+	 * make sure we support all requested capabilities.
+	 * NOTE: we assume that 'cap' represents a capability mask,
+	 * not discrete value.
+	 */
+	if ((hw & req_cap) != req_cap) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "VHT capability [%s]", name);
+		return 0;
+	}
+	return 1;
+}
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
+				     const char *name)
+{
+	u32 hw_max = hw & cap;
+	u32 conf_val = conf & cap;
+
+	if (conf_val > hw_max) {
+		int offset = find_first_bit(cap);
+		wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds "
+			   "max value supported by the driver (%d > %d)",
+			   name, conf_val >> offset, hw_max >> offset);
+		return 0;
+	}
+	return 1;
+}
+
+static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
+{
+	u32 hw = iface->current_mode->vht_capab;
+	u32 conf = iface->conf->vht_capab;
+
+	wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
+		   hw, conf);
+
+#define VHT_CAP_CHECK(cap) do {\
+		if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) do {\
+		if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
+	VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+	VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+	VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+	VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+	VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+	VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+	VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+	return 1;
+}
+#endif /* CONFIG_IEEE80211AC */
+
 #endif /* CONFIG_IEEE80211N */
 
 
@@ -624,6 +706,10 @@  int hostapd_check_ht_capab(struct hostapd_iface *iface)
 		return 0;
 	if (!ieee80211n_supported_ht_capab(iface))
 		return -1;
+#ifdef CONFIG_IEEE80211AC
+	if (!ieee80211ac_supported_vht_capab(iface))
+		return -1;
+#endif /* CONFIG_IEEE80211AC */
 	ret = ieee80211n_check_40mhz(iface);
 	if (ret)
 		return ret;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index c51c46c..67f6451 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -702,6 +702,7 @@  struct ieee80211_vht_operation {
 /* VHT Defines */
 #define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
 #define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK                ((u32) BIT(0) | BIT(1))
 #define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
 #define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
 #define VHT_CAP_RXLDPC                              ((u32) BIT(4))
@@ -712,6 +713,8 @@  struct ieee80211_vht_operation {
 #define VHT_CAP_RXSTBC_2                            ((u32) BIT(9))
 #define VHT_CAP_RXSTBC_3                            ((u32) BIT(8) | BIT(9))
 #define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
+#define VHT_CAP_RXSTBC_MASK                         ((u32) BIT(8) | BIT(9) | \
+							   BIT(10))
 #define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
 #define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
 #define VHT_CAP_BEAMFORMEE_STS_MAX                  ((u32) BIT(13) | \
diff --git a/src/utils/common.c b/src/utils/common.c
index 207d477..5494c79 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -577,6 +577,18 @@  int is_hex(const u8 *data, size_t len)
 	return 0;
 }
 
+int find_first_bit(u32 value)
+{
+	int pos = 0;
+
+	while (value) {
+		if (value & 0x1)
+			return pos;
+		value >>= 1;
+		pos++;
+	}
+	return -1;
+}
 
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
diff --git a/src/utils/common.h b/src/utils/common.h
index 29f0b95..fad24fd 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -485,6 +485,7 @@  const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
 
 char * wpa_config_parse_string(const char *value, size_t *len);
 int is_hex(const u8 *data, size_t len);
+int find_first_bit(u32 value);
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len);