[PATCH] S1G: Add support for freq_khz

Taavi E taavieomae at gmail.com
Tue Jul 4 11:42:44 PDT 2023


Hi,

I’ve rebased your patch on top of latest master and went over some
of the whitespace changes. I also incorporated the very small changes made
by JUN-KYU SHIN in "[PATCH v2, 2/2] Add hw mode config for 80211ah”
which makes it a bit more complete. (But it’s definitely not yet fully complete.)

After this patch I hope that I can get hostap working with Newracom’s
NRC7292 (without the driver faking other standards/channels like it does now)
and that might result in future patches to improve 802.11ah AP(/STA) support.

Side-note, I’m not too familiar with git-email, so apologies for any mistakes.

---

This commit adds support for specifying a channel frequency in kHz
and a 802.11ah (S1G) mode

The predominate use case is S1G. Many S1G channels are centered on
frequencies which a MHz value does not support. Additional freq_khz
parameters have been added as required to the key structures that
maintain the operating parameters of a hostapd AP. These freq_khz
params have been added to key functions alongside the traditional freq
parameter as an alternative.

The extent of this commit is the support of core BSS functionality using
freq_khz. It is intended that several follow up commits will make use of
this concept to support more advanced features.

Because this commit has introduced an alternative parameter that is used
instead of the traditional freq param we needed to introduce logic that
would support this change. We opted for logic that checks if freq_khz is
set, and if so, uses that parameter going forward, otherwise if freq_khz
is not set, freq is used as per the existing use case.
This approach prevents regression for existing code.

The kernel maintains frequencies by using a combination of freq and
freq_offset parameters. This patch includes a number of changes to support
this concept.

Signed-off-by: Taavi Eomäe <taavi.eomae at gmail.com>
Signed-off-by: Gilad Itzkovitch <gilad.itzkovitch at morsemicro.com>
Signed-off-by: JUN-KYU SHIN <jk.shin at newratek.com>
---
 hostapd/config_file.c              |  2 ++
 src/ap/ap_drv_ops.c                |  9 ++++--
 src/ap/ap_drv_ops.h                |  3 +-
 src/ap/beacon.c                    |  1 +
 src/ap/ctrl_iface_ap.c             |  2 ++
 src/ap/dfs.c                       |  9 ++++--
 src/ap/drv_callbacks.c             | 10 ++++---
 src/ap/hostapd.c                   | 12 ++++----
 src/ap/hostapd.h                   | 10 +++++--
 src/ap/hw_features.c               | 46 ++++++++++++++++++------------
 src/ap/hw_features.h               |  2 +-
 src/common/defs.h                  |  7 +++++
 src/common/hw_features_common.c    | 25 ++++++++++------
 src/common/hw_features_common.h    | 13 +++++----
 src/common/ieee802_11_common.c     | 12 ++++++++
 src/common/ieee802_11_common.h     |  1 +
 src/drivers/driver.h               | 14 +++++++++
 src/drivers/driver_nl80211.c       | 23 +++++++++++++--
 src/drivers/driver_nl80211_capa.c  | 12 +++++++-
 src/drivers/driver_nl80211_event.c | 17 ++++++++---
 wpa_supplicant/ap.c                | 13 +++++----
 wpa_supplicant/ap.h                |  4 +--
 wpa_supplicant/config_ssid.h       |  5 ++++
 wpa_supplicant/events.c            |  1 +
 wpa_supplicant/mesh.c              |  1 +
 wpa_supplicant/wpa_supplicant.c    |  3 +-
 wpa_supplicant/wpa_supplicant_i.h  |  1 +
 27 files changed, 193 insertions(+), 65 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 412ca8a9f..5b87643c7 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3101,6 +3101,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 			conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
 		else if (os_strcmp(pos, "ad") == 0)
 			conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+		else if (os_strcmp(pos, "ah") == 0)
