[PATCH] Fix ACS when using 20MHz channels in 6GHz

Matej Vrba Matej.Vrba at advantech.cz
Tue Mar 25 06:25:09 PDT 2025


When configured to use ACS with 20MHz channels, hostapd incorrectly rejects
half of the available channels with an error messages "Channel XX: not
allowed as primary channel for 40 MHz bandwidth." This includes all PSC
channels.

Signed-off-by: Matěj Vrba <matej.vrba at advantech.cz>
---
 src/ap/acs.c | 59 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/src/ap/acs.c b/src/ap/acs.c
index 44d083684..4eb44780c 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -242,6 +242,12 @@
  * [1] http://en.wikipedia.org/wiki/Near_and_far_field
  */
 
+// Corresponds to "Behavior limits set" in 802.11-2020 annex E
+enum behavior_limitation {
+  BLIMIT_NONE,
+  BLIMIT_PRIMARY_CH_LOWER,
+};
+
 enum bw_type {
    ACS_BW40,
    ACS_BW80,
@@ -439,17 +445,22 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
 
 
 static bool acs_usable_bw_chan(const struct hostapd_channel_data *chan,
-                  enum bw_type bw)
+                  enum bw_type bw, enum behavior_limitation limit)
 {
-   unsigned int i = 0;
-
-   while (bw_desc[bw][i].first != -1) {
-       if (chan->freq == bw_desc[bw][i].first)
-           return true;
-       i++;
+   switch (limit) {
+       case BLIMIT_NONE:
+           for (unsigned int i = 0; bw_desc[bw][i].first != -1; i++)
+               if (chan->freq == bw_desc[bw][i].first || chan->freq == bw_desc[bw][i].last)
+                   return true;
+           break;
+       case BLIMIT_PRIMARY_CH_LOWER:
+           for (unsigned int i = 0; bw_desc[bw][i].first != -1; i++)
+               if (chan->freq == bw_desc[bw][i].first)
+                   return true;
+           break;
    }
 
-   return false;
+  return false;
 }
 
 
@@ -797,19 +808,19 @@ acs_usable_bw320_chan(struct hostapd_iface *iface,
    *bw320_offset = 0;
    switch (conf_bw320_offset) {
    case 1:
-       if (acs_usable_bw_chan(chan, ACS_BW320_1))
+       if (acs_usable_bw_chan(chan, ACS_BW320_1, BLIMIT_PRIMARY_CH_LOWER))
            *bw320_offset = 1;
        break;
    case 2:
-       if (acs_usable_bw_chan(chan, ACS_BW320_2))
+       if (acs_usable_bw_chan(chan, ACS_BW320_2, BLIMIT_PRIMARY_CH_LOWER))
            *bw320_offset = 2;
        break;
    case 0:
    default:
        conf_bw320_offset = 0;
-       if (acs_usable_bw_chan(chan, ACS_BW320_1))
+       if (acs_usable_bw_chan(chan, ACS_BW320_1, BLIMIT_PRIMARY_CH_LOWER))
            *bw320_offset = 1;
-       else if (acs_usable_bw_chan(chan, ACS_BW320_2))
+       else if (acs_usable_bw_chan(chan, ACS_BW320_2, BLIMIT_PRIMARY_CH_LOWER))
            *bw320_offset = 2;
        break;
    }
@@ -889,15 +900,17 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
 
        /* HT40 on 5 GHz has a limited set of primary channels as per
         * 11n Annex J */
-       if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
-           ((iface->conf->ieee80211n &&
-             iface->conf->secondary_channel) ||
-            is_6ghz_freq(chan->freq)) &&
-           !acs_usable_bw_chan(chan, ACS_BW40)) {
-           wpa_printf(MSG_DEBUG,
-                  "ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth",
-                  chan->chan);
-           continue;
+       if (is_6ghz_freq(chan->freq)) {
+           if (iface->conf->op_class == 132 && !acs_usable_bw_chan(chan, ACS_BW40, BLIMIT_NONE)) {
+               wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth in 6Ghz band", chan->chan);
+               continue;
+           }
+       } else {
+           if (mode->mode == HOSTAPD_MODE_IEEE80211A && ((iface->conf->ieee80211n && iface->conf->secondary_channel)) &&
+                   !acs_usable_bw_chan(chan, ACS_BW40, BLIMIT_PRIMARY_CH_LOWER)) {
+               wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth", chan->chan);
+               continue;
+           }
        }
 
        if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
@@ -905,7 +918,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
             iface->conf->ieee80211be)) {
            if (hostapd_get_oper_chwidth(iface->conf) ==
                CONF_OPER_CHWIDTH_80MHZ &&
-               !acs_usable_bw_chan(chan, ACS_BW80)) {
+               !acs_usable_bw_chan(chan, ACS_BW80, BLIMIT_PRIMARY_CH_LOWER)) {
                wpa_printf(MSG_DEBUG,
                       "ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
                       chan->chan);
@@ -914,7 +927,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
 
            if (hostapd_get_oper_chwidth(iface->conf) ==
                CONF_OPER_CHWIDTH_160MHZ &&
-               !acs_usable_bw_chan(chan, ACS_BW160)) {
+               !acs_usable_bw_chan(chan, ACS_BW160, BLIMIT_PRIMARY_CH_LOWER)) {
                wpa_printf(MSG_DEBUG,
                       "ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
                       chan->chan);
-- 
2.49.0



More information about the Hostap mailing list