From bf7907effe890365697d81fb04f4277859c54405 Mon Sep 17 00:00:00 2001 From: Vignesh C Date: Sun, 20 Aug 2023 21:59:28 +0530 Subject: [PATCH] hostapd: Add support to send CW change notification Add hostapd_cli command to notify channel width change to all associated STA's. Notify Channel Width action frame for HT STA's. Spec:(IEEE P802.11-REVme/D3.0 - 9.6.11.2) Operating Mode Notification action frame for VHT STA's. Spec:(IEEE P802.11-REVme/D3.0 - 9.6.22.4) Usage: hostapd_cli notify_cw_change = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz. Signed-off-by: Vignesh C --- hostapd/ctrl_iface.c | 114 +++++++++++++++++++++++++++++++++++ hostapd/hostapd_cli.c | 19 ++++++ src/ap/ctrl_iface_ap.c | 2 +- src/ap/ctrl_iface_ap.h | 1 + src/common/ieee802_11_defs.h | 17 ++++++ 5 files changed, 152 insertions(+), 1 deletion(-) --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2915,6 +2915,117 @@ static int hostapd_ctrl_iface_chan_switc } +static char hostapd_ctrl_iface_notify_cw_htaction(struct hostapd_data *hapd, + const u8 *addr, u8 width) +{ + struct wpabuf *buf; + char ret; + + + buf = wpabuf_alloc(3); + if (buf == NULL) + return -1; + + width = width >=1 ? 1: 0; + + wpabuf_put_u8(buf, WLAN_ACTION_HT); + wpabuf_put_u8(buf, WLAN_HT_ACTION_NOTIFY_CHANWIDTH); + wpabuf_put_u8(buf, width); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + if (ret) + wpa_printf(MSG_DEBUG, "Fail to send HT action frame"); + + wpabuf_free(buf); + return ret; +} + + +static char hostapd_ctrl_iface_notify_cw_vhtaction(struct hostapd_data *hapd, + const u8 *addr, u8 width) +{ + struct wpabuf *buf; + char ret; + + buf = wpabuf_alloc(3); + if (buf == NULL) + return -1; + wpabuf_put_u8(buf, WLAN_ACTION_VHT); + wpabuf_put_u8(buf, WLAN_VHT_ACTION_OPMODE_NOTIF); + wpabuf_put_u8(buf, width); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + if (ret) + wpa_printf(MSG_DEBUG, "Fail to send VHT action frame"); + + wpabuf_free(buf); + return ret; +} + + +static char hostapd_ctrl_iface_notify_cw_change(struct hostapd_data *hapd, + const char *cmd) +{ + u8 cw, operating_mode = 0, nss; + struct sta_info *sta; + enum hostapd_hw_mode hw_mode; + + if (is_6ghz_freq(hapd->iface->freq)) { + wpa_printf(MSG_ERROR, + "20/40 BSS coex not supported in 6 GHz"); + return -1; + } + + cw = atoi(cmd); + hw_mode = hapd->iface->hw_features->mode; + if ((hw_mode == HOSTAPD_MODE_IEEE80211G || + hw_mode == HOSTAPD_MODE_IEEE80211B) && + !(cw == 0 || cw == 1)) { + wpa_printf(MSG_ERROR, "Channel width should be either " + "20 MHz or 40 MHz for 2.4G band"); + return -1; + } + + switch (cw) { + case 0: + operating_mode = 0; + break; + case 1: + operating_mode = VHT_OPMODE_CHANNEL_40MHZ; + break; + case 2: + operating_mode = VHT_OPMODE_CHANNEL_80MHZ; + break; + case 3: + operating_mode = VHT_OPMODE_CHANNEL_160MHZ; + break; + default: + wpa_printf(MSG_ERROR, "Channel width should be between" + "0 to 3"); + return -1; + } + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) { + nss = hostapd_maxnss(hapd, sta) - 1; + operating_mode |= (u8) (nss << 4); + hostapd_ctrl_iface_notify_cw_vhtaction(hapd, + sta->addr,operating_mode); + continue; + } + + if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) == WLAN_STA_HT && + sta->ht_capabilities) + hostapd_ctrl_iface_notify_cw_htaction(hapd, + sta->addr, cw); + } + + return 0; +} + + static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply, int reply_size, const char *param) { @@ -4261,6 +4372,9 @@ static int hostapd_ctrl_iface_receive_pr if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0) reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ + } else if (os_strncmp(buf, "NOTIFY_CW_CHANGE ", 17) == 0) { + if (hostapd_ctrl_iface_notify_cw_change(hapd, buf + 17)) + reply_len = -1; } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) reply_len = -1; --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1223,6 +1223,23 @@ static int hostapd_cli_cmd_chan_switch(s return wpa_ctrl_command(ctrl, cmd); } +static int hostapd_cli_cmd_notify_cw_change(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + char buf[50]; + int res; + + if (argc < 1) { + printf("Invalid 'notify_cw_change' command - no argument given\n" + "usage: \n"); + return -1; + } + + res = os_snprintf(buf, sizeof(buf), "NOTIFY_CW_CHANGE %s", argv[0]); + if (os_snprintf_error(sizeof(buf), res)) + return -1; + return wpa_ctrl_command(ctrl, buf); +} static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc, char *argv[]) @@ -1700,6 +1717,8 @@ static const struct hostapd_cli_cmd host { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, hostapd_complete_stations, " = send QoS Map Configure frame" }, + { "notify_cw_change", hostapd_cli_cmd_notify_cw_change, NULL, + " = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz" }, { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, " [sec_channel_offset=] [center_freq1=]\n" " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n" --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -109,7 +109,7 @@ static int hostapd_get_sta_conn_time(str return ret; } -static u8 hostapd_maxnss(struct hostapd_data *hapd, struct sta_info *sta) +u8 hostapd_maxnss(struct hostapd_data *hapd, struct sta_info *sta) { u8 *mcs_set = NULL; u16 mcs_map; --- a/src/ap/ctrl_iface_ap.h +++ b/src/ap/ctrl_iface_ap.h @@ -54,4 +54,5 @@ int hostapd_ctrl_iface_acl_show_mac(stru int hostapd_disassoc_accept_mac(struct hostapd_data *hapd); int hostapd_disassoc_deny_mac(struct hostapd_data *hapd); +u8 hostapd_maxnss(struct hostapd_data *hapd, struct sta_info *sta); #endif /* CTRL_IFACE_AP_H */ --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -677,6 +677,19 @@ #define WLAN_PA_FILS_DISCOVERY 34 #define WLAN_PA_LOCATION_MEASUREMENT_REPORT 47 +/* HT action field values (IEEE P802.11-REVme/D3.0, 9.6.11.1, Table 9-491) */ +#define WLAN_HT_ACTION_NOTIFY_CHANWIDTH 0 +#define WLAN_HT_ACTION_SMPS 1 +#define WLAN_HT_ACTION_CSI 4 +#define WLAN_HT_ACTION_NONCOMPRESSED_BF 5 +#define WLAN_HT_ACTION_COMPRESSED_BF 6 +#define WLAN_HT_ACTION_ASEL_IDX_FEEDBACK 7 + +/* VHT action field values (IEEE P802.11-REVme/D3.0, 9.6.22.1, Table 9-579) */ +#define WLAN_VHT_ACTION_COMPRESSED_BF 0 +#define WLAN_VHT_ACTION_GROUPID_MGMT 1 +#define WLAN_VHT_ACTION_OPMODE_NOTIF 2 + /* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11, * Table 9-332) */ #define WLAN_PROT_DSE_ENABLEMENT 1 @@ -1358,6 +1371,10 @@ struct ieee80211_ampe_ie { #define VHT_RX_NSS_MAX_STREAMS 8 +#define VHT_OPMODE_CHANNEL_40MHZ ((u8) BIT(0)) +#define VHT_OPMODE_CHANNEL_80MHZ ((u8) BIT(1)) +#define VHT_OPMODE_CHANNEL_160MHZ ((u8) BIT(1) | BIT(2)) + /* VHT operation information - channel widths */ #define CHANWIDTH_USE_HT 0 #define CHANWIDTH_80MHZ 1