hostapd: Add support to send CW change notification

Add hostapd_cli command to notify channel width change to all
associated STAs.

Notify Channel Width frame for HT STAs.
(IEEE P802.11-REVme/D4.0, 9.6.11.2)

Operating Mode Notification frame for VHT STAs.
(IEEE P802.11-REVme/D4.0, 9.6.22.4)

Usage: hostapd_cli notify_cw_change <channel_width>
<channel_width> = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz.

Co-developed-by: Bhagavathi Perumal S <quic_bperumal@quicinc.com>
Signed-off-by: Bhagavathi Perumal S <quic_bperumal@quicinc.com>
Signed-off-by: Vignesh C <quic_vignc@quicinc.com>
This commit is contained in:
Vignesh C 2023-11-02 13:06:56 +05:30 committed by Jouni Malinen
parent 835479b3d6
commit 41a60f6586
3 changed files with 178 additions and 0 deletions

View file

@ -2715,6 +2715,155 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
} }
static u8 hostapd_maxnss(struct hostapd_data *hapd, struct sta_info *sta)
{
u8 *mcs_set = NULL;
u16 mcs_map;
u8 ht_rx_nss = 0;
u8 vht_rx_nss = 1;
u8 mcs;
bool ht_supported = false;
bool vht_supported = false;
int i;
if (sta->ht_capabilities && (sta->flags & WLAN_STA_HT)) {
mcs_set = sta->ht_capabilities->supported_mcs_set;
ht_supported = true;
}
if (sta->vht_capabilities && (sta->flags & WLAN_STA_VHT)) {
mcs_map = le_to_host16(
sta->vht_capabilities->vht_supported_mcs_set.rx_map);
vht_supported = true;
}
if (ht_supported && mcs_set) {
if (mcs_set[0])
ht_rx_nss++;
if (mcs_set[1])
ht_rx_nss++;
if (mcs_set[2])
ht_rx_nss++;
if (mcs_set[3])
ht_rx_nss++;
}
if (vht_supported) {
for (i = 7; i >= 0; i--) {
mcs = (mcs_map >> (2 * i)) & 0x03;
if (mcs != 0x03) {
vht_rx_nss = i + 1;
break;
}
}
}
return ht_rx_nss > vht_rx_nss ? ht_rx_nss : vht_rx_nss;
}
static char hostapd_ctrl_iface_notify_cw_htaction(struct hostapd_data *hapd,
const u8 *addr, u8 width)
{
u8 buf[3];
char ret;
width = width >= 1 ? 1 : 0;
buf[0] = WLAN_ACTION_HT;
buf[1] = WLAN_HT_ACTION_NOTIFY_CHANWIDTH;
buf[2] = width;
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
buf, sizeof(buf));
if (ret)
wpa_printf(MSG_DEBUG,
"Failed to send Notify Channel Width frame to "
MACSTR, MAC2STR(addr));
return ret;
}
static char hostapd_ctrl_iface_notify_cw_vhtaction(struct hostapd_data *hapd,
const u8 *addr, u8 width)
{
u8 buf[3];
char ret;
buf[0] = WLAN_ACTION_VHT;
buf[1] = WLAN_VHT_ACTION_OPMODE_NOTIF;
buf[2] = width;
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
buf, sizeof(buf));
if (ret)
wpa_printf(MSG_DEBUG,
"Failed to send Opeating Mode Notification frame to "
MACSTR, MAC2STR(addr));
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->current_mode->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.4 GHz 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;
hostapd_ctrl_iface_notify_cw_vhtaction(hapd, sta->addr,
operating_mode |
(u8) (nss << 4));
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, static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
int reply_size, const char *param) int reply_size, const char *param)
{ {
@ -3561,6 +3710,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
reply_len = -1; reply_len = -1;
} 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, "VENDOR ", 7) == 0) { } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply, reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
reply_size); reply_size);

View file

@ -1207,6 +1207,13 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
} }
static int hostapd_cli_cmd_notify_cw_change(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
return hostapd_cli_cmd(ctrl, "NOTIFY_CW_CHANGE", 1, argc, argv);
}
static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc, static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
char *argv[]) char *argv[])
{ {
@ -1679,6 +1686,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n" "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
" [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n" " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
" = initiate channel switch announcement" }, " = initiate channel switch announcement" },
{ "notify_cw_change", hostapd_cli_cmd_notify_cw_change, NULL,
"<channel_width> = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz" },
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
"<addr> <url>\n" "<addr> <url>\n"
" = send WNM-Notification Subscription Remediation Request" }, " = send WNM-Notification Subscription Remediation Request" },

View file

@ -678,6 +678,19 @@
#define WLAN_PA_FILS_DISCOVERY 34 #define WLAN_PA_FILS_DISCOVERY 34
#define WLAN_PA_LOCATION_MEASUREMENT_REPORT 47 #define WLAN_PA_LOCATION_MEASUREMENT_REPORT 47
/* HT Action field values (IEEE P802.11-REVme/D4.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/D4.0, 9.6.22.1, Table 9-579) */
#define WLAN_VHT_ACTION_COMPRESSED_BF 0
#define WLAN_VHT_ACTION_GROUP_ID_MGMT 1
#define WLAN_VHT_ACTION_OPMODE_NOTIF 2
/* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11, /* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11,
* Table 9-332) */ * Table 9-332) */
#define WLAN_PROT_DSE_ENABLEMENT 1 #define WLAN_PROT_DSE_ENABLEMENT 1
@ -1357,6 +1370,10 @@ struct ieee80211_ampe_ie {
#define VHT_RX_NSS_MAX_STREAMS 8 #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 */ /* VHT operation information - channel widths */
#define CHANWIDTH_USE_HT 0 #define CHANWIDTH_USE_HT 0
#define CHANWIDTH_80MHZ 1 #define CHANWIDTH_80MHZ 1