hostapd: Verify VHT capabilities are supported by driver
authorEliad Peller <eliad@wizery.com>
Sun, 27 Oct 2013 17:11:29 +0000 (19:11 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 27 Oct 2013 17:11:29 +0000 (19:11 +0200)
Make sure the defined VHT capabilities are supported by the driver.

Signed-hostap: Eliad Peller <eliadx.peller@intel.com>

src/ap/hw_features.c
src/common/ieee802_11_defs.h
src/utils/common.c
src/utils/common.h

index 07db315..d2831d4 100644 (file)
@@ -653,6 +653,92 @@ 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 a 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 */
 
 
@@ -664,6 +750,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;
index 12bf92d..4d60fc0 100644 (file)
@@ -704,6 +704,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))
@@ -714,6 +715,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) | \
index 5734de7..257bb6d 100644 (file)
@@ -578,6 +578,21 @@ int is_hex(const u8 *data, size_t len)
 }
 
 
+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,
                         const u8 *src2, size_t src2_len)
index ba08cf4..028a5ef 100644 (file)
@@ -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);