+			conf->hw_mode = HOSTAPD_MODE_IEEE80211AH;
 		else if (os_strcmp(pos, "any") == 0)
 			conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
 		else {
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 8f9cc5b36..09dd6daca 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -571,7 +571,8 @@ int hostapd_flush(struct hostapd_data *hapd)
 
 
 int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
-		     int freq, int channel, int edmg, u8 edmg_channel,
+		     int freq, int freq_khz, int channel,
+		     int edmg, u8 edmg_channel,
 		     int ht_enabled, int vht_enabled,
 		     int he_enabled, bool eht_enabled,
 		     int sec_channel_offset, int oper_chwidth,
@@ -580,7 +581,9 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 	struct hostapd_freq_params data;
 	struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
 
-	if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
+
+	if (hostapd_set_freq_params(&data, mode, freq, freq_khz,
+				    channel, edmg,
 				    edmg_channel, ht_enabled,
 				    vht_enabled, he_enabled, eht_enabled,
 				    sec_channel_offset, oper_chwidth,
@@ -899,7 +902,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
 		return -1;
 	}
 
-	if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
+	if (hostapd_set_freq_params(&data, mode, freq, 0, channel, 0, 0,
 				    ht_enabled,
 				    vht_enabled, he_enabled, eht_enabled,
 				    sec_channel_offset,
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 331b0eaf4..11efa5fbf 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -65,7 +65,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
 		       const u8 *addr, int idx, int link_id, u8 *seq);
 int hostapd_flush(struct hostapd_data *hapd);
 int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
-		     int freq, int channel, int edmg, u8 edmg_channel,
+		     int freq, int freq_khz, int channel,
+		     int edmg, u8 edmg_channel,
 		     int ht_enabled, int vht_enabled, int he_enabled,
 		     bool eht_enabled, int sec_channel_offset, int oper_chwidth,
 		     int center_segment0, int center_segment1);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 32c143a2b..6b15eb1ef 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2163,6 +2163,7 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
 
 	if (cmode &&
 	    hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+				    iface->freq_khz,
 				    iconf->channel, iconf->enable_edmg,
 				    iconf->edmg_channel, iconf->ieee80211n,
 				    iconf->ieee80211ac, iconf->ieee80211ax,
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index c7504ad2b..df7bc99e9 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -223,6 +223,8 @@ static const char * hw_mode_str(enum hostapd_hw_mode mode)
 		return "a";
 	case HOSTAPD_MODE_IEEE80211AD:
 		return "ad";
+	case HOSTAPD_MODE_IEEE80211AH:
+		return "ah";
 	case HOSTAPD_MODE_IEEE80211ANY:
 		return "any";
 	case NUM_HOSTAPD_MODES:
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index e8c5ec9ac..2e275de7e 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -826,6 +826,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
 	if (is_6ghz_freq(iface->freq))
 		return 1;
 
+	if (is_s1g_freq(iface->freq_khz))
+		return 1;
+
 	if (!iface->current_mode) {
 		/*
 		 * This can happen with drivers that do not provide mode
@@ -955,6 +958,7 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
 
 static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
 					      int channel, int freq,
+					      int freq_khz,
 					      int secondary_channel,
 					      u8 current_vht_oper_chwidth,
 					      u8 oper_centr_freq_seg0_idx,
@@ -984,7 +988,7 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
 #endif /* CONFIG_MESH */
 	err = hostapd_set_freq_params(&csa_settings.freq_params,
 				      iface->conf->hw_mode,
-				      freq, channel,
+				      freq, freq_khz, channel,
 				      iface->conf->enable_edmg,
 				      iface->conf->edmg_channel,
 				      iface->conf->ieee80211n,
@@ -1117,7 +1121,7 @@ hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
 	hostpad_dfs_update_background_chain(iface);
 
 	return hostapd_dfs_request_channel_switch(
-		iface, iface->conf->channel, iface->freq,
+		iface, iface->conf->channel, iface->freq, 0,
 		iface->conf->secondary_channel, current_vht_oper_chwidth,
 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
@@ -1409,6 +1413,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
 
 	return hostapd_dfs_request_channel_switch(iface, channel->chan,
 						  channel->freq,
+						  channel->freq_khz,
 						  secondary_channel,
 						  current_vht_oper_chwidth,
 						  oper_centr_freq_seg0_idx,
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 4d765dcb1..3a2e44031 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -857,8 +857,8 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
-void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset, int width, int cf1, int cf2,
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int freq_khz,
+			     int ht, int offset, int width, int cf1, int cf2,
 			     u16 punct_bitmap, int finished)
 {
 #ifdef NEED_AP_MLME
@@ -888,7 +888,7 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 	is_dfs0 = hostapd_is_dfs_required(hapd->iface);
 	hapd->iface->freq = freq;
 
-	channel = hostapd_hw_get_channel(hapd, freq);
+	channel = hostapd_hw_get_channel(hapd, freq, freq_khz);
 	if (!channel) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_WARNING,
@@ -1111,6 +1111,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
 				if (hapd->iface->freq > 0 &&
 				    !hw_get_chan(mode->mode,
 						 hapd->iface->freq,
+						 hapd->iface->freq_khz,
 						 hapd->iface->hw_features,
 						 hapd->iface->num_hw_features))
 					continue;
@@ -1135,7 +1136,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
 		goto out;
 	}
 	pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
-				       acs_res->pri_freq, NULL,
+				       acs_res->pri_freq, 0, NULL,
 				       hapd->iface->hw_features,
 				       hapd->iface->num_hw_features);
 	if (!pri_chan) {
@@ -2133,6 +2134,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		if (!data)
 			break;
 		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
+					data->ch_switch.freq_khz,
 					data->ch_switch.ht_enabled,
 					data->ch_switch.ch_offset,
 					data->ch_switch.ch_width,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 99d10bea9..8702d0716 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1672,7 +1672,7 @@ static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
 
 		if (mode->mode == iface->conf->hw_mode) {
 			if (iface->freq > 0 &&
-			    !hw_mode_get_channel(mode, iface->freq, NULL)) {
+			    !hw_mode_get_channel(mode, iface->freq, 0, NULL)) {
 				mode = NULL;
 				continue;
 			}
@@ -1698,7 +1698,7 @@ static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
 			struct hostapd_channel_data *chan;
 
 			chan = hw_get_channel_freq(iface->current_mode->mode,
-						   iface->freq, NULL,
+						   iface->freq, 0, NULL,
 						   iface->hw_features,
 						   iface->num_hw_features);
 
@@ -1733,7 +1733,7 @@ static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
 			struct hostapd_channel_data *chan;
 
 			chan = hw_get_channel_freq(iface->current_mode->mode,
-						   iface->freq, NULL,
+						   iface->freq, 0, NULL,
 						   iface->hw_features,
 						   iface->num_hw_features);
 			if (!chan) {
@@ -2326,7 +2326,8 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
 #endif /* CONFIG_MESH */
 
 		if (!delay_apply_cfg &&
-		    hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+		    hostapd_set_freq(hapd, hapd->iconf->hw_mode,
+				     iface->freq, iface->freq_khz,
 				     hapd->iconf->channel,
 				     hapd->iconf->enable_edmg,
 				     hapd->iconf->edmg_channel,
@@ -3769,7 +3770,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 
 	if (!params->channel) {
 		/* check if the new channel is supported by hw */
-		params->channel = hostapd_hw_get_channel(hapd, params->freq);
+		params->channel = hostapd_hw_get_channel(hapd, params->freq, 0);
 	}
 
 	channel = params->channel;
@@ -3783,6 +3784,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 	if (old_params &&
 	    hostapd_set_freq_params(old_params, conf->hw_mode,
 				    hostapd_hw_get_freq(hapd, conf->channel),
+				    0,
 				    conf->channel, conf->enable_edmg,
 				    conf->edmg_channel, conf->ieee80211n,
 				    conf->ieee80211ac, conf->ieee80211ax,
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 6e0ce3dea..aadfc704f 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -561,6 +561,12 @@ struct hostapd_iface {
 	struct hostapd_rate_data *current_rates;
 	int *basic_rates;
 	int freq;
+	/*
+	 * freq_khz was added to support S1G frequencies.
+	 * This variable could be use in other modes of operation.
+	 * However, this is not currently supported.
+	 */
+	int freq_khz;
 
 	/* Background radar configuration */
 	struct {
@@ -738,8 +744,8 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
 int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
 			 const u8 *bssid, const u8 *ie, size_t ie_len,
 			 int ssi_signal);
-void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset, int width, int cf1, int cf2,
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int freq_khz,
+			     int ht, int offset, int width, int cf1, int cf2,
 			     u16 punct_bitmap, int finished);
 struct survey_results;
 void hostapd_event_get_survey(struct hostapd_iface *iface,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 7d899f50d..7726b6afe 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -235,11 +235,11 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
 	if (!iface->current_mode)
 		return 0;
 
-	p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
+	p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, 0, NULL,
 				     iface->hw_features,
 				     iface->num_hw_features);
 
-	s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
+	s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, 0, NULL,
 				     iface->hw_features,
 				     iface->num_hw_features);
 
@@ -274,10 +274,10 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
 
 	if (!iface->current_mode)
 		return 0;
-	pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
+	pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, 0,
 				       NULL, iface->hw_features,
 				       iface->num_hw_features);
-	sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
+	sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, 0,
 				       NULL, iface->hw_features,
 				       iface->num_hw_features);
 
@@ -800,15 +800,16 @@ int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
  * -1 = not currently usable due to 6 GHz NO-IR
  */
 static int hostapd_is_usable_chan(struct hostapd_iface *iface,
-				  int frequency, int primary)
+				  int frequency, int frequency_khz, int primary)
 {
 	struct hostapd_channel_data *chan;
 
 	if (!iface->current_mode)
 		return 0;
 
-	chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
-				   iface->hw_features, iface->num_hw_features);
+	chan = hw_get_channel_freq(iface->current_mode->mode, frequency,
+				   frequency_khz, NULL, iface->hw_features,
+				   iface->num_hw_features);
 	if (!chan)
 		return 0;
 
@@ -818,7 +819,8 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
 
 	wpa_printf(MSG_INFO,
 		   "Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
-		   frequency, primary ? "primary" : "secondary",
+		   frequency_khz ? frequency_khz : frequency,
+		   primary ? "primary" : "secondary",
 		   chan->flag,
 		   chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
 		   chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
@@ -845,7 +847,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
 	if (!iface->current_mode)
 		return 0;
 	pri_chan = hw_get_channel_freq(iface->current_mode->mode,
-				       iface->freq, NULL,
+				       iface->freq, iface->freq_khz, NULL,
 				       iface->hw_features,
 				       iface->num_hw_features);
 	if (!pri_chan)
@@ -875,7 +877,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
 		if (num_of_enabled > 4)
 			return 0;
 
-		err = hostapd_is_usable_chan(iface, freq, 1);
+		err = hostapd_is_usable_chan(iface, freq, 0, 1);
 		if (err <= 0)
 			return err;
 
@@ -967,7 +969,8 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 	if (!iface->current_mode)
 		return 0;
 	pri_chan = hw_get_channel_freq(iface->current_mode->mode,
-				       iface->freq, NULL,
+				       iface->freq,
+				       iface->freq_khz, NULL,
 				       iface->hw_features,
 				       iface->num_hw_features);
 	if (!pri_chan) {
@@ -975,7 +978,9 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 		return 0;
 	}
 
-	err = hostapd_is_usable_chan(iface, pri_chan->freq, 1);
+	err = hostapd_is_usable_chan(iface, pri_chan->freq,
+				       pri_chan->freq_khz,
+				       pri_chan->freq_khz ? 0 : 1);
 	if (err <= 0) {
 		wpa_printf(MSG_ERROR, "Primary frequency not allowed");
 		return err;
@@ -991,7 +996,7 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 		return 1;
 
 	err = hostapd_is_usable_chan(iface, iface->freq +
-				     iface->conf->secondary_channel * 20, 0);
+				     iface->conf->secondary_channel * 20, 0, 0);
 	if (err > 0) {
 		if (iface->conf->secondary_channel == 1 &&
 		    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
@@ -1005,14 +1010,14 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 
 	/* Both HT40+ and HT40- are set, pick a valid secondary channel */
 	secondary_freq = iface->freq + 20;
-	err = hostapd_is_usable_chan(iface, secondary_freq, 0);
+	err = hostapd_is_usable_chan(iface, secondary_freq, 0, 0);
 	if (err > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
 		iface->conf->secondary_channel = 1;
 		return 1;
 	}
 
 	secondary_freq = iface->freq - 20;
-	err = hostapd_is_usable_chan(iface, secondary_freq, 0);
+	err = hostapd_is_usable_chan(iface, secondary_freq, 0, 0);
 	if (err > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
 		iface->conf->secondary_channel = -1;
 		return 1;
@@ -1027,7 +1032,8 @@ static bool skip_mode(struct hostapd_iface *iface,
 {
 	int chan;
 
-	if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, &chan))
+	if ((iface->freq > 0 || iface->freq_khz > 0) &&
+	     !hw_mode_get_channel(mode, iface->freq, iface->freq_khz, &chan))
 		return true;
 
 	if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 &&
@@ -1078,7 +1084,7 @@ void hostapd_determine_mode(struct hostapd_iface *iface)
 static enum hostapd_chan_status
 hostapd_check_chans(struct hostapd_iface *iface)
 {
-	if (iface->freq) {
+	if (iface->freq || iface->freq_khz) {
 		int err;
 
 		hostapd_determine_mode(iface);
@@ -1194,6 +1200,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
 	if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
 	     iface->conf->ieee80211n || iface->conf->ieee80211ac ||
 	     iface->conf->ieee80211ax || iface->conf->ieee80211be) &&
+	     iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211AH &&
 	    iface->conf->channel == 14) {
 		wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14");
 		iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
@@ -1277,13 +1284,14 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
 }
 
 
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq, int freq_khz)
 {
 	int i, channel;
 	struct hostapd_hw_modes *mode;
 
 	if (hapd->iface->current_mode) {
 		channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
+				      freq_khz,
 				      hapd->iface->hw_features,
 				      hapd->iface->num_hw_features);
 		if (channel)
@@ -1296,7 +1304,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
 		return 0;
 	for (i = 0; i < hapd->iface->num_hw_features; i++) {
 		mode = &hapd->iface->hw_features[i];
-		channel = hw_get_chan(mode->mode, freq,
+		channel = hw_get_chan(mode->mode, freq, freq_khz,
 				      hapd->iface->hw_features,
 				      hapd->iface->num_hw_features);
 		if (channel)
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 092941f77..b5fc3d5d2 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -19,7 +19,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err);
 int hostapd_select_hw_mode(struct hostapd_iface *iface);
 const char * hostapd_hw_mode_txt(int mode);
 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq, int freq_khz);
 int hostapd_check_ht_capab(struct hostapd_iface *iface);
 int hostapd_check_edmg_capab(struct hostapd_iface *iface);
 int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface);
diff --git a/src/common/defs.h b/src/common/defs.h
index c0c6dbe84..78d9e60e2 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -376,6 +376,7 @@ enum hostapd_hw_mode {
 	HOSTAPD_MODE_IEEE80211G,
 	HOSTAPD_MODE_IEEE80211A,
 	HOSTAPD_MODE_IEEE80211AD,
+	HOSTAPD_MODE_IEEE80211AH,
 	HOSTAPD_MODE_IEEE80211ANY,
 	NUM_HOSTAPD_MODES
 };
@@ -529,4 +530,10 @@ enum sae_pwe {
 	SAE_PWE_NOT_SET = 4,
 };
 
+#define MHZ_TO_KHZ(x) ((x) * 1000)
+#define KHZ_TO_MHZ(x) ((x) / 1000)
+#define KHZ_TO_S1G_OFFSET(x) ((x) % 1000)
+/* If x (freq_khz) is 0 then print "MHz" else print "kHz" */
+#define KHZ_PRINT_FREQ_UNITS(x) (x) == 0 ? "MHz" : "kHz"
+
 #endif /* DEFS_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 584c6d275..3f2255a3d 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -41,14 +41,18 @@ struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
 
 
 struct hostapd_channel_data *
-hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq,
+						  int freq_khz, int *chan)
 {
 	int i;
 
 	for (i = 0; i < mode->num_channels; i++) {
 		struct hostapd_channel_data *ch = &mode->channels[i];
 
-		if (ch->freq == freq) {
+		if (freq_khz && (ch->freq_khz == freq_khz)) {
+			return ch;
+		}
+		if (freq && (ch->freq == freq)) {
 			if (chan)
 				*chan = ch->chan;
 			return ch;
@@ -60,8 +64,9 @@ hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
 
 
 struct hostapd_channel_data *
-hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
-		    struct hostapd_hw_modes *hw_features, int num_hw_features)
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int freq_khz,
+		    int *chan, struct hostapd_hw_modes *hw_features,
+		    int num_hw_features)
 {
 	struct hostapd_channel_data *chan_data;
 	int i;
@@ -78,7 +83,8 @@ hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
 		if (curr_mode->mode != mode)
 			continue;
 
-		chan_data = hw_mode_get_channel(curr_mode, freq, chan);
+		chan_data = hw_mode_get_channel(curr_mode, freq,
+			   freq_khz, chan);
 		if (chan_data)
 			return chan_data;
 	}
@@ -97,12 +103,13 @@ int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
 }
 
 
-int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+int hw_get_chan(enum hostapd_hw_mode mode, int freq, int freq_khz,
 		struct hostapd_hw_modes *hw_features, int num_hw_features)
 {
 	int chan;
 
-	hw_get_channel_freq(mode, freq, &chan, hw_features, num_hw_features);
+	hw_get_channel_freq(mode, freq, freq_khz, &chan, hw_features,
+			   num_hw_features);
 
 	return chan;
 }
@@ -380,7 +387,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
 
 int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int enable_edmg,
+			    int freq, int freq_khz,
+			    int channel, int enable_edmg,
 			    u8 edmg_channel, int ht_enabled,
 			    int vht_enabled, int he_enabled,
 			    bool eht_enabled, int sec_channel_offset,
@@ -397,6 +405,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
 	os_memset(data, 0, sizeof(*data));
 	data->mode = mode;
 	data->freq = freq;
+	data->freq_khz = freq_khz;
 	data->channel = channel;
 	data->ht_enabled = ht_enabled;
 	data->vht_enabled = vht_enabled;
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 82e028238..5402fd970 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -15,14 +15,16 @@
 struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
 						  int chan, int *freq);
 struct hostapd_channel_data *
-hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan);
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq,
+		    int freq_khz, int *chan);
 
 struct hostapd_channel_data *
-hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
-		    struct hostapd_hw_modes *hw_features, int num_hw_features);
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int freq_khz,
+		    int *chan, struct hostapd_hw_modes *hw_features,
+		    int num_hw_features);
 
 int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
-int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+int hw_get_chan(enum hostapd_hw_mode mode, int freq, int freq_khz,
 		struct hostapd_hw_modes *hw_features, int num_hw_features);
 
 int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
@@ -37,7 +39,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
 		    int sec_chan);
 int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int edmg, u8 edmg_channel,
+			    int freq, int freq_khz,
+			    int channel, int edmg, u8 edmg_channel,
 			    int ht_enabled,
 			    int vht_enabled, int he_enabled,
 			    bool eht_enabled, int sec_channel_offset,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index a8f16b3d1..4f064e2dc 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1372,6 +1372,9 @@ ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
 
 	/* TODO: more operating classes */
 
+	if (is_s1g_freq(MHZ_TO_KHZ(freq)))
+		return HOSTAPD_MODE_IEEE80211AH;
+
 	if (sec_channel > 1 || sec_channel < -1)
 		return NUM_HOSTAPD_MODES;
 
@@ -2433,6 +2436,7 @@ static enum phy_type ieee80211_phy_type_by_freq(int freq)
 
 	switch (hw_mode) {
 	case HOSTAPD_MODE_IEEE80211A:
+	case HOSTAPD_MODE_IEEE80211AH:
 		return PHY_TYPE_OFDM;
 	case HOSTAPD_MODE_IEEE80211B:
 		return PHY_TYPE_HRDSSS;
@@ -2823,6 +2827,14 @@ int get_6ghz_sec_channel(int channel)
 	return 1;
 }
 
+bool is_s1g_freq(int freq_khz)
+{
+	if (freq_khz < 1000000 && freq_khz > 0)
+		return true;
+
+	return false;
+}
+
 
 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
 				    size_t nei_rep_len)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 785fe608a..811ae3699 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -280,6 +280,7 @@ bool is_6ghz_freq(int freq);
 bool is_6ghz_op_class(u8 op_class);
 bool is_6ghz_psc_frequency(int freq);
 int get_6ghz_sec_channel(int channel);
+bool is_s1g_freq(int freq_khz);
 
 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
 				    size_t nei_rep_len);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8e462c8b7..8236f4ebd 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -119,6 +119,11 @@ struct hostapd_channel_data {
 	 */
 	int freq;
 
+	/**
+	 * freq_khz - Frequency in kHz
+	 */
+	int freq_khz;
+
 	/**
 	 * flag - Channel flags (HOSTAPD_CHAN_*)
 	 */
@@ -778,6 +783,11 @@ struct hostapd_freq_params {
 	 */
 	int freq;
 
+	/**
+	 * freq_khz - Primary channel center frequency in kHz
+	 */
+	int freq_khz;
+
 	/**
 	 * channel - Channel number
 	 */
@@ -6422,6 +6432,7 @@ union wpa_event_data {
 	/**
 	 * struct ch_switch
 	 * @freq: Frequency of new channel in MHz
+	 * @freq_khz: Frequency of new channel in kHz
 	 * @ht_enabled: Whether this is an HT channel
 	 * @ch_offset: Secondary channel offset
 	 * @ch_width: Channel width
@@ -6432,6 +6443,7 @@ union wpa_event_data {
 	 */
 	struct ch_switch {
 		int freq;
+		int freq_khz;
 		int ht_enabled;
 		int ch_offset;
 		enum chan_width ch_width;
@@ -6515,6 +6527,7 @@ union wpa_event_data {
 	/**
 	 * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
 	 * @pri_freq: Selected primary frequency
+	 * @pri_freq_khz: Selected primary frequency in kHz
 	 * @sec_freq: Selected secondary frequency
 	 * @edmg_channel: Selected EDMG channel
 	 * @vht_seg0_center_ch: VHT mode Segment0 center channel
@@ -6534,6 +6547,7 @@ union wpa_event_data {
 	 */
 	struct acs_selected_channels {
 		unsigned int pri_freq;
+		unsigned int pri_freq_khz;
 		unsigned int sec_freq;
 		u8 edmg_channel;
 		u8 vht_seg0_center_ch;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e4180daed..f99af8747 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4862,8 +4862,19 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
 	u8 channel;
 
 	wpa_printf(MSG_DEBUG, "  * freq=%d", freq->freq);
-	if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
-		return -ENOBUFS;
+	if (is_s1g_freq(freq->freq_khz)) {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+			KHZ_TO_MHZ(freq->freq_khz)))
+				return -ENOBUFS;
+		wpa_printf(MSG_DEBUG, "  * freq_offset=%d",
+		KHZ_TO_S1G_OFFSET(freq->freq_khz));
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
+			KHZ_TO_S1G_OFFSET(freq->freq_khz)))
+			return -ENOBUFS;
+		} else {
+			if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
+				return -ENOBUFS;
+	}
 
 	wpa_printf(MSG_DEBUG, "  * eht_enabled=%d", freq->eht_enabled);
 	wpa_printf(MSG_DEBUG, "  * he_enabled=%d", freq->he_enabled);
@@ -5027,6 +5038,14 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
 		goto fail;
 
+	if (is_s1g_freq(params->freq->freq_khz)) {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+			       KHZ_TO_MHZ(params->freq->freq_khz)) ||
+			       nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
+			       KHZ_TO_S1G_OFFSET(params->freq->freq_khz)))
+			goto fail;
+	}
+
 	if (params->mld_ap) {
 		wpa_printf(MSG_DEBUG, "nl80211: link_id=%u",
 			   params->mld_link_id);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 5e6406885..d974c8c27 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1652,6 +1652,8 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
 
 	os_memset(chan, 0, sizeof(*chan));
 	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+	chan->freq_khz = MHZ_TO_KHZ(chan->freq) +
+	nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_OFFSET]);
 	chan->flag = 0;
 	chan->allowed_bw = ~0;
 	chan->dfs_cac_ms = 0;
@@ -2134,7 +2136,10 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
 	for (m = 0; m < *num_modes; m++) {
 		if (!modes[m].num_channels)
 			continue;
-		if (modes[m].channels[0].freq < 2000) {
+		if (modes[m].channels[0].freq_khz < 1000000 &&
+			modes[m].channels[0].freq_khz > 0){
+			modes[m].mode = HOSTAPD_MODE_IEEE80211AH;
+		} else if (modes[m].channels[0].freq < 2000) {
 			modes[m].num_channels = 0;
 			continue;
 		} else if (modes[m].channels[0].freq < 4000) {
@@ -2177,6 +2182,9 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
 			return modes; /* 802.11b already included */
 		if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
 			mode11g_idx = m;
+		if (modes[m].mode == HOSTAPD_MODE_IEEE80211AH) {
+			return modes;
+		}
 	}
 
 	if (mode11g_idx < 0)
@@ -2531,6 +2539,8 @@ static const char * modestr(enum hostapd_hw_mode mode)
 		return "802.11a";
 	case HOSTAPD_MODE_IEEE80211AD:
 		return "802.11ad";
+	case HOSTAPD_MODE_IEEE80211AH:
+		return "802.11ah";
 	default:
 		return "?";
 	}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index e7aff260d..346bc461c 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1198,7 +1198,8 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
 
 static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
 				 struct nlattr *ifindex, struct nlattr *link,
-				 struct nlattr *freq, struct nlattr *type,
+				 struct nlattr *freq, struct nlattr *freq_off,
+				 struct nlattr *type,
 				 struct nlattr *bw, struct nlattr *cf1,
 				 struct nlattr *cf2,
 				 struct nlattr *punct_bitmap,
@@ -1255,6 +1256,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
 
 	os_memset(&data, 0, sizeof(data));
 	data.ch_switch.freq = nla_get_u32(freq);
+	data.ch_switch.freq_khz = MHZ_TO_KHZ(data.ch_switch.freq) +
+		nla_get_u32(freq_off);
 	data.ch_switch.ht_enabled = ht_enabled;
 	data.ch_switch.ch_offset = chan_offset;
 	if (punct_bitmap)
@@ -1631,7 +1634,8 @@ nl80211_get_mld_link_by_freq(struct i802_bss *bss, unsigned int freq)
 static void mlme_event(struct i802_bss *bss,
 		       enum nl80211_commands cmd, struct nlattr *frame,
 		       struct nlattr *addr, struct nlattr *timed_out,
-		       struct nlattr *freq, struct nlattr *ack,
+		       struct nlattr *freq, struct nlattr *freq_offset,
+		       struct nlattr *ack,
 		       struct nlattr *cookie, struct nlattr *sig,
 		       struct nlattr *wmm, struct nlattr *req_ie,
 		       struct nlattr *link)
@@ -3814,7 +3818,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 	case NL80211_CMD_UNPROT_DISASSOCIATE:
 		mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
 			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
-			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+			   tb[NL80211_ATTR_WIPHY_FREQ],
+			   tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
+			   tb[NL80211_ATTR_ACK],
 			   tb[NL80211_ATTR_COOKIE],
 			   tb[NL80211_ATTR_RX_SIGNAL_DBM],
 			   tb[NL80211_ATTR_STA_WME],
@@ -3843,6 +3849,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 				     tb[NL80211_ATTR_IFINDEX],
 				     tb[NL80211_ATTR_MLO_LINK_ID],
 				     tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
 				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
 				     tb[NL80211_ATTR_CHANNEL_WIDTH],
 				     tb[NL80211_ATTR_CENTER_FREQ1],
@@ -3855,6 +3862,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 				     tb[NL80211_ATTR_IFINDEX],
 				     tb[NL80211_ATTR_MLO_LINK_ID],
 				     tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
 				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
 				     tb[NL80211_ATTR_CHANNEL_WIDTH],
 				     tb[NL80211_ATTR_CENTER_FREQ1],
@@ -4044,7 +4052,8 @@ int process_bss_event(struct nl_msg *msg, void *arg)
 	case NL80211_CMD_FRAME_TX_STATUS:
 		mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
 			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
-			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
+			   tb[NL80211_ATTR_ACK],
 			   tb[NL80211_ATTR_COOKIE],
 			   tb[NL80211_ATTR_RX_SIGNAL_DBM],
 			   tb[NL80211_ATTR_STA_WME], NULL,
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index ff7c75644..fa5757b71 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1838,9 +1838,9 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
 #endif /* CONFIG_CTRL_IFACE */
 
 
-void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset, int width, int cf1, int cf2,
-		       u16 punct_bitmap, int finished)
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int freq_khz,
+				int ht, int offset, int width, int cf1, int cf2,
+				u16 punct_bitmap, int finished)
 {
 	struct hostapd_iface *iface = wpa_s->ap_iface;
 
@@ -1849,9 +1849,12 @@ void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
 	if (!iface)
 		return;
 	wpa_s->assoc_freq = freq;
-	if (wpa_s->current_ssid)
+	wpa_s->assoc_freq_khz = freq_khz;
+	if (wpa_s->current_ssid) {
 		wpa_s->current_ssid->frequency = freq;
-	hostapd_event_ch_switch(iface->bss[0], freq, ht,
+		wpa_s->current_ssid->frequency_khz = freq_khz;
+	}
+	hostapd_event_ch_switch(iface->bss[0], freq, freq_khz, ht,
 				offset, width, cf1, cf2, punct_bitmap,
 				finished);
 }
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 5835ecd87..612999fe8 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -72,8 +72,8 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
 int ap_switch_channel(struct wpa_supplicant *wpa_s,
 		      struct csa_settings *settings);
 int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
-void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset, int width, int cf1, int cf2,
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int freq_khz,
+		       int ht, int offset, int width, int cf1, int cf2,
 		       u16 punct_bitmap, int finished);
 struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
 					     int ndef);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index ff045380e..7ee8d1d1a 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -524,6 +524,11 @@ struct wpa_ssid {
 	 */
 	int frequency;
 
+	/**
+	 * frequency_khz - Channel frequency in kilohertz (kHz)
+	 */
+	int frequency_khz;
+
 	/**
 	 * enable_edmg - Enable EDMG feature in STA/AP mode
 	 *
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index e7aaa1a12..291bbd40b 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -5730,6 +5730,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		    wpa_s->current_ssid->mode ==
 		    WPAS_MODE_P2P_GROUP_FORMATION) {
 			wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+					  data->ch_switch.freq_khz,
 					  data->ch_switch.ht_enabled,
 					  data->ch_switch.ch_offset,
 					  data->ch_switch.ch_width,
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 486fc6a09..90771e2d9 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -219,6 +219,7 @@ static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s)
 		    &params->freq,
 		    ifmsh->conf->hw_mode,
 		    ifmsh->freq,
+		    ifmsh->freq_khz,
 		    ifmsh->conf->channel,
 		    ifmsh->conf->enable_edmg,
 		    ifmsh->conf->edmg_channel,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e0f3240e8..52cd5eb9e 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3027,6 +3027,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 	bool is_6ghz;
 
 	freq->freq = ssid->frequency;
+	freq->freq_khz = ssid->frequency_khz;
 
 	if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) {
 		struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid);
@@ -3043,7 +3044,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 	hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
 	for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
 		if (wpa_s->hw.modes[i].mode == hw_mode &&
-		    hw_mode_get_channel(&wpa_s->hw.modes[i], freq->freq,
+		    hw_mode_get_channel(&wpa_s->hw.modes[i], freq->freq, freq->freq_khz,
 					NULL) != NULL) {
 			mode = &wpa_s->hw.modes[i];
 			break;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d5b3dab67..d333f9cbe 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -685,6 +685,7 @@ struct wpa_supplicant {
 	struct wpa_bss *current_bss;
 	int ap_ies_from_associnfo;
 	unsigned int assoc_freq;
+	unsigned int assoc_freq_khz;
 	u8 ap_mld_addr[ETH_ALEN];
 	u8 mlo_assoc_link_id;
 	u16 valid_links; /* bitmap of valid MLO link IDs */
-- 
2.34.1




More information about the Hostap mailing list