hostapd: Verify VHT capabilities are supported by driver

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

Signed-hostap: Eliad Peller <eliadx.peller@intel.com>
This commit is contained in:
Eliad Peller 2013-10-27 19:11:29 +02:00 committed by Jouni Malinen
parent b29b012cbc
commit c781eb8428
4 changed files with 109 additions and 0 deletions

View file

@ -653,6 +653,92 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 1; 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 */ #endif /* CONFIG_IEEE80211N */
@ -664,6 +750,10 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0; return 0;
if (!ieee80211n_supported_ht_capab(iface)) if (!ieee80211n_supported_ht_capab(iface))
return -1; return -1;
#ifdef CONFIG_IEEE80211AC
if (!ieee80211ac_supported_vht_capab(iface))
return -1;
#endif /* CONFIG_IEEE80211AC */
ret = ieee80211n_check_40mhz(iface); ret = ieee80211n_check_40mhz(iface);
if (ret) if (ret)
return ret; return ret;

View file

@ -704,6 +704,7 @@ struct ieee80211_vht_operation {
/* VHT Defines */ /* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0)) #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_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_160MHZ ((u32) BIT(2))
#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3)) #define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3))
#define VHT_CAP_RXLDPC ((u32) BIT(4)) #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_2 ((u32) BIT(9))
#define VHT_CAP_RXSTBC_3 ((u32) BIT(8) | BIT(9)) #define VHT_CAP_RXSTBC_3 ((u32) BIT(8) | BIT(9))
#define VHT_CAP_RXSTBC_4 ((u32) BIT(10)) #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_BEAMFORMER_CAPABLE ((u32) BIT(11))
#define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12)) #define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12))
#define VHT_CAP_BEAMFORMEE_STS_MAX ((u32) BIT(13) | \ #define VHT_CAP_BEAMFORMEE_STS_MAX ((u32) BIT(13) | \

View 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, size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len, const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len) const u8 *src2, size_t src2_len)

View 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); char * wpa_config_parse_string(const char *value, size_t *len);
int is_hex(const u8 *data, 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, size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len, const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len); const u8 *src2, size_t src2_len);