diff mbox series

iw: handle VHT extended NSS

Message ID 405f5ed2c434846f8ab2730b34288c5f649b8915.camel@freebox.fr
State New
Headers show
Series iw: handle VHT extended NSS | expand

Commit Message

Maxime Bizon May 16, 2022, 9:07 a.m. UTC
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@freebox.fr>
---
 util.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 179 insertions(+), 5 deletions(-)
diff mbox series

Patch

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,