[PATCH v13 2/5] hostapd: Support 80/160/320 MHz widths in hostapd_is_usable_chans

Allen Ye allen.ye at mediatek.com
Mon Aug 3 23:34:34 PDT 2026


Add hostapd_is_usable_chan_seg() to check all constituent 20 MHz
sub-channels for a given bandwidth segment. The channel count is derived
from oper_chwidth (4 for 80 MHz, 8 for 160 MHz, 16 for 320 MHz), and
the start frequency is computed from the center frequency index. For
80+80 MHz, both seg0 and seg1 are checked independently.

hostapd_is_usable_chans() dispatches to hostapd_is_usable_chan_seg() for
5 GHz/6 GHz non-HT modes with a valid center frequency. The condition
intentionally excludes 2.4 GHz (mode != IEEE80211A) and HT-only
configurations (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT), as well as
the 80+80 ACS case where the center frequency has not yet been filled in
by acs_adjust_center_freq(). These cases fall through to the existing
20/40 MHz path.

This is a preliminary patch to introduce AFC support.

Tested-by: Felix Fietkau <nbd at nbd.name>
Tested-by: Krishna Chaitanya <chaitanya.mgit at gmail.com>
Reviewed-by: Money Wang <money.wang at mediatek.com>
Signed-off-by: Allen Ye <allen.ye at mediatek.com>
---
 src/ap/hw_features.c | 94 ++++++++++++++++++++++++++++++++++++++++----
 src/ap/hw_features.h |  6 +++
 2 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 30edac214..01a693828 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -1083,16 +1083,83 @@ static bool hostapd_is_usable_punct_bitmap(struct hostapd_iface *iface)
 }
 
 
+static int hostapd_is_usable_chan_seg(struct hostapd_iface *iface)
+{
+	int central, oper_chwidth, err;
+	int start_chan, start_freq, chan_num, i;
+
+	oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+	central = hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
+
+	switch (oper_chwidth) {
+	case CONF_OPER_CHWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
+		chan_num = 4;
+		break;
+	case CONF_OPER_CHWIDTH_160MHZ:
+		chan_num = 8;
+		break;
+	case CONF_OPER_CHWIDTH_320MHZ:
+		chan_num = 16;
+		break;
+	default:
+		return 0;
+	}
+	start_chan = central - chan_num * 2 + 2;
+	start_freq = hw_get_freq(iface->current_mode, start_chan);
+
+	if (!start_freq) {
+		wpa_printf(MSG_ERROR, "frequency not present");
+		return 0;
+	}
+
+	for (i = 0; i < chan_num; i++) {
+		int freq = start_freq + i * 20;
+
+		err = hostapd_is_usable_chan(iface, freq, freq == iface->freq);
+		if (err <= 0) {
+			wpa_printf(MSG_ERROR, "frequency %d is not allowed",
+				   freq);
+			return err;
+		}
+	}
+
+	if (oper_chwidth != CONF_OPER_CHWIDTH_80P80MHZ)
+		return 1;
+
+	central = hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
+	start_chan = central - chan_num * 2 + 2;
+	start_freq = hw_get_freq(iface->current_mode, start_chan);
+
+	if (!start_freq) {
+		wpa_printf(MSG_ERROR, "frequency not present");
+		return 0;
+	}
+
+	for (i = 0; i < chan_num; i++) {
+		int freq = start_freq + i * 20;
+
+		err = hostapd_is_usable_chan(iface, freq, freq == iface->freq);
+		if (err <= 0) {
+			wpa_printf(MSG_ERROR, "frequency %d is not allowed",
+				   freq);
+			return err;
+		}
+	}
+	return 1;
+}
+
+
 /* Returns:
  * 1 = usable
  * 0 = not usable
  * -1 = not currently usable due to 6 GHz NO-IR
  */
-static int hostapd_is_usable_chans(struct hostapd_iface *iface)
+int hostapd_is_usable_chans(struct hostapd_iface *iface)
 {
 	int secondary_freq, new_sec, bw_flag;
 	struct hostapd_channel_data *pri_chan;
-	int err, err2;
+	int err, err2, central, oper_chwidth;
 
 	if (!iface->current_mode)
 		return 0;
@@ -1105,11 +1172,6 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 		return 0;
 	}
 
-	err = hostapd_is_usable_chan(iface, pri_chan->freq, 1);
-	if (err <= 0) {
-		wpa_printf(MSG_ERROR, "Primary frequency not allowed");
-		return err;
-	}
 	err = hostapd_is_usable_edmg(iface);
 	if (err <= 0)
 		return err;
@@ -1117,6 +1179,24 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 	if (!hostapd_is_usable_punct_bitmap(iface))
 		return 0;
 
+	oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+
+	/*
+	 * The central channel is not filled in acs_adjust_center_freq() after
+	 * ACS of 80p80. In the case we only check the primary 40 MHz.
+	 */
+	central = hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
+
+	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+	    oper_chwidth != CONF_OPER_CHWIDTH_USE_HT && central)
+		return hostapd_is_usable_chan_seg(iface);
+
+	err = hostapd_is_usable_chan(iface, pri_chan->freq, 1);
+	if (err <= 0) {
+		wpa_printf(MSG_ERROR, "Primary frequency not allowed");
+		return err;
+	}
+
 	if (!iface->conf->secondary_channel)
 		return 1;
 
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 6f945cc77..4993e68af 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -32,6 +32,7 @@ int hostapd_hw_skip_mode(struct hostapd_iface *iface,
 int hostapd_determine_mode(struct hostapd_iface *iface);
 void hostapd_free_multi_hw_info(struct hostapd_multi_hw_info *multi_hw_info);
 int hostapd_set_current_hw_info(struct hostapd_iface *iface, int oper_freq);
+int hostapd_is_usable_chans(struct hostapd_iface *iface);
 #else /* NEED_AP_MLME */
 static inline void
 hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -115,6 +116,11 @@ static inline int hostapd_set_current_hw_info(struct hostapd_iface *iface,
 {
 	return 0;
 }
+
+static inline int hostapd_is_usable_chans(struct hostapd_iface *iface)
+{
+	return 1;
+}
 #endif /* NEED_AP_MLME */
 
 #endif /* HW_FEATURES_H */
-- 
2.45.2




More information about the Hostap mailing list