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:
parent
835479b3d6
commit
41a60f6586
3 changed files with 178 additions and 0 deletions
|
@ -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,
|
||||
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) {
|
||||
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
|
||||
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) {
|
||||
reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
|
||||
reply_size);
|
||||
|
|
|
@ -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,
|
||||
char *argv[])
|
||||
{
|
||||
|
@ -1679,6 +1686,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
|||
"<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
|
||||
" [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
|
||||
" = 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,
|
||||
"<addr> <url>\n"
|
||||
" = send WNM-Notification Subscription Remediation Request" },
|
||||
|
|
|
@ -678,6 +678,19 @@
|
|||
#define WLAN_PA_FILS_DISCOVERY 34
|
||||
#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,
|
||||
* Table 9-332) */
|
||||
#define WLAN_PROT_DSE_ENABLEMENT 1
|
||||
|
@ -1357,6 +1370,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
|
||||
|
|
Loading…
Reference in a new issue