From 6cbf57cd8899d8a531706c9f85393f602cd08219 Mon Sep 17 00:00:00 2001
From: Hari Chandrakanthan <haric@codeaurora.org>
Date: Tue, 4 May 2021 12:35:55 +0530
Subject: [PATCH] hostapd cli cmd to display allowed bw on each channel

Signed-off-by: Hari Chandrakanthan <haric@codeaurora.org>
---
 hostapd/ctrl_iface.c  | 235 ++++++++++++++++++++++++++++++++++++++------------
 hostapd/hostapd_cli.c |  10 +--
 2 files changed, 185 insertions(+), 60 deletions(-)

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index bbe49aa..ea1a156 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -3215,75 +3215,202 @@ set:
 	return ret;
 }
 
-static int hostapd_2ghz_ht40_allow_map(struct hostapd_hw_modes *mode,
-				       char *buf, size_t buflen)
+static int hostapd_2ghz_channel_bw(struct hostapd_hw_modes *mode, char *buf,
+				   size_t buflen)
 {
-	int j, ret, len = 0;
+	int ch, ret, len = 0;
+	char temp_buf[30] = {0};
 
-	for (j = 0; j < mode->num_channels; j++) {
-		struct hostapd_channel_data *chan = &mode->channels[j];
-		if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
-			ret = os_snprintf(buf + len, buflen - len,
-					  "Channel: %d : %d HT40%c%c\n",
-					  chan->chan, chan->freq,
-					  (chan->flag & HOSTAPD_CHAN_HT40MINUS) ?
-						'-' : ' ',
-					  (chan->flag & HOSTAPD_CHAN_HT40PLUS) ?
-						'+' : ' ');
-			if (os_snprintf_error(buflen - len, ret))
-				return len;
-			len += ret;
-		}
+	for (ch = 0; ch < mode->num_channels; ch++) {
+		struct hostapd_channel_data *chan = &mode->channels[ch];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		ret = os_snprintf(temp_buf, 30, "Channel[%d]", chan->chan);
+		if (os_snprintf_error(30, ret))
+			return len;
+		ret = os_snprintf(buf + len, buflen - len,
+				  "%-13s : %d - 20MHz HT40%c%c\n",
+				  temp_buf, chan->freq,
+				  (chan->flag & HOSTAPD_CHAN_HT40MINUS)?'-':' ',
+				  (chan->flag & HOSTAPD_CHAN_HT40PLUS)?'+':' ');
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
 	}
 	return len;
 }
 
-static int hostapd_5ghz_ht40_allow_map(struct hostapd_hw_modes *mode,
-				       char *buf, size_t buflen)
+static int hostapd_get_channel_idx(struct hostapd_hw_modes *mode,
+				   int channel_num)
 {
-	int j, k, ok, ret, len = 0, allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
-						149, 157, 184, 192 };
+	int  j=0;
 
-	for (j = 0; j < mode->num_channels; j++) {
+	for(j = 0; j < mode->num_channels; j++) {
 		struct hostapd_channel_data *chan = &mode->channels[j];
+		if(chan->chan == channel_num)
+			return j;
+	}
+	return -1;
+}
 
