[PATCH] AP: Avoid disabling HT/VHT/HE/EHT during CSA

Andrei Otcheretianski andrei.otcheretianski at intel.com
Thu Dec 28 06:01:04 PST 2023


From: Ilan Peer <ilan.peer at intel.com>

During CSA an AP should not disable its HT/VHT/HE/EHT capabilities
as it is not allowed by the IEEE80211 specification.

- Modify the CSA flow to preserve the current HT/VHT/HE/EHT
  capabilities allowing only to add additional ones.
- Update the DFS CSA flow to also preserve the HT/VHT/HE/EHT
  capabilities.

Modify one of the hwsim tests that verified that VHT capabilities
are disabled during CSA, to verify that they are kept.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 hostapd/ctrl_iface.c       | 34 +++++++++++++++++++++--
 src/ap/ap_config.h         | 23 ++++++----------
 src/ap/dfs.c               |  9 ++++++
 src/ap/drv_callbacks.c     | 56 +++++++++-----------------------------
 src/ap/hostapd.c           | 25 ++++++-----------
 tests/hwsim/test_ap_vht.py |  8 +++---
 6 files changed, 74 insertions(+), 81 deletions(-)

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index f9a78651ca..e654d932c7 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2603,6 +2603,26 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
 		break;
 	}
 
+	if (!settings.freq_params.ht_enabled && iface->conf->ieee80211n) {
+		wpa_printf(MSG_WARNING, "CSA: Cannot disable HT. Ignore");
+		settings.freq_params.ht_enabled = iface->conf->ieee80211n;
+	}
+
+	if (!settings.freq_params.vht_enabled && iface->conf->ieee80211ac) {
+		wpa_printf(MSG_WARNING, "CSA: Cannot disable VHT. Ignore");
+		settings.freq_params.vht_enabled = iface->conf->ieee80211ac;
+	}
+
+	if (!settings.freq_params.he_enabled && iface->conf->ieee80211ax) {
+		wpa_printf(MSG_WARNING, "CSA: Cannot disable HE. Ignore");
+		settings.freq_params.he_enabled = iface->conf->ieee80211ax;
+	}
+
+	if (!settings.freq_params.eht_enabled && iface->conf->ieee80211be) {
+		wpa_printf(MSG_WARNING, "CSA: Cannot disable EHT. Ignore");
+		settings.freq_params.eht_enabled = iface->conf->ieee80211be;
+	}
+
 	if (settings.freq_params.center_freq1)
 		dfs_range += hostapd_is_dfs_overlap(
 			iface, bandwidth, settings.freq_params.center_freq1);
@@ -2614,6 +2634,18 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
 		dfs_range += hostapd_is_dfs_overlap(
 			iface, bandwidth, settings.freq_params.center_freq2);
 
