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:
parent
b29b012cbc
commit
c781eb8428
4 changed files with 109 additions and 0 deletions
|
@ -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;
|
||||||
|
|
|
@ -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) | \
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue