diff --git a/src/wiphy.c b/src/wiphy.c index 88a0fff8..f83353ed 100644 --- a/src/wiphy.c +++ b/src/wiphy.c @@ -936,6 +936,74 @@ static void wiphy_print_mcs_info(const uint8_t *mcs_map, } } +static void wiphy_print_he_capabilities(struct band *band, + const struct band_he_capabilities *he_cap) +{ + int i; + char type_buf[128]; + char *s = type_buf; + uint8_t width_set = bit_field(he_cap->he_phy_capa[0], 1, 7); + + for (i = 0; i < 32; i++) { + if (!(he_cap->iftypes & (1 << i))) + continue; + + if (L_WARN_ON(s >= type_buf + sizeof(type_buf))) + return; + + switch (i) { + case NETDEV_IFTYPE_ADHOC: + s += sprintf(s, "%s ", "Ad-Hoc"); + break; + case NETDEV_IFTYPE_STATION: + s += sprintf(s, "%s ", "Station"); + break; + case NETDEV_IFTYPE_AP: + s += sprintf(s, "%s ", "AP"); + break; + case NETDEV_IFTYPE_P2P_CLIENT: + s += sprintf(s, "%s ", "P2P Client"); + break; + case NETDEV_IFTYPE_P2P_GO: + s += sprintf(s, "%s ", "P2P GO"); + break; + } + } + + l_info("\t\t\tInterface Types: %s", type_buf); + + switch (band->freq) { + case BAND_FREQ_2_4_GHZ: + wiphy_print_mcs_info(he_cap->he_mcs_set, + "HE RX <= 80MHz", 7, 9, 11); + wiphy_print_mcs_info(he_cap->he_mcs_set + 2, + "HE TX <= 80MHz", 7, 9, 11); + break; + case BAND_FREQ_5_GHZ: + case BAND_FREQ_6_GHZ: + wiphy_print_mcs_info(he_cap->he_mcs_set, + "HE RX <= 80MHz", 7, 9, 11); + wiphy_print_mcs_info(he_cap->he_mcs_set + 2, + "HE TX <= 80MHz", 7, 9, 11); + + if (test_bit(&width_set, 2)) { + wiphy_print_mcs_info(he_cap->he_mcs_set + 4, + "HE RX <= 160MHz", 7, 9, 11); + wiphy_print_mcs_info(he_cap->he_mcs_set + 6, + "HE TX <= 160MHz", 7, 9, 11); + } + + if (test_bit(&width_set, 3)) { + wiphy_print_mcs_info(he_cap->he_mcs_set + 8, + "HE RX <= 80+80MHz", 7, 9, 11); + wiphy_print_mcs_info(he_cap->he_mcs_set + 10, + "HE TX <= 80+80MHz", 7, 9, 11); + } + + break; + } +} + static void wiphy_print_band_info(struct band *band, const char *name) { int i; @@ -995,6 +1063,20 @@ static void wiphy_print_band_info(struct band *band, const char *name) wiphy_print_mcs_info(band->vht_mcs_set, "RX", 7, 8, 9); wiphy_print_mcs_info(band->vht_mcs_set + 4, "TX", 7, 8, 9); } + + if (band->he_capabilities) { + const struct l_queue_entry *entry; + + l_info("\t\tHE Capabilities"); + + for (entry = l_queue_get_entries(band->he_capabilities); + entry; entry = entry->next) { + const struct band_he_capabilities *he_cap = entry->data; + + wiphy_print_he_capabilities(band, he_cap); + } + + } } static void wiphy_print_basic_info(struct wiphy *wiphy) @@ -1208,6 +1290,90 @@ static struct band *band_new_from_message(struct l_genl_attr *band) return ret; } +static uint32_t get_iftypes(struct l_genl_attr *iftypes) +{ + uint16_t type; + uint16_t len; + uint32_t types = 0; + + while (l_genl_attr_next(iftypes, &type, &len, NULL)) { + if (len != 0) + continue; + + types |= (1 << type); + } + + return types; +} + +static void parse_iftype_attrs(struct band *band, struct l_genl_attr *types) +{ + uint16_t type; + uint16_t len; + const void *data; + unsigned int count = 0; + struct band_he_capabilities *he_cap = + l_new(struct band_he_capabilities, 1); + + while (l_genl_attr_next(types, &type, &len, &data)) { + struct l_genl_attr iftypes; + + switch (type) { + case NL80211_BAND_IFTYPE_ATTR_IFTYPES: + if (!l_genl_attr_recurse(types, &iftypes)) + goto parse_error; + + he_cap->iftypes = get_iftypes(&iftypes); + break; + case NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: + if (len > sizeof(he_cap->he_phy_capa)) + continue; + + memcpy(he_cap->he_phy_capa, data, len); + count++; + break; + case NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: + if (len > sizeof(he_cap->he_mcs_set)) + continue; + + memcpy(he_cap->he_mcs_set, data, len); + count++; + break; + default: + break; + } + } + + /* + * Since the capabilities element indicates what values are present in + * the MCS set ensure both values are parsed + */ + if (count != 2 || !he_cap->iftypes) + goto parse_error; + + if (!band->he_capabilities) + band->he_capabilities = l_queue_new(); + + l_queue_push_head(band->he_capabilities, he_cap); + + return; + +parse_error: + l_free(he_cap); +} + +static void parse_band_iftype_data(struct band *band, struct l_genl_attr *ifdata) +{ + while (l_genl_attr_next(ifdata, NULL, NULL, NULL)) { + struct l_genl_attr types; + + if (!l_genl_attr_recurse(ifdata, &types)) + continue; + + parse_iftype_attrs(band, &types); + } +} + static void parse_supported_bands(struct wiphy *wiphy, struct l_genl_attr *bands) { @@ -1256,15 +1422,17 @@ static void parse_supported_bands(struct wiphy *wiphy, } else band = *bandp; + + while (l_genl_attr_next(&attr, &type, &len, &data)) { - struct l_genl_attr freqs; + struct l_genl_attr nested; switch (type) { case NL80211_BAND_ATTR_FREQS: - if (!l_genl_attr_recurse(&attr, &freqs)) + if (!l_genl_attr_recurse(&attr, &nested)) continue; - parse_supported_frequencies(wiphy, &freqs); + parse_supported_frequencies(wiphy, &nested); break; case NL80211_BAND_ATTR_RATES: @@ -1304,6 +1472,12 @@ static void parse_supported_bands(struct wiphy *wiphy, memcpy(band->ht_capabilities, data, len); band->ht_supported = true; break; + case NL80211_BAND_ATTR_IFTYPE_DATA: + if (!l_genl_attr_recurse(&attr, &nested)) + continue; + + parse_band_iftype_data(band, &nested); + break; } }