+	/* If VHT/HE/EHT was enabled, we must also set the bandwidth and center
+	 * frequency
+	 */
+	if ((settings.freq_params.vht_enabled ||
+	     settings.freq_params.he_enabled ||
+	     settings.freq_params.eht_enabled) &&
+	    (!settings.freq_params.bandwidth ||
+	     !settings.freq_params.center_freq1)) {
+		settings.freq_params.bandwidth = 20;
+		settings.freq_params.center_freq1 = settings.freq_params.freq;
+	}
+
 	if (dfs_range) {
 		ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
 		if (ret == NUM_HOSTAPD_MODES) {
@@ -2641,8 +2673,6 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
 	}
 
 	for (i = 0; i < iface->num_bss; i++) {
-
-		/* Save CHAN_SWITCH VHT, HE, and EHT config */
 		hostapd_chan_switch_config(iface->bss[i],
 					   &settings.freq_params);
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 1d39495595..baf2ebb8bf 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1164,16 +1164,14 @@ struct hostapd_config {
 
 	bool require_he;
 #endif /* CONFIG_IEEE80211AX */
-
-	/* VHT enable/disable config from CHAN_SWITCH */
-#define CH_SWITCH_VHT_ENABLED BIT(0)
-#define CH_SWITCH_VHT_DISABLED BIT(1)
-	unsigned int ch_switch_vht_config;
-
-	/* HE enable/disable config from CHAN_SWITCH */
-#define CH_SWITCH_HE_ENABLED BIT(0)
-#define CH_SWITCH_HE_DISABLED BIT(1)
-	unsigned int ch_switch_he_config;
+	/*
+	 * Save the expected HT/VHT/HE/EHT configuration so it could be used
+	 * once CSA is done
+	 */
+	unsigned int ch_switch_ht_config:1;
+	unsigned int ch_switch_vht_config:1;
+	unsigned int ch_switch_he_config:1;
+	unsigned int ch_switch_eht_config:1;
 
 	int rssi_reject_assoc_rssi;
 	int rssi_reject_assoc_timeout;
@@ -1202,11 +1200,6 @@ struct hostapd_config {
 	u8 eht_bw320_offset;
 #endif /* CONFIG_IEEE80211BE */
 
-	/* EHT enable/disable config from CHAN_SWITCH */
-#define CH_SWITCH_EHT_ENABLED BIT(0)
-#define CH_SWITCH_EHT_DISABLED BIT(1)
-	unsigned int ch_switch_eht_config;
-
 	enum mbssid {
 		MBSSID_DISABLED = 0,
 		MBSSID_ENABLED = 1,
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 18cb355a75..a91eb22475 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -1016,7 +1016,16 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
 		return err;
 	}
 
+	/* preserve the HT/VHT/HE/EHT configuration */
+	csa_settings.freq_params.ht_enabled = iface->conf->ieee80211n;
+	csa_settings.freq_params.vht_enabled = iface->conf->ieee80211ac;
+	csa_settings.freq_params.he_enabled = iface->conf->ieee80211ax;
+	csa_settings.freq_params.eht_enabled = iface->conf->ieee80211be;
+
 	for (i = 0; i < iface->num_bss; i++) {
+		hostapd_chan_switch_config(iface->bss[i],
+					   &csa_settings.freq_params);
+
 		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
 		if (err)
 			break;
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 210068a94d..f30fa364da 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1036,7 +1036,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 		       "driver %s channel switch: iface->freq=%d, freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d, puncturing_bitmap=0x%x",
 		       finished ? "had" : "starting",
 		       hapd->iface->freq,
-		       freq, ht, hapd->iconf->ch_switch_vht_config,
+		       freq,
+		       hapd->iconf->ch_switch_ht_config,
+		       hapd->iconf->ch_switch_vht_config,
 		       hapd->iconf->ch_switch_he_config,
 		       hapd->iconf->ch_switch_eht_config, offset,
 		       width, channel_width_to_string(width), cf1, cf2,
@@ -1111,49 +1113,17 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 	}
 
 	hapd->iconf->channel = channel;
-	hapd->iconf->ieee80211n = ht;
-	if (!ht)
-		hapd->iconf->ieee80211ac = 0;
-	if (hapd->iconf->ch_switch_vht_config) {
-		/* CHAN_SWITCH VHT config */
-		if (hapd->iconf->ch_switch_vht_config &
-		    CH_SWITCH_VHT_ENABLED)
-			hapd->iconf->ieee80211ac = 1;
-		else if (hapd->iconf->ch_switch_vht_config &
-			 CH_SWITCH_VHT_DISABLED)
-			hapd->iconf->ieee80211ac = 0;
-	}
-	if (hapd->iconf->ch_switch_he_config) {
-		/* CHAN_SWITCH HE config */
-		if (hapd->iconf->ch_switch_he_config &
-		    CH_SWITCH_HE_ENABLED) {
-			hapd->iconf->ieee80211ax = 1;
-			if (hapd->iface->freq > 4000 &&
-			    hapd->iface->freq < 5895)
-				hapd->iconf->ieee80211ac = 1;
-		}
-		else if (hapd->iconf->ch_switch_he_config &
-			 CH_SWITCH_HE_DISABLED)
-			hapd->iconf->ieee80211ax = 0;
-	}
-#ifdef CONFIG_IEEE80211BE
-	if (hapd->iconf->ch_switch_eht_config) {
-		/* CHAN_SWITCH EHT config */
-		if (hapd->iconf->ch_switch_eht_config &
-		    CH_SWITCH_EHT_ENABLED) {
-			hapd->iconf->ieee80211be = 1;
-			hapd->iconf->ieee80211ax = 1;
-			if (!is_6ghz_freq(hapd->iface->freq) &&
-			    hapd->iface->freq > 4000)
-				hapd->iconf->ieee80211ac = 1;
-		} else if (hapd->iconf->ch_switch_eht_config &
-			   CH_SWITCH_EHT_DISABLED)
-			hapd->iconf->ieee80211be = 0;
+	hapd->iconf->ieee80211n = hapd->iconf->ch_switch_ht_config;
+	hapd->iconf->ieee80211ac = hapd->iconf->ch_switch_vht_config;
+	hapd->iconf->ieee80211ax = hapd->iconf->ch_switch_he_config;
+	hapd->iconf->ieee80211be = hapd->iconf->ch_switch_eht_config;
+
+	if (finished) {
+		hapd->iconf->ch_switch_ht_config = 0;
+		hapd->iconf->ch_switch_vht_config = 0;
+		hapd->iconf->ch_switch_he_config = 0;
+		hapd->iconf->ch_switch_eht_config = 0;
 	}
-#endif /* CONFIG_IEEE80211BE */
-	hapd->iconf->ch_switch_vht_config = 0;
-	hapd->iconf->ch_switch_he_config = 0;
-	hapd->iconf->ch_switch_eht_config = 0;
 
 	if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 ||
 	    width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160 ||
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 6a9b07e864..83ec043ba1 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -4034,27 +4034,18 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
 void hostapd_chan_switch_config(struct hostapd_data *hapd,
 				struct hostapd_freq_params *freq_params)
 {
-	if (freq_params->eht_enabled)
-		hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_ENABLED;
-	else
-		hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_DISABLED;
-
-	if (freq_params->he_enabled)
-		hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
-	else
-		hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED;
-
-	if (freq_params->vht_enabled)
-		hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
-	else
-		hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
+	hapd->iconf->ch_switch_ht_config = freq_params->ht_enabled;
+	hapd->iconf->ch_switch_vht_config = freq_params->vht_enabled;
+	hapd->iconf->ch_switch_he_config = freq_params->he_enabled;
+	hapd->iconf->ch_switch_eht_config = freq_params->eht_enabled;
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO,
-		       "CHAN_SWITCH EHT config 0x%x HE config 0x%x VHT config 0x%x",
-		       hapd->iconf->ch_switch_eht_config,
+		       "CHAN_SWITCH: config: ht=%u, vht=%u, he=%u, eht=%u",
+		       hapd->iconf->ch_switch_ht_config,
+		       hapd->iconf->ch_switch_vht_config,
 		       hapd->iconf->ch_switch_he_config,
-		       hapd->iconf->ch_switch_vht_config);
+		       hapd->iconf->ch_switch_eht_config);
 }
 
 
diff --git a/tests/hwsim/test_ap_vht.py b/tests/hwsim/test_ap_vht.py
index 2a7da8f68c..a6ef121229 100644
--- a/tests/hwsim/test_ap_vht.py
+++ b/tests/hwsim/test_ap_vht.py
@@ -969,8 +969,8 @@ def test_ap_vht_csa_vht20(dev, apdev):
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
 
-def test_ap_vht_csa_vht40_disable(dev, apdev):
-    """VHT CSA with VHT40 getting disabled"""
+def test_ap_vht_csa_vht40_unchanged(dev, apdev):
+    """VHT CSA with VHT not specified. Verify the VHT was not disabled"""
     csa_supported(dev[0])
     try:
         hapd = None
@@ -1014,8 +1014,8 @@ def test_ap_vht_csa_vht40_disable(dev, apdev):
         dev[1].connect("vht", key_mgmt="NONE", scan_freq="5200")
         hwsim_utils.test_connectivity(dev[1], hapd)
 
-        if dev[1].get_status_field("ieee80211ac") == '1':
-            raise Exception("VHT not disabled as part of channel switch")
+        if dev[1].get_status_field("ieee80211ac") != '1':
+            raise Exception("VHT unexpectedly disabled as part of channel switch")
     finally:
         dev[0].request("DISCONNECT")
         dev[1].request("DISCONNECT")
-- 
2.43.0




More information about the Hostap mailing list