[PATCH v9 4/7] hostapd: Support 80/160/320 MHz widths in hostapd_is_usable_chans

Allen Ye allen.ye at mediatek.com
Mon Dec 1 03:10:39 PST 2025


Update hostapd_is_usable_chans utility routine logic to take into
account 80MHz, 160MHz and 320MHz channel widths.
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 | 126 +++++++++++++++++++++++++++++++++----------
 src/ap/hw_features.h |   7 +++
 2 files changed, 105 insertions(+), 28 deletions(-)

diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 460b1d3ad..5d90a552f 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -1029,11 +1029,12 @@ static bool hostapd_is_usable_punct_bitmap(struct hostapd_iface *iface)
  * 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;
 	struct hostapd_channel_data *pri_chan;
-	int err, err2;
+	int err, central, oper_chwidth;
+	int start_chan, start_freq, chan_num, i;
+	bool is_24ghz, ht_chwidth, acs_80p80;
 
 	if (!iface->current_mode)
 		return 0;
@@ -1046,11 +1047,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;
@@ -1058,38 +1054,112 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 	if (!hostapd_is_usable_punct_bitmap(iface))
 		return 0;
 
-	if (!iface->conf->secondary_channel)
-		return 1;
+	oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+	central = hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
+
+	is_24ghz = (iface->current_mode->mode <= HOSTAPD_MODE_IEEE80211G);
+	ht_chwidth = (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT);
+	/*
+	 * 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
+	 */
+	acs_80p80 = (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ && !central);
+	if (is_24ghz || ht_chwidth || acs_80p80) {
+		int secondary_freq, err2;
+
+		err = hostapd_is_usable_chan(iface, iface->freq, 0);
+		if (err <= 0 || !iface->conf->secondary_channel)
+			return err;
+
+		secondary_freq =
+			iface->freq + iface->conf->secondary_channel * 20;
+		err = hostapd_is_usable_chan(iface, secondary_freq, 0);
+
+		if (err > 0) {
+			if (iface->conf->secondary_channel == 1 &&
+			    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
+				return 1;
+			if (iface->conf->secondary_channel == -1 &&
+			    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))
+				return 1;
+			err = 0;
+		}
+
+		if (!iface->conf->ht40_plus_minus_allowed)
+			return err;
+
+		/* Both HT40+ and HT40- are set, check the other secondary 40 */
+		secondary_freq =
+			iface->freq - iface->conf->secondary_channel * 20;
+		err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
+		if (err2 <= 0)
+			return err;
 
-	err = hostapd_is_usable_chan(iface, iface->freq +
-				     iface->conf->secondary_channel * 20, 0);
-	if (err > 0) {
 		if (iface->conf->secondary_channel == 1 &&
-		    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
+		    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
+			iface->conf->secondary_channel = -1;
 			return 1;
+		}
+
 		if (iface->conf->secondary_channel == -1 &&
-		    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))
+		    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
+			iface->conf->secondary_channel = 1;
 			return 1;
-	}
-	if (!iface->conf->ht40_plus_minus_allowed)
+		}
 		return err;
+	}
 
-	/* Both HT40+ and HT40- are set, pick a valid secondary channel */
-	secondary_freq = iface->freq + 20;
-	err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
-	if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
-		iface->conf->secondary_channel = 1;
-		return 1;
+	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);
 
-	secondary_freq = iface->freq - 20;
-	err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
-	if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
-		iface->conf->secondary_channel = -1;
+	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, 0);
+		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);
+	for (i = 0; i < chan_num; i++) {
+		int freq = start_freq + i * 20;
+
+		err = hostapd_is_usable_chan(iface, freq, 0);
+		if (err <= 0) {
+			wpa_printf(MSG_ERROR, "frequency %d is not allowed",
+				   freq);
+			return err;
+		}
 	}
 
-	return err;
+	return 1;
 }
 
 
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 73663d0af..d4953e8ba 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,12 @@ 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