From c781eb842852f4055080b2fab63fb8bf8ffba76d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 27 Oct 2013 19:11:29 +0200 Subject: [PATCH] hostapd: Verify VHT capabilities are supported by driver Make sure the defined VHT capabilities are supported by the driver. Signed-hostap: Eliad Peller --- src/ap/hw_features.c | 90 ++++++++++++++++++++++++++++++++++++ src/common/ieee802_11_defs.h | 3 ++ src/utils/common.c | 15 ++++++ src/utils/common.h | 1 + 4 files changed, 109 insertions(+) diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 07db3154b..d2831d4c6 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -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; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 12bf92db0..4d60fc0a9 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -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) | \ diff --git a/src/utils/common.c b/src/utils/common.c index 5734de711..257bb6d42 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -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) diff --git a/src/utils/common.h b/src/utils/common.h index ba08cf4d1..028a5eff7 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);