From 9e01563e8c60baf0332bf899300204e103d0b1d2 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Tue, 20 Dec 2022 13:43:12 -0800 Subject: [PATCH] wiphy: add getter for HT capabilities This adds some additional parsing to obtain the AMPDU parameter byte as well as wiphy_get_ht_capabilities() which returns the complete IE (combining the 3 separate kernel attributes). --- src/wiphy.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/wiphy.h | 3 +++ 2 files changed, 56 insertions(+) diff --git a/src/wiphy.c b/src/wiphy.c index 4ea7c3f8..a97b3522 100644 --- a/src/wiphy.c +++ b/src/wiphy.c @@ -910,6 +910,42 @@ bool wiphy_country_is_unknown(struct wiphy *wiphy) (cc[0] == 'X' && cc[1] == 'X')); } +const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy, + enum band_freq band, + size_t *size) +{ + static uint8_t ht_capa[26]; + const struct band *bandp = wiphy_get_band(wiphy, band); + + if (!bandp) + return NULL; + + if (!bandp->ht_supported) + return NULL; + + memset(ht_capa, 0, sizeof(ht_capa)); + + /* + * The kernel segments the HT capabilities element into multiple + * attributes. For convenience on the caller just combine them and + * return the full IE rather than adding 3 separate getters. This also + * provides a way to check if HT is supported. + */ + memcpy(ht_capa, bandp->ht_capabilities, 2); + ht_capa[2] = bandp->ht_ampdu_params; + memcpy(ht_capa + 3, bandp->ht_mcs_set, 16); + + /* + * TODO: HT Extended capabilities, beamforming, and ASEL capabilities + * are not available to get from the kernel, leave as zero. + */ + + if (size) + *size = sizeof(ht_capa); + + return ht_capa; +} + int wiphy_estimate_data_rate(struct wiphy *wiphy, const void *ies, uint16_t ies_len, const struct scan_bss *bss, @@ -1617,6 +1653,23 @@ static void parse_supported_bands(struct wiphy *wiphy, memcpy(band->ht_capabilities, data, len); band->ht_supported = true; break; + /* + * AMPDU factor/density are part of A-MPDU Parameters, + * 802.11-2020 Section 9.4.2.55.3. + */ + case NL80211_BAND_ATTR_HT_AMPDU_FACTOR: + if (L_WARN_ON(len != 1)) + continue; + + band->ht_ampdu_params |= l_get_u8(data) & 0x3; + break; + case NL80211_BAND_ATTR_HT_AMPDU_DENSITY: + if (L_WARN_ON(len != 1)) + continue; + + band->ht_ampdu_params |= + (l_get_u8(data) & 0x7) << 2; + break; case NL80211_BAND_ATTR_IFTYPE_DATA: if (!l_genl_attr_recurse(&attr, &nested)) continue; diff --git a/src/wiphy.h b/src/wiphy.h index 6616da61..5cf22537 100644 --- a/src/wiphy.h +++ b/src/wiphy.h @@ -138,6 +138,9 @@ bool wiphy_get_rsnxe(const struct wiphy *wiphy, uint8_t *buf, size_t len); void wiphy_get_reg_domain_country(struct wiphy *wiphy, char *out); bool wiphy_country_is_unknown(struct wiphy *wiphy); +const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy, + enum band_freq band, + size_t *size); void wiphy_generate_random_address(struct wiphy *wiphy, uint8_t addr[static 6]); void wiphy_generate_address_from_ssid(struct wiphy *wiphy, const char *ssid, uint8_t addr[static 6]);