-		if ((chan->flag & HOSTAPD_CHAN_HT40MINUS) ||
-				(chan->flag & HOSTAPD_CHAN_HT40PLUS)) {
-			ok = 0;
-			for (k = 0; k < ARRAY_SIZE(allowed); k++) {
-				if (chan->chan < allowed[k])
-					break;
-				if (chan->chan == allowed[k]) {
-					ok = 1;
-					break;
-				}
+static int hostapd_5ghz_vht_80_channel_bw(struct hostapd_hw_modes *mode,
+					  int channel_idx)
+{
+	int k, m, ok, allowed[][4] = {{36, 40, 44, 48}, {52, 56, 60, 64},
+				      {100, 104, 108, 112}, {116, 120, 124, 128},
+				      {132, 136, 140, 144}, {149, 153, 157, 161}};
+	struct hostapd_channel_data *chan = &mode->channels[channel_idx];
+
+	ok = 0;
+	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
+		for(m = 0; m < ARRAY_SIZE(allowed[0]); m++) {
+			if (chan->chan == allowed[k][m]) {
+				ok = 1;
+				break;
 			}
+		}
+		if(ok == 1)
+			break;
+	}
 
-			if (!ok && chan->chan != (allowed[k - 1] + 4))
-				ok = -1;
-
-			if (ok == 1 && (mode->channels[j + 1].flag &
-					HOSTAPD_CHAN_DISABLED))
-				ok = -1;
+	if (ok == 0)
+		return false;
 
-			if (ok != -1) {
-				ret = os_snprintf(buf + len, buflen - len,
-						  "Channel: %d : %d HT40%s\n",
-						  chan->chan, chan->freq,
-						  ok == 1 ? "+" : "-");
+	for(m = 0; m < ARRAY_SIZE(allowed[0]); m++) {
+		channel_idx = hostapd_get_channel_idx(mode, allowed[k][m]);
+		if((channel_idx == -1) || (mode->channels[channel_idx].flag &
+		   HOSTAPD_CHAN_DISABLED))
+			return false;
+	}
 
-				if (os_snprintf_error(buflen - len, ret))
-					return len;
+	return true;
+}
 
-				len += ret;
+static bool hostapd_5ghz_vht_160_channel_bw(struct hostapd_hw_modes *mode,
+					    int channel_idx)
+{
+	int k, m, ok, allowed[][8] = {{36, 40, 44, 48, 52, 56, 60, 64},
+				      {100, 104, 108, 112, 116, 120, 124, 128}};
+	struct hostapd_channel_data *chan = &mode->channels[channel_idx];
+
+	ok = 0;
+	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
+		for(m = 0; m < ARRAY_SIZE(allowed[0]); m++) {
+			if (chan->chan == allowed[k][m]) {
+				ok = 1;
+				break;
 			}
 		}
+		if(ok == 1)
+			break;
+	}
+
+	if (ok == 0)
+		return false;
+
+	for(m = 0; m < ARRAY_SIZE(allowed[0]); m++) {
+		channel_idx = hostapd_get_channel_idx(mode, allowed[k][m]);
+		if (channel_idx == -1 || (mode->channels[channel_idx].flag &
+		    HOSTAPD_CHAN_DISABLED))
+			return false;
+	}
+	return true;
+}
+
+static int hostapd_5ghz_ht_40_channel_bw(struct hostapd_hw_modes *mode,
+					 int channel_idx)
+{
+
+	int  k, ok, allowed[] = {36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
+				 149, 157, 184, 192};
+	struct hostapd_channel_data *chan = &mode->channels[channel_idx];
+
+	if (!((chan->flag & HOSTAPD_CHAN_HT40MINUS) ||
+	    (chan->flag & HOSTAPD_CHAN_HT40PLUS)))
+		return 0;
+
+	ok = 0;
+	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
+		if (chan->chan < allowed[k])
+			break;
+		if (chan->chan == allowed[k]) {
+			ok = 1;
+			break;
+		}
+	}
+
+	if (!ok && chan->chan != (allowed[k - 1] + 4))
+		ok = -1;
+
+	if (ok == 1 && (mode->channels[channel_idx + 1].flag &
+	    HOSTAPD_CHAN_DISABLED))
+		ok = -1;
+
+	if (ok != -1) {
+		if( ok == 1)
+			return HOSTAPD_CHAN_HT40PLUS;
+		else
+			return HOSTAPD_CHAN_HT40MINUS;
+	}
+	return 0;
+}
+
+static int hostapd_5ghz_channel_bw(struct hostapd_hw_modes *mode,
+				   char *buf, size_t buflen)
+{
+	int j, ret, ret_val, len = 0;
+	char temp_buf[30] = {0};
+
+	for (j = 0; j < mode->num_channels; j++) {
+		struct hostapd_channel_data *chan = &mode->channels[j];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+
+		ret = os_snprintf(temp_buf, 30, "Channel[%d]", chan->chan);
+		if (os_snprintf_error(30, ret))
+			return len;
+
+		ret = os_snprintf(buf + len, buflen - len, "%-13s : %d - 20MHz ",
+				  temp_buf, chan->freq);
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+
+		ret_val = hostapd_5ghz_ht_40_channel_bw(mode, j);
+		if(ret_val) {
+			ret = os_snprintf(buf + len, buflen - len, "HT40%s ",
+					  ret_val == HOSTAPD_CHAN_HT40PLUS? "+":"-");
+			if (os_snprintf_error(buflen - len, ret))
+				return len;
+			len += ret;
+		}
+
+		if(hostapd_5ghz_vht_80_channel_bw(mode, j)) {
+			ret = os_snprintf(buf + len, buflen - len, "80MHz ");
+			if (os_snprintf_error(buflen - len, ret))
+				return len;
+			len += ret;
+		}
+
+		if((mode->vht_capab & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+		   VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) &&
+		   hostapd_5ghz_vht_160_channel_bw(mode, j)) {
+			ret = os_snprintf(buf + len, buflen - len, "160MHz ");
+			if (os_snprintf_error(buflen - len, ret))
+				return len;
+			len += ret;
+		}
+
+		ret = os_snprintf(buf + len, buflen - len,"\n");
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
 	}
 	return len;
 }
 
