Print the HE MAC/PHY capabilities and MCS/NSS sets. Signed-off-by: Shashidhar Lakkavalli <slakkavalli@xxxxxxxxx> Signed-off-by: John Crispin <john@xxxxxxxxxxx> --- Changes in V2 * add a missing ',' in the iftypes name list info.c | 6 ++ iw.h | 1 + util.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) diff --git a/info.c b/info.c index 92c7d1d..e6270c8 100644 --- a/info.c +++ b/info.c @@ -162,7 +162,13 @@ static int print_phy_handler(struct nl_msg *msg, void *arg) tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]) print_vht_info(nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]), nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])); + if (tb_band[NL80211_BAND_ATTR_IFTYPE_DATA]) { + struct nlattr *nl_iftype; + int rem_band; + nla_for_each_nested(nl_iftype, tb_band[NL80211_BAND_ATTR_IFTYPE_DATA], rem_band) + print_he_info(nl_iftype); + } if (tb_band[NL80211_BAND_ATTR_FREQS]) { if (!band_had_freq) { printf("\t\tFrequencies:\n"); diff --git a/iw.h b/iw.h index ca8a0ff..bc0b3ac 100644 --- a/iw.h +++ b/iw.h @@ -197,6 +197,7 @@ void print_ampdu_length(__u8 exponent); void print_ampdu_spacing(__u8 spacing); void print_ht_capability(__u16 cap); void print_vht_info(__u32 capa, const __u8 *mcs); +void print_he_info(struct nlattr *nl_iftype); char *channel_width_name(enum nl80211_chan_width width); const char *iftype_name(enum nl80211_iftype iftype); diff --git a/util.c b/util.c index 2fa0b74..bb34fd3 100644 --- a/util.c +++ b/util.c @@ -1101,6 +1101,237 @@ void print_vht_info(__u32 capa, const __u8 *mcs) printf("\t\tVHT TX highest supported: %d Mbps\n", tmp & 0x1fff); } +void print_he_info(struct nlattr *nl_iftype) +{ + struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1]; + struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1]; + char *iftypes[NUM_NL80211_IFTYPES] = { + "Unspec", "Adhoc", "Station", "AP", "AP/VLAN", "WDS", "Monitor", + "Mesh", "P2P/Client", "P2P/Go", "P2P/Device", "OCB", "NAN", + }; + __u16 mac_cap[3] = { 0 }; + __u16 phy_cap[6] = { 0 }; + __u16 mcs_set[6] = { 0 }; + __u8 ppet[25] = { 0 }; + size_t len; + int i; + + #define PRINT_HE_CAP(_var, _idx, _bit, _str) \ + do { \ + if (_var[_idx] & BIT(_bit)) \ + printf("\t\t\t\t" _str "\n"); \ + } while (0) + + #define PRINT_HE_CAP_MASK(_var, _idx, _shift, _mask, _str) \ + do { \ + if ((_var[_idx] >> _shift) & _mask) \ + printf("\t\t\t\t" _str ": %d\n", (_var[_idx] >> _shift) & _mask); \ + } while (0) + + #define PRINT_HE_MAC_CAP(...) PRINT_HE_CAP(mac_cap, __VA_ARGS__) + #define PRINT_HE_MAC_CAP_MASK(...) PRINT_HE_CAP_MASK(mac_cap, __VA_ARGS__) + #define PRINT_HE_PHY_CAP(...) PRINT_HE_CAP(phy_cap, __VA_ARGS__) + #define PRINT_HE_PHY_CAP0(_idx, _bit, ...) PRINT_HE_CAP(phy_cap, _idx, _bit + 8, __VA_ARGS__) + #define PRINT_HE_PHY_CAP_MASK(...) PRINT_HE_CAP_MASK(phy_cap, __VA_ARGS__) + + nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX, + nla_data(nl_iftype), nla_len(nl_iftype), NULL); + + if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES]) + return; + + if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX, + tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL)) + return; + + printf("\t\tHE Iftypes:"); + for (i = 0; i < NUM_NL80211_IFTYPES; i++) + if (nla_get_flag(tb_flags[i]) && iftypes[i]) + printf(" %s", iftypes[i]); + printf("\n"); + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]); + if (len > sizeof(mac_cap)) + len = sizeof(mac_cap); + memcpy(mac_cap, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]), + len); + } + printf("\t\t\tHE MAC Capabilities (0x"); + for (i = 0; i < 3; i++) + printf("%04x", mac_cap[i]); + printf("):\n"); + + PRINT_HE_MAC_CAP(0, 0, "+HTC HE Supported"); + PRINT_HE_MAC_CAP(0, 1, "TWT Requester"); + PRINT_HE_MAC_CAP(0, 2, "TWT Responder"); + PRINT_HE_MAC_CAP_MASK(0, 3, 0x3, "Dynamic BA Fragmentation Level"); + PRINT_HE_MAC_CAP_MASK(0, 5, 0x7, "Maximum number of MSDUS Fragments"); + PRINT_HE_MAC_CAP_MASK(0, 8, 0x3, "Minimum Payload size of 128 bytes"); + PRINT_HE_MAC_CAP_MASK(0, 10, 0x3, "Trigger Frame MAC Padding Duration"); + PRINT_HE_MAC_CAP_MASK(0, 12, 0x7, "Multi-TID Aggregation Support"); + + PRINT_HE_MAC_CAP(1, 1, "All Ack"); + PRINT_HE_MAC_CAP(1, 2, "TRS"); + PRINT_HE_MAC_CAP(1, 3, "BSR"); + PRINT_HE_MAC_CAP(1, 4, "Broadcast TWT"); + PRINT_HE_MAC_CAP(1, 5, "32-bit BA Bitmap"); + PRINT_HE_MAC_CAP(1, 6, "MU Cascading"); + PRINT_HE_MAC_CAP(1, 7, "Ack-Enabled Aggregation"); + PRINT_HE_MAC_CAP(1, 9, "OM Control"); + PRINT_HE_MAC_CAP(1, 10, "OFDMA RA"); + PRINT_HE_MAC_CAP_MASK(1, 11, 0x3, "Maximum A-MPDU Length Exponent"); + PRINT_HE_MAC_CAP(1, 13, "A-MSDU Fragmentation"); + PRINT_HE_MAC_CAP(1, 14, "Flexible TWT Scheduling"); + PRINT_HE_MAC_CAP(1, 15, "RX Control Frame to MultiBSS"); + + PRINT_HE_MAC_CAP(2, 0, "BSRP BQRP A-MPDU Aggregation"); + PRINT_HE_MAC_CAP(2, 1, "QTP"); + PRINT_HE_MAC_CAP(2, 2, "BQR"); + PRINT_HE_MAC_CAP(2, 3, "SRP Responder Role"); + PRINT_HE_MAC_CAP(2, 4, "NDP Feedback Report"); + PRINT_HE_MAC_CAP(2, 5, "OPS"); + PRINT_HE_MAC_CAP(2, 6, "A-MSDU in A-MPDU"); + PRINT_HE_MAC_CAP_MASK(2, 7, 7, "Multi-TID Aggregation TX"); + PRINT_HE_MAC_CAP(2, 10, "HE Subchannel Selective Transmission"); + PRINT_HE_MAC_CAP(2, 11, "UL 2x996-Tone RU"); + PRINT_HE_MAC_CAP(2, 12, "OM Control UL MU Data Disable RX"); + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); + + if (len > sizeof(phy_cap) - 1) + len = sizeof(phy_cap) - 1; + memcpy(&((__u8 *)phy_cap)[1], + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]), + len); + } + printf("\t\t\tHE PHY Capabilities: (0x"); + for (i = 0; i < 11; i++) + printf("%02x", ((__u8 *)phy_cap)[i + 1]); + printf("):\n"); + + PRINT_HE_PHY_CAP0(0, 1, "HE40/2.4GHz"); + PRINT_HE_PHY_CAP0(0, 2, "HE40/HE80/5GHz"); + PRINT_HE_PHY_CAP0(0, 3, "HE160/5GHz"); + PRINT_HE_PHY_CAP0(0, 4, "HE160/HE80+80/5GHz"); + PRINT_HE_PHY_CAP0(0, 5, "242 tone RUs/2.4GHz"); + PRINT_HE_PHY_CAP0(0, 6, "242 tone RUs/5GHz"); + + PRINT_HE_PHY_CAP_MASK(1, 0, 0xf, "Punctured Preamble RX"); + PRINT_HE_PHY_CAP_MASK(1, 4, 0x1, "Device Class"); + PRINT_HE_PHY_CAP(1, 5, "LDPC Coding in Payload"); + PRINT_HE_PHY_CAP(1, 6, "HE SU PPDU with 1x HE-LTF and 0.8us GI"); + PRINT_HE_PHY_CAP_MASK(1, 7, 0x3, "Midamble Rx Max NSTS"); + PRINT_HE_PHY_CAP(1, 9, "NDP with 4x HE-LTF and 3.2us GI"); + PRINT_HE_PHY_CAP(1, 10, "STBC Tx <= 80MHz"); + PRINT_HE_PHY_CAP(1, 11, "STBC Rx <= 80MHz"); + PRINT_HE_PHY_CAP(1, 12, "Doppler Tx"); + PRINT_HE_PHY_CAP(1, 13, "Doppler Rx"); + PRINT_HE_PHY_CAP(1, 14, "Full Bandwidth UL MU-MIMO"); + PRINT_HE_PHY_CAP(1, 15, "Partial Bandwidth UL MU-MIMO"); + + PRINT_HE_PHY_CAP_MASK(2, 0, 0x3, "DCM Max Constellation"); + PRINT_HE_PHY_CAP_MASK(2, 2, 0x1, "DCM Max NSS Tx"); + PRINT_HE_PHY_CAP_MASK(2, 3, 0x3, "DCM Max Constellation Rx"); + PRINT_HE_PHY_CAP_MASK(2, 5, 0x1, "DCM Max NSS Rx"); + PRINT_HE_PHY_CAP(2, 6, "Rx HE MU PPDU from Non-AP STA"); + PRINT_HE_PHY_CAP(2, 7, "SU Beamformer"); + PRINT_HE_PHY_CAP(2, 8, "SU Beamformee"); + PRINT_HE_PHY_CAP(2, 9, "MU Beamformer"); + PRINT_HE_PHY_CAP_MASK(2, 10, 0x7, "Beamformee STS <= 80Mhz"); + PRINT_HE_PHY_CAP_MASK(2, 13, 0x7, "Beamformee STS > 80Mhz"); + + PRINT_HE_PHY_CAP_MASK(3, 0, 0x7, "Sounding Dimensions <= 80Mhz"); + PRINT_HE_PHY_CAP_MASK(3, 3, 0x7, "Sounding Dimensions > 80Mhz"); + PRINT_HE_PHY_CAP(3, 6, "Ng = 16 SU Feedback"); + PRINT_HE_PHY_CAP(3, 7, "Ng = 16 MU Feedback"); + PRINT_HE_PHY_CAP(3, 8, "Codebook Size SU Feedback"); + PRINT_HE_PHY_CAP(3, 9, "Codebook Size MU Feedback"); + PRINT_HE_PHY_CAP(3, 10, "Triggered SU Beamforming Feedback"); + PRINT_HE_PHY_CAP(3, 11, "Triggered MU Beamforming Feedback"); + PRINT_HE_PHY_CAP(3, 12, "Triggered CQI Feedback"); + PRINT_HE_PHY_CAP(3, 13, "Partial Bandwidth Extended Range"); + PRINT_HE_PHY_CAP(3, 14, "Partial Bandwidth DL MU-MIMO"); + PRINT_HE_PHY_CAP(3, 15, "PPE Threshold Present"); + + PRINT_HE_PHY_CAP(4, 0, "SRP-based SR"); + PRINT_HE_PHY_CAP(4, 1, "Power Boost Factor ar"); + PRINT_HE_PHY_CAP(4, 2, "HE SU PPDU & HE PPDU 4x HE-LTF 0.8us GI"); + PRINT_HE_PHY_CAP_MASK(4, 3, 0x7, "Max NC"); + PRINT_HE_PHY_CAP(4, 6, "STBC Tx > 80MHz"); + PRINT_HE_PHY_CAP(4, 7, "STBC Rx > 80MHz"); + PRINT_HE_PHY_CAP(4, 8, "HE ER SU PPDU 4x HE-LTF 0.8us GI"); + PRINT_HE_PHY_CAP(4, 9, "20MHz in 40MHz HE PPDU 2.4GHz"); + PRINT_HE_PHY_CAP(4, 10, "20MHz in 160/80+80MHz HE PPDU"); + PRINT_HE_PHY_CAP(4, 11, "80MHz in 160/80+80MHz HE PPDU"); + PRINT_HE_PHY_CAP(4, 12, "HE ER SU PPDU 1x HE-LTF 0.8us GI"); + PRINT_HE_PHY_CAP(4, 13, "Midamble Rx 2x & 1x HE-LTF"); + PRINT_HE_PHY_CAP_MASK(4, 14, 0x3, "DCM Max BW"); + + PRINT_HE_PHY_CAP(5, 0, "Longer Than 16HE SIG-B OFDM Symbols"); + PRINT_HE_PHY_CAP(5, 1, "Non-Triggered CQI Feedback"); + PRINT_HE_PHY_CAP(5, 2, "TX 1024-QAM"); + PRINT_HE_PHY_CAP(5, 3, "RX 1024-QAM"); + PRINT_HE_PHY_CAP(5, 4, "RX Full BW SU Using HE MU PPDU with Compression SIGB"); + PRINT_HE_PHY_CAP(5, 5, "RX Full BW SU Using HE MU PPDU with Non-Compression SIGB"); + + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]); + if (len > sizeof(mcs_set)) + len = sizeof(mcs_set); + memcpy(mcs_set, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]), + len); + } + + for (i = 0; i < 3; i++) { + __u8 phy_cap_support[] = { BIT(1) | BIT(2), BIT(3), BIT(4) }; + char *bw[] = { "<= 80", "160", "80+80" }; + int j; + + if ((phy_cap[0] & (phy_cap_support[i] << 8)) == 0) + continue; + + for (j = 0; j < 2; j++) { + int k; + printf("\t\t\tHE %s MCS and NSS set %s MHz\n", j ? "TX" : "RX", bw[i]); + for (k = 0; k < 8; k++) { + __u16 mcs = mcs_set[(i * 2) + j]; + mcs >>= k * 2; + mcs &= 0x3; + printf("\t\t\t\t\t %d streams: ", k + 1); + if (mcs == 3) + printf("not supported\n"); + else + printf("MCS 0-%d\n", 7 + (mcs * 2)); + } + + } + } + + len = 0; + if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]); + if (len > sizeof(ppet)) + len = sizeof(ppet); + memcpy(ppet, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]), + len); + } + + if (len && (phy_cap[3] & BIT(15))) { + size_t i; + + printf("\t\t\tPPE Threshold "); + for (i = 0; i < len; i++) + if (ppet[i]) + printf("0x%02x ", ppet[i]); + printf("\n"); + } +} + void iw_hexdump(const char *prefix, const __u8 *buf, size_t size) { size_t i; -- 2.20.1