]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Add support to send CW change notification
authorVignesh C <quic_vignc@quicinc.com>
Thu, 2 Nov 2023 07:36:56 +0000 (13:06 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 3 Nov 2023 14:19:11 +0000 (16:19 +0200)
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>
hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/common/ieee802_11_defs.h

index f90eb22c45b4bbb5c1bd0f188617ff649a606a71..83efdee156e6235decf8076cfbbb26d57c108be0 100644 (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,
                                  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);
index 646dfc598b382402af0989500c296f1d5c7aeb44..01fe34fa04910f7ff09b1eca0603fa3fe926d3ae 100644 (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,
                                      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" },
index 805a4024f32a17782743e3e81b9da027dab29ebf..110f2b1e1b8326be75eecbce8a9eb54fac9973ce 100644 (file)
 #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