-static int hostapd_ctrl_iface_ht40_allow_map(struct hostapd_iface *iface,
-					     char *buf, size_t buflen)
+static int hostapd_ctrl_iface_channel_bw(struct hostapd_iface *iface,
+					 char *buf, size_t buflen)
 {
 	struct hostapd_data *hapd = iface->bss[0];
 	struct hostapd_hw_modes *mode;
@@ -3295,11 +3422,12 @@ static int hostapd_ctrl_iface_ht40_allow_map(struct hostapd_iface *iface,
 					   &dfs_domain);
 
 	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
-		len = hostapd_2ghz_ht40_allow_map(mode, buf, buflen);
+		len = hostapd_2ghz_channel_bw(mode, buf, buflen);
 	else
-		len = hostapd_5ghz_ht40_allow_map(mode, buf, buflen);
+		len = hostapd_5ghz_channel_bw(mode, buf, buflen);
 
 	return len;
+
 }
 
 static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
@@ -3912,10 +4040,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
 		if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
 			reply_len = -1;
 #endif /* RADIUS_SERVER */
-	} else if (os_strcmp(buf, "HT40_ALLOW_MAP") == 0) {
-		reply_len = hostapd_ctrl_iface_ht40_allow_map(hapd->iface,
-							      reply,
-							      reply_size);
+	} else if(os_strcmp(buf, "CHANNEL_BW") == 0) {
+		reply_len = hostapd_ctrl_iface_channel_bw(hapd->iface, reply,
+							  reply_size);
 	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
 		reply_len = hostapd_ctrl_iface_get_capability(
 			hapd, buf + 15, reply, reply_size);
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 6ee8d96..14317f5 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1384,13 +1384,11 @@ static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
 	return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
 }
 
-static int hostapd_cli_cmd_ht40_allow_map(struct wpa_ctrl *ctrl,
+static int hostapd_cli_cmd_channel_bw(struct wpa_ctrl *ctrl,
 					  int argc, char *argv[])
 {
-	return wpa_ctrl_command(ctrl, "HT40_ALLOW_MAP");
+	return wpa_ctrl_command(ctrl, "CHANNEL_BW");
 }
-
-
 #ifdef CONFIG_DPP
 
 static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
@@ -1753,8 +1751,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
 	  "=Add/Delete/Show/Clear deny MAC ACL" },
 	{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
 	  "<addr> = poll a STA to check connectivity with a QoS null frame" },
-	{ "ht40_allow_map", hostapd_cli_cmd_ht40_allow_map, NULL,
-	  "= show ht40 allow map status" },
+	{ "channel_bw", hostapd_cli_cmd_channel_bw, NULL,
+	  "= show allowed bandwidth on each channel"},
 	{ "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
 	  "<addr> [req_mode=] <measurement request hexdump>  = send a Beacon report request to a station" },
 	{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
-- 
2.7.4

