No change in "Supported Channel Width" output format when extended NSS is not supported. Sample output for a PHY with 1/2 NSS ratio: VHT Capabilities (0xb39b79f2): Max MPDU length: 11454 Supported Channel Width: 160Mhz (1/2 NSS) 80+80Mhz (1/2 NSS) [...] VHT extended NSS: supported Signed-off-by: Maxime Bizon <mbizon@xxxxxxxxxx> --- util.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 5 deletions(-) diff --git a/util.c b/util.c index f8ab6ca..8a2ba10 100644 --- a/util.c +++ b/util.c @@ -922,9 +922,159 @@ void print_ht_mcs(const __u8 *mcs) } } +struct vht_nss_ratio { + bool valid; + int bw_20; + int bw_40; + int bw_80; + int bw_160; + int bw_80_80; +}; + +/* + * indexed by [chan_width][ext_nss_bw], ratio in 1/4 unit + */ +static const struct vht_nss_ratio nss_ratio_tbl[3][4] = { + { + /* chan_width == 0, ext_nss_bw == 0 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + }, + /* chan_width == 0, ext_nss_bw == 1 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + .bw_160 = 2, + }, + /* chan_width == 0, ext_nss_bw == 2 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + .bw_160 = 2, + .bw_80_80 = 2, + }, + /* chan_width == 0, ext_nss_bw == 3 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + .bw_160 = 3, + .bw_80_80 = 3, + }, + }, + { + /* chan_width == 1, ext_nss_bw == 0 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + .bw_160 = 4, + }, + /* chan_width == 1, ext_nss_bw == 1 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + .bw_160 = 4, + .bw_80_80 = 2, + }, + /* chan_width == 1, ext_nss_bw == 2 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + .bw_160 = 4, + .bw_80_80 = 3, + }, + /* chan_width == 1, ext_nss_bw == 3 */ + { + .valid = true, + .bw_20 = 8, + .bw_40 = 8, + .bw_80 = 8, + .bw_160 = 8, + .bw_80_80 = 1, + }, + }, + { + /* chan_width == 2, ext_nss_bw == 0 */ + { + .valid = true, + .bw_20 = 4, + .bw_40 = 4, + .bw_80 = 4, + .bw_160 = 4, + .bw_80_80 = 4, + }, + /* chan_width == 2, ext_nss_bw == 1 */ + {}, + /* chan_width == 2, ext_nss_bw == 2 */ + {}, + /* chan_width == 2, ext_nss_bw == 3 */ + { + .valid = true, + .bw_20 = 8, + .bw_40 = 8, + .bw_80 = 8, + .bw_160 = 4, + .bw_80_80 = 4, + }, + }, +}; + +static void print_nss_ratio_value(int ratio) +{ + const char *rstr; + + switch (ratio) { + case 4: + return; + case 3: + rstr = "3/4"; + break; + case 2: + rstr = "1/2"; + break; + case 8: + rstr = "x2"; + break; + default: + rstr = "undef"; + break; + } + + printf("(%s NSS) ", rstr); +} + +static void print_nss_ratio(const char *str, bool force_show, int ratio) +{ + if (!ratio) + return; + if (ratio == 4) { + if (force_show) + printf("%s ", str); + } else { + printf("%s ", str); + print_nss_ratio_value(ratio); + } +} + void print_vht_info(__u32 capa, const __u8 *mcs) { __u16 tmp; + __u32 supp_chan_width, ext_nss_bw; + const struct vht_nss_ratio *nss_tbl; int i; printf("\t\tVHT Capabilities (0x%.8x):\n", capa); @@ -942,13 +1092,34 @@ void print_vht_info(__u32 capa, const __u8 *mcs) case 2: printf("11454\n"); break; case 3: printf("(reserved)\n"); } + printf("\t\t\tSupported Channel Width: "); - switch ((capa >> 2) & 3) { - case 0: printf("neither 160 nor 80+80\n"); break; - case 1: printf("160 MHz\n"); break; - case 2: printf("160 MHz, 80+80 MHz\n"); break; - case 3: printf("(reserved)\n"); + supp_chan_width = (capa >> 2) & 3; + ext_nss_bw = (capa >> 30) & 3; + nss_tbl = &nss_ratio_tbl[supp_chan_width][ext_nss_bw]; + + if (!nss_tbl->valid) + printf("(reserved)\n"); + else if (nss_tbl->bw_20 == 4 && + nss_tbl->bw_40 == 4 && + nss_tbl->bw_80 == 4 && + (!nss_tbl->bw_160 || nss_tbl->bw_160 == 4) && + (!nss_tbl->bw_80_80 || nss_tbl->bw_80_80 == 4)) { + /* old style print format */ + switch (supp_chan_width) { + case 0: printf("neither 160 nor 80+80\n"); break; + case 1: printf("160 MHz\n"); break; + case 2: printf("160 MHz, 80+80 MHz\n"); break; + } + } else { + print_nss_ratio("20Mhz", false, nss_tbl->bw_20); + print_nss_ratio("40Mhz", false, nss_tbl->bw_40); + print_nss_ratio("80Mhz", false, nss_tbl->bw_80); + print_nss_ratio("160Mhz", false, nss_tbl->bw_160); + print_nss_ratio("80+80Mhz", false, nss_tbl->bw_80_80); + printf("\n"); } + PRINT_VHT_CAPA(4, "RX LDPC"); PRINT_VHT_CAPA(5, "short GI (80 MHz)"); PRINT_VHT_CAPA(6, "short GI (160/80+80 MHz)"); @@ -994,6 +1165,9 @@ void print_vht_info(__u32 capa, const __u8 *mcs) } tmp = mcs[6] | (mcs[7] << 8); printf("\t\tVHT TX highest supported: %d Mbps\n", tmp & 0x1fff); + + printf("\t\tVHT extended NSS: %ssupported\n", + (tmp & (1 << 13)) ? "" : "not "); } static void __print_he_capa(const __u16 *mac_cap, -- 2.17.1