[RFC 5/8] AP: add S1G support

Lachlan Hodges lachlan.hodges at morsemicro.com
Wed May 27 23:38:54 PDT 2026


Introduce the ability to bring up an S1G AP. Currently only US 2024
channelisation is supported. A sample config is as follows:

```
interface=wlan0
country_code=US
driver=nl80211
ssid=wifi_halow

channel=43
ieee80211ah=1
op_class=71
beacon_int=100
dtim_period=10
s1g_oper_centr_freq_idx=44
s1g_primary_2mhz=1

hw_mode=ah
wpa=2
wpa_key_mgmt=SAE
rsn_pairwise=CCMP
sae_password=12345678
ieee80211w=2
```

Where we are configuring an operating channel of 44, primary 1MHz
channel of 43, whilst utilising a 2MHz primary. There is no need to
include sae_pwe=1 as H2E will automatically be enabled for S1G.
ieee80211w=2 is required, and will error if not set correctly during
config validation.

Signed-off-by: Lachlan Hodges <lachlan.hodges at morsemicro.com>
---
 hostapd/Makefile                |   5 +
 hostapd/config_file.c           |  10 ++
 src/ap/Makefile                 |   1 +
 src/ap/ap_config.c              |  34 ++++++
 src/ap/ap_config.h              |  23 ++++
 src/ap/ap_drv_ops.c             |  18 ++-
 src/ap/ap_drv_ops.h             |   4 +-
 src/ap/beacon.c                 |  97 ++++++++++++++--
 src/ap/ctrl_iface_ap.c          |   8 +-
 src/ap/dfs.c                    |   8 +-
 src/ap/hostapd.c                |  13 ++-
 src/ap/hw_features.c            |  32 +++++-
 src/ap/ieee802_11.c             |  60 ++++++++--
 src/ap/ieee802_11.h             |  10 ++
 src/ap/ieee802_11_s1g.c         | 196 ++++++++++++++++++++++++++++++++
 src/ap/ieee802_11_shared.c      |  14 +++
 src/ap/interference.c           |   1 +
 src/ap/sta_info.c               |   5 +-
 src/ap/sta_info.h               |   4 +-
 src/common/defs.h               |   6 +
 src/common/hw_features_common.c |  49 +++++++-
 src/common/hw_features_common.h |   6 +-
 src/common/ieee802_11_common.c  |  55 ++++++++-
 src/common/ieee802_11_common.h  |   6 +-
 src/common/ieee802_11_defs.h    |  55 +++++++++
 wlantest/bss.c                  |   2 +-
 26 files changed, 677 insertions(+), 45 deletions(-)
 create mode 100644 src/ap/ieee802_11_s1g.c

diff --git a/hostapd/Makefile b/hostapd/Makefile
index b2420e8474be..89f041720ace 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -355,6 +355,11 @@ CFLAGS += -DCONFIG_IEEE80211AX
 OBJS += ../src/ap/ieee802_11_he.o
 endif
 
+ifdef CONFIG_IEEE80211AH
+CFLAGS += -DCONFIG_IEEE80211AH
+OBJS += ../src/ap/ieee802_11_s1g.o
+endif
+
 ifdef CONFIG_MBO
 CFLAGS += -DCONFIG_MBO
 OBJS += ../src/ap/mbo_ap.o
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index d34b4aa83950..790e8dcc1811 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3177,6 +3177,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 {
@@ -3752,6 +3754,14 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 	} else if (os_strcmp(buf, "mbssid_max") == 0) {
 		conf->mbssid_max = atoi(pos);
 #endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211AH
+	} else if (os_strcmp(buf, "ieee80211ah") == 0) {
+		conf->ieee80211ah = atoi(pos);
+	} else if (os_strcmp(buf, "s1g_oper_centr_freq_idx") == 0) {
+		conf->s1g_oper_centr_freq_idx = atoi(pos);
+	} else if (os_strcmp(buf, "s1g_primary_2mhz") == 0) {
+		conf->s1g_primary_2mhz = atoi(pos);
+#endif /* CONFIG_IEEE80211AH */
 	} else if (os_strcmp(buf, "max_listen_interval") == 0) {
 		bss->max_listen_interval = atoi(pos);
 	} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 22a21d31eda6..790deabc2886 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -35,6 +35,7 @@ LIB_OBJS= \
 	ieee802_11_ht.o \
 	ieee802_11_shared.o \
 	ieee802_11_vht.o \
+	ieee802_11_s1g.o \
 	ieee802_1x.o \
 	interference.o \
 	neighbor_db.o \
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 36a4dad65626..7e14f3efd168 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1199,6 +1199,26 @@ static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
 }
 #endif /* CONFIG_SAE_PK */
 
+#ifdef CONFIG_IEEE80211AH
+bool hostapd_config_check_bss_s1g(struct hostapd_bss_config *bss)
+{
+	if (bss->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED) {
+		wpa_printf(MSG_ERROR,
+			   "Management frame protection is required in S1GHz (ieee80211w=2)");
+		return false;
+	}
+
+#ifdef CONFIG_SAE
+	if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) &&
+	    bss->sae_pwe != SAE_PWE_HASH_TO_ELEMENT) {
+		wpa_printf(MSG_INFO, "SAE: Forcing SAE H2E on S1GHz");
+		bss->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+	}
+#endif /* CONFIG_SAE */
+
+	return true;
+}
+#endif /* CONFIG_IEEE80211AH */
 
 bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
 {
@@ -1256,6 +1276,12 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
 	    !hostapd_config_check_bss_6g(bss))
 		return -1;
 
+#ifdef CONFIG_IEEE80211AH
+	if (full_config && conf->hw_mode ==  HOSTAPD_MODE_IEEE80211AH &&
+	    !hostapd_config_check_bss_s1g(bss))
+		return -1;
+#endif /* CONFIG_IEEE80211AH */
+
 	if (full_config && bss->ieee802_1x && !bss->eap_server &&
 	    !bss->radius->auth_servers) {
 		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
@@ -1629,6 +1655,14 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
 		return -1;
 	}
 
+#ifdef CONFIG_IEEE80211AH
+	if (full_config && conf->hw_mode == HOSTAPD_MODE_IEEE80211AH &&
+	    !is_supported_s1g_op_class(conf->op_class)) {
+		wpa_printf(MSG_ERROR, "Unsupported global op_class for S1G operation");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 	for (i = 0; i < conf->num_bss; i++) {
 		if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
 			return -1;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 3fe2206b9133..9e1d9c9e925f 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1068,6 +1068,7 @@ struct hostapd_config {
 	u8 channel;
 	int enable_edmg;
 	u8 edmg_channel;
+	bool s1g_primary_2mhz;
 	u8 acs;
 	struct wpa_freq_range_list acs_ch_list;
 	struct wpa_freq_range_list acs_freq_list;
@@ -1207,6 +1208,12 @@ struct hostapd_config {
 	bool require_he;
 #endif /* CONFIG_IEEE80211AX */
 
+	int ieee80211ah;
+#ifdef CONFIG_IEEE80211AH
+	int s1g_oper_centr_freq_idx;
+	enum oper_chan_width s1g_oper_chwidth;
+#endif /* CONFIG_IEEE80211AH */
+
 	/* VHT enable/disable config from CHAN_SWITCH */
 #define CH_SWITCH_VHT_ENABLED BIT(0)
 #define CH_SWITCH_VHT_DISABLED BIT(1)
@@ -1274,6 +1281,10 @@ struct hostapd_config {
 static inline enum oper_chan_width
 hostapd_get_oper_chwidth(struct hostapd_config *conf)
 {
+#ifdef CONFIG_IEEE80211AH
+	if (conf->ieee80211ah)
+		return conf->s1g_oper_chwidth;
+#endif
 #ifdef CONFIG_IEEE80211BE
 	if (conf->ieee80211be)
 		return conf->eht_oper_chwidth;
@@ -1289,6 +1300,10 @@ static inline void
 hostapd_set_oper_chwidth(struct hostapd_config *conf,
 			 enum oper_chan_width oper_chwidth)
 {
+#ifdef CONFIG_IEEE80211AH
+	if (conf->ieee80211ah)
+		conf->s1g_oper_chwidth = oper_chwidth;
+#endif /* CONFIG_IEEE80211AH */
 #ifdef CONFIG_IEEE80211BE
 	if (conf->ieee80211be)
 		conf->eht_oper_chwidth = oper_chwidth;
@@ -1305,6 +1320,10 @@ hostapd_set_oper_chwidth(struct hostapd_config *conf,
 static inline u8
 hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
 {
+#ifdef CONFIG_IEEE80211AH
+	if (conf->ieee80211ah)
+		return conf->s1g_oper_centr_freq_idx;
+#endif /* CONFIG_IEEE80211AH */
 #ifdef CONFIG_IEEE80211BE
 	if (conf->ieee80211be)
 		return conf->eht_oper_centr_freq_seg0_idx;
@@ -1320,6 +1339,10 @@ static inline void
 hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
 				     u8 oper_centr_freq_seg0_idx)
 {
+#ifdef CONFIG_IEEE80211AH
+	if (conf->ieee80211ah)
+		conf->s1g_oper_centr_freq_idx = oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211AH */
 #ifdef CONFIG_IEEE80211BE
 	if (conf->ieee80211be)
 		conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 5862bedff238..a10472155068 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -478,6 +478,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
 		    const struct ieee80211_eht_capabilities *eht_capab,
 		    size_t eht_capab_len,
 		    const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
+		    const struct ieee80211_s1g_capabilities *s1g_capab,
 		    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
 		    int set, const u8 *link_addr, bool mld_link_sta,
 		    u16 eml_cap, bool epp_sta)
@@ -503,6 +504,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
 	params.eht_capab = eht_capab;
 	params.eht_capab_len = eht_capab_len;
 	params.he_6ghz_capab = he_6ghz_capab;
+	params.s1g_capab = s1g_capab;
 	params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
 	params.vht_opmode = vht_opmode;
 	params.flags = hostapd_sta_flags_to_drv(flags);
@@ -650,6 +652,7 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 		     int edmg, u8 edmg_channel,
 		     int ht_enabled, int vht_enabled,
 		     int he_enabled, bool eht_enabled,
+		     int s1g_enabled,
 		     int sec_channel_offset, int oper_chwidth,
 		     int center_segment0, int center_segment1)
 {
@@ -659,7 +662,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 	if (hostapd_set_freq_params(&data, mode, freq, freq_offset,
 				    channel, edmg,
 				    edmg_channel, ht_enabled,
-				    vht_enabled, he_enabled, eht_enabled,
+				    vht_enabled, he_enabled,
+				    eht_enabled, s1g_enabled,
 				    sec_channel_offset, oper_chwidth,
 				    center_segment0, center_segment1,
 				    cmode ? cmode->vht_capab : 0,
@@ -667,7 +671,9 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 				    &cmode->he_capab[IEEE80211_MODE_AP] : NULL,
 				    cmode ?
 				    &cmode->eht_capab[IEEE80211_MODE_AP] :
-				    NULL, hostapd_get_punct_bitmap(hapd)))
+				    NULL, hostapd_get_punct_bitmap(hapd),
+				    hapd->iconf->op_class,
+				    hapd->iconf->s1g_primary_2mhz))
 		return -1;
 
 	if (hapd->driver == NULL)
@@ -1098,14 +1104,16 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
 
 	if (hostapd_set_freq_params(&data, mode, freq, 0, channel, 0, 0,
 				    ht_enabled,
-				    vht_enabled, he_enabled, eht_enabled,
+				    vht_enabled, he_enabled,
+				    eht_enabled, 0,
 				    sec_channel_offset,
 				    oper_chwidth, center_segment0,
 				    center_segment1,
 				    cmode->vht_capab,
 				    &cmode->he_capab[IEEE80211_MODE_AP],
 				    &cmode->eht_capab[IEEE80211_MODE_AP],
-				    hostapd_get_punct_bitmap(hapd))) {
+				    hostapd_get_punct_bitmap(hapd),
+				    hapd->iconf->op_class, false)) {
 		wpa_printf(MSG_ERROR, "Can't set freq params");
 		return -1;
 	}
@@ -1255,6 +1263,8 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
 
 	for (i = 0; i < hapd->iface->num_hw_features; i++) {
 		mode = &hapd->iface->hw_features[i];
+		if (mode->mode == HOSTAPD_MODE_IEEE80211AH)
+			continue;
 		if (selected_mode != HOSTAPD_MODE_IEEE80211ANY &&
 		    selected_mode != mode->mode)
 			continue;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index fa84f709de91..76e2f875fd50 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -48,6 +48,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
 		    const struct ieee80211_eht_capabilities *eht_capab,
 		    size_t eht_capab_len,
 		    const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
+		    const struct ieee80211_s1g_capabilities *s1g_capab,
 		    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
 		    int set, const u8 *link_addr, bool mld_link_sta,
 		    u16 eml_cap, bool epp_sta);
@@ -74,7 +75,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 		     int freq, int freq_offset,
 		     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,
+		     bool eht_enabled, int s1g_enabled,
+		     int sec_channel_offset, int oper_chwidth,
 		     int center_segment0, int center_segment1);
 int hostapd_set_rts(struct hostapd_data *hapd, int rts);
 int hostapd_set_frag(struct hostapd_data *hapd, int frag);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 2610106871a6..0fd541868306 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -809,8 +809,15 @@ static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_IEEE80211BE */
 
-	buflen += hostapd_eid_mbssid_len(hapd_probed, WLAN_FC_STYPE_PROBE_RESP,
-					 NULL,
+
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+	        buflen += 2 + sizeof(struct ieee80211_s1g_capabilities) +
+			  2 + sizeof(struct ieee80211_s1g_operation);
+	}
+#endif /* CONFIG_IEEE80211AH */
+
+	buflen += hostapd_eid_mbssid_len(hapd_probed, WLAN_FC_STYPE_PROBE_RESP, NULL,
 					 params->known_bss,
 					 params->known_bss_len, NULL);
 	buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP, true);
@@ -919,6 +926,13 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		pos = hostapd_eid_s1g_capab(hapd, pos);
+		pos = hostapd_eid_s1g_oper(hapd, pos);
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 #ifdef CONFIG_IEEE80211AX
 	if (hostapd_is_he_enabled(hapd) &&
 	    is_6ghz_op_class(hapd->iconf->op_class))
@@ -1504,7 +1518,11 @@ void handle_probe_req(struct hostapd_data *hapd,
 		return;
 	}
 
-	if ((!elems.ssid || !elems.supp_rates)) {
+	/*
+	 * S1G does not support legacy rates. The equivalent information is
+	 * advertised in the S1G Capabilities element.
+	 */
+	if ((!elems.ssid || (!elems.supp_rates && !elems.s1g_capabilities))) {
 		wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
 			   "without SSID or supported rates element",
 			   MAC2STR(mgmt->sa));
@@ -2234,6 +2252,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 			       struct wpa_driver_ap_params *params)
 {
 	struct ieee80211_mgmt *head = NULL;
+#ifdef CONFIG_IEEE80211AH
+	struct ieee80211_ext *ext_head = NULL;
+#endif /* CONFIG_IEEE80211AH */
 	u8 *tail = NULL;
 	size_t head_len = 0, tail_len = 0;
 	u8 *resp = NULL;
@@ -2299,6 +2320,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_IEEE80211BE */
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		/* +2 for element type + length respectively */
+		tail_len += 2 + sizeof(struct ieee80211_s1g_operation) +
+			    2 + sizeof(struct ieee80211_s1g_capabilities);
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 	if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
 	    hapd == hostapd_mbssid_get_tx_bss(hapd))
 		tail_len += 5; /* Multiple BSSID Configuration element */
@@ -2317,12 +2346,25 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	}
 	tailend = tail + tail_len;
 
-	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_BEACON);
+	if (hapd->iconf->ieee80211ah) {
+#ifdef CONFIG_IEEE80211AH
+		ext_head = (struct ieee80211_ext *)head;
+		ext_head->duration = host_to_le16(0);
+		ext_head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_EXT, WLAN_FC_STYPE_S1G_BEACON);
+		ext_head->frame_control |= WLAN_S1G_FC_BSS_BW(WLAN_S1G_BSS_BW_MIN_1_MAX_16);
+#endif /* CONFIG_IEEE80211AH */
+	} else {
+		head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_BEACON);
+	}
+
 	head->duration = host_to_le16(0);
 	os_memset(head->da, 0xff, ETH_ALEN);
 
 	os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah)
+		os_memcpy(ext_head->sa, hapd->own_addr, ETH_ALEN);
+#endif /* CONFIG_IEEE80211AH */
 	os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
 	head->u.beacon.beacon_int =
 		host_to_le16(hapd->iconf->beacon_int);
@@ -2330,7 +2372,30 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	/* hardware or low-level driver will setup seq_ctrl and timestamp */
 	capab_info = hostapd_own_capab_info(hapd);
 	head->u.beacon.capab_info = host_to_le16(capab_info);
+
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah)
+		pos = &ext_head->u.beacon.variable[0];
+	else
+		pos = &head->u.beacon.variable[0];
+#else
 	pos = &head->u.beacon.variable[0];
+#endif /* CONFIG_IEEE80211AH */
+
+	/*
+	 * As per IEEE80211-2024 11.1.3.10.1 the first element in a beacon
+	 * transmitted at a TBTT that is not a TSBTT (i.e a long beacon) shall
+	 * contain the Beacon Compatibility element as the first element in a
+	 * beacon. Therefore insert this at the head before the SSID element.
+	 * Other elements can be inserted in the tail as normal.
+	 */
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		pos = hostapd_eid_s1g_beacon_compat(hapd, pos);
+		tailpos = hostapd_eid_s1g_capab(hapd, tailpos);
+		tailpos = hostapd_eid_s1g_oper(hapd, tailpos);
+	}
+#endif /* CONFIG_IEEE80211AH */
 
 	/* SSID */
 	*pos++ = WLAN_EID_SSID;
@@ -2354,7 +2419,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	/* DS Params */
 	pos = hostapd_eid_ds_params(hapd, pos);
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah)
+		head_len = pos - (u8 *) ext_head;
+	else
+		head_len = pos - (u8 *) head;
+#else
 	head_len = pos - (u8 *) head;
+#endif /* CONFIG_IEEE80211AH */
 
 	tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
 
@@ -2590,7 +2662,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_SAE */
 
+	#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah)
+		params->head = (u8 *) ext_head;
+	else
+		params->head = (u8 *) head;
+	#else
 	params->head = (u8 *) head;
+	#endif /* CONFIG_IEEE80211AH */
 	params->head_len = head_len;
 	params->tail = tail;
 	params->tail_len = tail_len;
@@ -2812,7 +2891,7 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
 				    iconf->channel, iconf->enable_edmg,
 				    iconf->edmg_channel, iconf->ieee80211n,
 				    iconf->ieee80211ac, iconf->ieee80211ax,
-				    iconf->ieee80211be,
+				    iconf->ieee80211be, iconf->ieee80211ah,
 				    iconf->secondary_channel,
 				    hostapd_get_oper_chwidth(iconf),
 				    hostapd_get_oper_centr_freq_seg0_idx(iconf),
@@ -2820,7 +2899,9 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
 				    cmode->vht_capab,
 				    &cmode->he_capab[IEEE80211_MODE_AP],
 				    &cmode->eht_capab[IEEE80211_MODE_AP],
-				    hostapd_get_punct_bitmap(hapd)) == 0) {
+				    hostapd_get_punct_bitmap(hapd),
+				    hapd->iconf->op_class,
+				    hapd->iconf->s1g_primary_2mhz) == 0) {
 		freq.link_id = -1;
 #ifdef CONFIG_IEEE80211BE
 		if (hapd->conf->mld_ap)
@@ -2832,6 +2913,8 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
 	for (i = 0; i < hapd->iface->num_hw_features; i++) {
 		mode = &hapd->iface->hw_features[i];
 
+		if (mode->mode == HOSTAPD_MODE_IEEE80211AH)
+			continue;
 		if (iconf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
 		    iconf->hw_mode != mode->mode)
 			continue;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 90a0a49363e3..50bc35665768 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -224,6 +224,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:
@@ -885,6 +887,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
 			  "ieee80211ac=%d\n"
 			  "ieee80211ax=%d\n"
 			  "ieee80211be=%d\n"
+			  "ieee80211ah=%d\n"
 			  "beacon_int=%u\n"
 			  "dtim_period=%d\n",
 			  iface->conf->channel,
@@ -896,6 +899,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
 			  hostapd_is_vht_enabled(hapd),
 			  hostapd_is_he_enabled(hapd),
 			  hostapd_is_eht_enabled(hapd),
+			  iface->conf->ieee80211ah,
 			  iface->conf->beacon_int,
 			  hapd->conf->dtim_period);
 	if (os_snprintf_error(buflen - len, ret))
@@ -1173,7 +1177,9 @@ static struct hostapd_hw_modes * get_target_hw_mode(struct hostapd_iface *iface,
 	enum hostapd_hw_mode target_mode;
 	bool is_6ghz = is_6ghz_freq(freq);
 
-	if (freq < 4000)
+	if (freq < 1000)
+		target_mode = HOSTAPD_MODE_IEEE80211AH;
+	else if (freq < 4000)
 		target_mode = HOSTAPD_MODE_IEEE80211G;
 	else if (freq > 50000)
 		target_mode = HOSTAPD_MODE_IEEE80211AD;
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 2758454ff033..683485f85c6b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -839,7 +839,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
 	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
 	int skip_radar = 0;
 
-	if (is_6ghz_freq(iface->freq))
+	if (is_6ghz_freq(iface->freq) || is_s1ghz_freq(iface->freq))
 		return 1;
 
 	if (!iface->current_mode) {
@@ -1021,6 +1021,7 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
 				      iface->conf->ieee80211ac,
 				      iface->conf->ieee80211ax,
 				      iface->conf->ieee80211be,
+				      0, /* No DFS for S1G */
 				      secondary_channel,
 				      new_vht_oper_chwidth,
 				      oper_centr_freq_seg0_idx,
@@ -1028,7 +1029,8 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
 				      cmode->vht_capab,
 				      &cmode->he_capab[ieee80211_mode],
 				      &cmode->eht_capab[ieee80211_mode],
-				      hostapd_get_punct_bitmap(iface->bss[0]));
+				      hostapd_get_punct_bitmap(iface->bss[0]),
+				      iface->conf->op_class, false);
 
 	if (err) {
 		wpa_printf(MSG_ERROR,
@@ -1599,6 +1601,7 @@ int hostapd_is_dfs_required(struct hostapd_iface *iface)
 	if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
 	     !iface->conf->ieee80211h) ||
 	    !iface->current_mode ||
+	    iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AH ||
 	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
 		return 0;
 
@@ -1715,6 +1718,7 @@ int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
 	int i;
 
 	if (!iface->conf->ieee80211h || !mode ||
+	    mode->mode == HOSTAPD_MODE_IEEE80211AH ||
 	    mode->mode != HOSTAPD_MODE_IEEE80211A)
 		return 0;
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index a15e17919b3f..6f0b34b55de5 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -133,7 +133,8 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
 
 	if (hapd->conf->wmm_enabled < 0)
 		hapd->conf->wmm_enabled = hapd->iconf->ieee80211n |
-			hapd->iconf->ieee80211ax;
+					  hapd->iconf->ieee80211ax |
+					  hapd->iconf->ieee80211ah;
 
 #ifndef CONFIG_NO_RADIUS
 	radius_client_reconfig(hapd->radius, hapd->conf->radius);
@@ -1541,7 +1542,8 @@ setup_mld:
 
 	if (conf->wmm_enabled < 0)
 		conf->wmm_enabled = hapd->iconf->ieee80211n |
-			hapd->iconf->ieee80211ax;
+				    hapd->iconf->ieee80211ax |
+				    hapd->iconf->ieee80211ah;
 
 #ifdef CONFIG_IEEE80211R_AP
 	if (is_zero_ether_addr(conf->r1_key_holder))
@@ -2654,6 +2656,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
 				     hapd->iconf->ieee80211ac,
 				     hapd->iconf->ieee80211ax,
 				     hapd->iconf->ieee80211be,
+				     hapd->iconf->ieee80211ah,
 				     hapd->iconf->secondary_channel,
 				     hostapd_get_oper_chwidth(hapd->iconf),
 				     hostapd_get_oper_centr_freq_seg0_idx(
@@ -4532,7 +4535,8 @@ int hostapd_change_config_freq(struct hostapd_data *hapd,
 				    conf->channel, conf->enable_edmg,
 				    conf->edmg_channel, conf->ieee80211n,
 				    conf->ieee80211ac, conf->ieee80211ax,
-				    conf->ieee80211be, conf->secondary_channel,
+				    conf->ieee80211be, 0,
+				    conf->secondary_channel,
 				    hostapd_get_oper_chwidth(conf),
 				    hostapd_get_oper_centr_freq_seg0_idx(conf),
 				    hostapd_get_oper_centr_freq_seg1_idx(conf),
@@ -4541,7 +4545,8 @@ int hostapd_change_config_freq(struct hostapd_data *hapd,
 				    NULL,
 				    mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
 				    NULL,
-				    hostapd_get_punct_bitmap(hapd)))
+				    hostapd_get_punct_bitmap(hapd),
+				    hapd->iconf->op_class, false))
 		return -1;
 
 	switch (params->bandwidth) {
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 6ac7cd9d8837..b55c0a62cc75 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -261,6 +261,12 @@ int hostapd_prepare_rates(struct hostapd_data *hapd,
 	int basic_rates_g[] = { 10, 20, 55, 110, 0 };
 	const int *basic_rates;
 
+#ifdef CONFIG_IEEE80211AH
+	/* S1G does not support basic rates */
+	if (mode->mode == HOSTAPD_MODE_IEEE80211AH)
+		return 0;
+#endif
+
 	if (conf->basic_rates)
 		basic_rates = conf->basic_rates;
 	else switch (mode->mode) {
@@ -1114,6 +1120,12 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 		wpa_printf(MSG_ERROR, "Primary frequency not allowed");
 		return err;
 	}
+
+#ifdef CONFIG_IEEE80211AH
+	if (iface->conf->ieee80211ah)
+		return 1;
+#endif
+
 	err = hostapd_is_usable_edmg(iface);
 	if (err <= 0)
 		return err;
@@ -1181,7 +1193,9 @@ int hostapd_determine_mode(struct hostapd_iface *iface)
 	    iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
 		return 0;
 
-	if (iface->freq < 4000)
+	if (iface->freq < 1000)
+		target_mode = HOSTAPD_MODE_IEEE80211AH;
+	else if (iface->freq < 4000)
 		target_mode = HOSTAPD_MODE_IEEE80211G;
 	else if (iface->freq > 50000)
 		target_mode = HOSTAPD_MODE_IEEE80211AD;
@@ -1357,6 +1371,14 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
 		iface->conf->ieee80211be = 0;
 	}
 
+	if (iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211AH) {
+		wpa_printf(MSG_INFO, "Disabling HT/VHT/HE/EHT for S1G mode");
+		iface->conf->ieee80211n = 0;
+		iface->conf->ieee80211ac = 0;
+		iface->conf->ieee80211ax = 0;
+		iface->conf->ieee80211be = 0;
+	}
+
 	iface->current_mode = NULL;
 	for (i = 0; i < iface->num_hw_features; i++) {
 		struct hostapd_hw_modes *mode = &iface->hw_features[i];
@@ -1419,6 +1441,8 @@ const char * hostapd_hw_mode_txt(int mode)
 		return "IEEE 802.11g";
 	case HOSTAPD_MODE_IEEE80211AD:
 		return "IEEE 802.11ad";
+	case HOSTAPD_MODE_IEEE80211AH:
+		return "IEEE 802.11ah";
 	default:
 		return "UNKNOWN";
 	}
@@ -1466,6 +1490,12 @@ int hostapd_hw_skip_mode(struct hostapd_iface *iface,
 {
 	int i;
 
+	if (mode->mode == HOSTAPD_MODE_IEEE80211AH && !iface->current_mode)
+		return 1;
+	if (iface->current_mode &&
+	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211AH &&
+	    mode->mode == HOSTAPD_MODE_IEEE80211AH)
+		return 1;
 	if (iface->current_mode)
 		return mode != iface->current_mode;
 	if (mode->mode != HOSTAPD_MODE_IEEE80211B)
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 50f7e2a35f2e..fbb5f83f7e90 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -173,6 +173,12 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
 	u8 buf[100];
 	size_t len;
 
+#ifdef CONFIG_IEEE80211AH
+	/* No supp rates for S1G */
+	if (hapd->iconf->ieee80211ah)
+		return eid;
+#endif /* CONFIG_IEEE80211AH */
+
 	len = hostapd_supp_rates(hapd, buf);
 	if (len == 0)
 		return eid;
@@ -4971,9 +4977,10 @@ static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
 static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
 			   struct ieee802_11_elems *elems)
 {
-	/* Supported rates not used in IEEE 802.11ad/DMG */
-	if (hapd->iface->current_mode &&
-	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
+	/* Supported rates not used in IEEE 802.11ad/DMG/ah */
+	if ((hapd->iface->current_mode &&
+	     hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) ||
+	    hapd->iconf->ieee80211ah)
 		return WLAN_STATUS_SUCCESS;
 
 	if (!elems->supp_rates) {
@@ -5543,6 +5550,15 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 	}
 #endif /* CONFIG_IEEE80211BE */
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		resp = copy_sta_s1g_capab(hapd, sta, IEEE80211_MODE_AP,
+					  elems->s1g_capabilities);
+		if (resp != WLAN_STATUS_SUCCESS)
+			return resp;
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 #ifdef CONFIG_P2P
 	if (elems->p2p && ies && ies_len) {
 		wpabuf_free(sta->p2p_ie);
@@ -6471,6 +6487,9 @@ static int add_associated_sta(struct hostapd_data *hapd,
 	struct ieee80211_vht_capabilities vht_cap;
 	struct ieee80211_he_capabilities he_cap;
 	struct ieee80211_eht_capabilities eht_cap;
+#ifdef CONFIG_IEEE80211AH
+	struct ieee80211_s1g_capabilities s1g_cap;
+#endif /* CONFIG_IEEE80211AH */
 	int set = 1;
 	const u8 *mld_link_addr = NULL;
 	bool mld_link_sta = false, epp_sta = false;
@@ -6553,6 +6572,12 @@ static int add_associated_sta(struct hostapd_data *hapd,
 				      sta->eht_capab_len);
 #endif /* CONFIG_IEEE80211BE */
 
+#ifdef CONFIG_IEEE80211AH
+	if (sta->flags & WLAN_STA_S1G)
+		hostapd_get_s1g_capab(hapd, sta->s1g_capab, &s1g_cap,
+				      sizeof(s1g_cap));
+#endif /* CONFIG_IEEE80211AH */
+
 	/*
 	 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
 	 * will be set when the ACK frame for the (Re)Association Response frame
@@ -6567,7 +6592,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
 			    sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
 			    sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
 			    sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
-			    sta->he_6ghz_capab,
+			    sta->he_6ghz_capab, sta->s1g_capab,
 			    sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
 			    sta->vht_opmode, sta->p2p_ie ? 1 : 0,
 			    set, mld_link_addr, mld_link_sta, eml_cap,
@@ -6602,6 +6627,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 	struct ieee80211_mgmt *reply;
 	u8 *p;
 	u16 res = WLAN_STATUS_SUCCESS;
+	le16 aid;
 
 	buflen = sizeof(struct ieee80211_mgmt) + 1024;
 #ifdef CONFIG_FILS
@@ -6645,15 +6671,23 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 	os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
 
 	send_len = IEEE80211_HDRLEN;
-	send_len += sizeof(reply->u.assoc_resp);
 	reply->u.assoc_resp.capab_info =
 		host_to_le16(hostapd_own_capab_info(hapd));
 	reply->u.assoc_resp.status_code = host_to_le16(status_code);
 
-	reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
-					       BIT(14) | BIT(15));
+	aid = host_to_le16((sta ? sta->aid : 0) | BIT(14) | BIT(15));
+	if (hapd->iconf->ieee80211ah) {
+		/* S1G AID is carried in the AID Response element */
+		send_len += sizeof(reply->u.s1g_assoc_resp);
+		p = reply->u.s1g_assoc_resp.variable;
+	} else {
+		send_len += sizeof(reply->u.assoc_resp);
+		reply->u.assoc_resp.aid = aid;
+		p = reply->u.assoc_resp.variable;
+	}
+
 	/* Supported rates */
-	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
+	p = hostapd_eid_supp_rates(hapd, p);
 	/* Extended supported rates */
 	p = hostapd_eid_ext_supp_rates(hapd, p);
 
@@ -6747,6 +6781,14 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 	}
 #endif /* CONFIG_IEEE80211AX */
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		p = hostapd_eid_s1g_capab(hapd, p);
+		p = hostapd_eid_s1g_oper(hapd, p);
+		p = hostapd_eid_aid_response(hapd, p, aid);
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 	p = hostapd_eid_ext_capab(hapd, p, false);
 	p = hostapd_eid_bss_max_idle_period(hapd, p,
 					    sta ? sta->max_idle_period : 0);
@@ -7339,7 +7381,7 @@ static void handle_assoc(struct hostapd_data *hapd,
 			hostapd_logger(hapd, mgmt->sa,
 				       HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_INFO,
-				       "Station tried to associate before authentication (aid=%d flags=0x%x)",
+				       "Station tried to associate before authentication (aid=%d flags=0x%lx)",
 				       sta ? sta->aid : -1,
 				       sta ? sta->flags : 0);
 			send_deauth(hapd, mgmt->sa,
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 664d585b994c..38cb181aa850 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -103,6 +103,10 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_s1g_oper(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_s1g_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_s1g_beacon_compat(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_aid_response(struct hostapd_data *hapd, u8 *eid, le16 aid);
 
 int hostapd_ht_operation_update(struct hostapd_iface *iface);
 void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@@ -189,6 +193,12 @@ int hostapd_update_time_adv(struct hostapd_data *hapd);
 void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
 				     u16 value);
+u16 copy_sta_s1g_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		       enum ieee80211_op_mode opmode, const u8 *s1g_capab);
+void hostapd_get_s1g_capab(struct hostapd_data *hapd,
+			   const struct ieee80211_s1g_capabilities *src,
+			   struct ieee80211_s1g_capabilities *dest,
+			   size_t len);
 
 int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
 #ifdef CONFIG_SAE
diff --git a/src/ap/ieee802_11_s1g.c b/src/ap/ieee802_11_s1g.c
new file mode 100644
index 000000000000..b79de44bd4f2
--- /dev/null
+++ b/src/ap/ieee802_11_s1g.c
@@ -0,0 +1,196 @@
+/*
+ * hostapd / IEEE 802.11ah S1G
+ * Copyright (c) 2022, Morse Micro
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+/* 1SS, MCS9. TODO set via config */
+#define S1G_BASIC_MCS_NSS 0xCCC4
+
+static u8 hostapd_global_op_class_to_s1g_op_class(u8 global)
+{
+	switch(global) {
+		/* US */
+		case 68: return 1;
+		case 69: return 2;
+		case 70: return 3;
+		case 71: return 4;
+		case 72: return 5;
+		default: return 0;
+	}
+}
+
+static u8 hostapd_s1g_calc_pri_1mhz_loc(struct hostapd_data *hapd)
+{
+	u8 low_chan;
+	u8 pri_1mhz_chan = hapd->iconf->channel;
+	u8 oper_ch = hapd->iconf->s1g_oper_centr_freq_idx ?
+		     hapd->iconf->s1g_oper_centr_freq_idx :
+		     hapd->iconf->channel;
+
+	if (hapd->iconf->s1g_oper_chwidth == CONF_OPER_CHWIDTH_1MHZ)
+		return 0;
+
+	switch (hapd->iconf->s1g_oper_chwidth) {
+	case CONF_OPER_CHWIDTH_4MHZ:
+		low_chan = oper_ch - 3;
+		break;
+	case CONF_OPER_CHWIDTH_8MHZ:
+		low_chan = oper_ch - 7;
+		break;
+	case CONF_OPER_CHWIDTH_16MHZ:
+		low_chan = oper_ch - 15;
+		break;
+	default:
+		return 0;
+	}
+
+	return ((pri_1mhz_chan - low_chan) / 2) & 1;
+}
+
+u8 *hostapd_eid_s1g_oper(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_s1g_operation *cap;
+	u8 *pos = eid;
+	u8 ch_width = 0;
+	u8 bss_width;
+	u8 s1g_pri_loc = hostapd_s1g_calc_pri_1mhz_loc(hapd);
+
+	*pos++ = WLAN_EID_S1G_OPERATION;
+	*pos++ = sizeof(*cap);
+
+	cap = (struct ieee80211_s1g_operation *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+
+	/* IEEE80211-2024 Table 10-39 */
+	switch (hapd->iconf->s1g_oper_chwidth) {
+	case CONF_OPER_CHWIDTH_1MHZ:
+		bss_width = 0x0;
+		break;
+	case CONF_OPER_CHWIDTH_2MHZ:
+		bss_width = 0x1;
+		break;
+	case CONF_OPER_CHWIDTH_4MHZ:
+		bss_width = 0x3;
+		break;
+	case CONF_OPER_CHWIDTH_8MHZ:
+		bss_width = 0x7;
+		break;
+	case CONF_OPER_CHWIDTH_16MHZ:
+		bss_width = 0xF;
+		break;
+	default:
+		return NULL;
+	}
+
+	if (!hapd->iconf->s1g_primary_2mhz)
+		ch_width |= S1G_OPER_IE_CHANWIDTH_PRIM_CH_MASK;
+
+	ch_width |= (bss_width << 1) & S1G_OPER_IE_CHANWIDTH_OPER_CH_MASK;
+
+	if (hapd->iconf->s1g_primary_2mhz && s1g_pri_loc)
+		ch_width |= S1G_OPER_IE_CHANWIDTH_PRIM_OFFSET;
+
+	cap->ch_width = ch_width;
+	cap->oper_class = hostapd_global_op_class_to_s1g_op_class(hapd->iconf->op_class);
+	cap->basic_mcs_nss = host_to_le16(S1G_BASIC_MCS_NSS);
+
+	if (hapd->iconf->s1g_primary_2mhz) {
+		if (s1g_pri_loc)
+			cap->primary_ch = hapd->iconf->channel - 1;
+		else
+			cap->primary_ch = hapd->iconf->channel + 1;
+	} else {
+		cap->primary_ch = hapd->iconf->channel;
+	}
+
+	cap->oper_ch = hapd->iconf->s1g_oper_centr_freq_idx ?
+		       hapd->iconf->s1g_oper_centr_freq_idx :
+		       cap->primary_ch;
+
+	pos += sizeof(*cap);
+	return pos;
+}
+
+u8 * hostapd_eid_s1g_capab(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_s1g_capabilities *cap;
+	u8 *pos = eid;
+
+	*pos++ = WLAN_EID_S1G_CAPABILITIES;
+	*pos++ = sizeof(*cap);
+
+	cap = (struct ieee80211_s1g_capabilities *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+
+	os_memcpy(cap, &hapd->iface->current_mode->s1g_capab, sizeof(*cap));
+
+	pos += sizeof(*cap);
+	return pos;
+}
+
+
+u8 * hostapd_eid_s1g_beacon_compat(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	u16 beacon_int;
+
+	beacon_int = hapd->iconf->beacon_int;
+
+	*pos++ = WLAN_EID_S1G_BCN_COMPAT;
+	*pos++ = 8;
+	*pos++ = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY;;
+	*pos++ = 0;
+
+	*pos++ = beacon_int & 0xff;
+	*pos++ = (beacon_int >> 8) & 0xff;
+
+	/*
+	 * Last 4 octets will be filled by the driver/fw to contain the 4
+	 * MSB of the TSF timer at time of generation.
+	 */
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	return pos;
+}
+
+u16 copy_sta_s1g_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		       enum ieee80211_op_mode opmode, const u8 *s1g_capab)
+{
+	sta->s1g_capab = os_memdup(s1g_capab, sizeof(struct ieee80211_s1g_capabilities));
+	if (!sta->s1g_capab)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	sta->flags |= WLAN_STA_S1G;
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+void hostapd_get_s1g_capab(struct hostapd_data *hapd,
+			   const struct ieee80211_s1g_capabilities *src,
+			   struct ieee80211_s1g_capabilities *dest,
+			   size_t len)
+{
+	if (!src || !dest)
+		return;
+
+	if (len > sizeof(*dest))
+		len = sizeof(*dest);
+
+	os_memset(dest, 0, sizeof(*dest));
+	os_memcpy(dest, src, len);
+}
\ No newline at end of file
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index a6decab8d97b..42b1efe471aa 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -496,6 +496,20 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx,
 	}
 }
 
+u8 * hostapd_eid_aid_response(struct hostapd_data *hapd, u8 *eid, le16 aid)
+{
+	u8 *pos = eid;
+	const u8 len = 5;
+
+	*pos++ = WLAN_EID_AID_RESPONSE;
+	*pos++ = len;
+
+	memset(pos, 0, len);
+	u8 *end = pos + len;
+	*pos++ = aid;
+
+	return end;
+}
 
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid,
 			   bool mbssid_complete)
diff --git a/src/ap/interference.c b/src/ap/interference.c
index 44aa6c0019ef..12ab133c32d6 100644
--- a/src/ap/interference.c
+++ b/src/ap/interference.c
@@ -558,6 +558,7 @@ int hostapd_incumbt_sig_intf_detected(struct hostapd_iface *iface, int freq,
 			    iface->conf->ieee80211ac,
 			    iface->conf->ieee80211ax,
 			    iface->conf->ieee80211be,
+			    iface->conf->ieee80211ah,
 			    iface->conf->secondary_channel,
 			    hostapd_get_oper_chwidth(iface->conf),
 			    hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 2bb7e1235cb0..246996054e44 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -474,6 +474,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 	os_free(sta->he_capab);
 	os_free(sta->he_6ghz_capab);
 	os_free(sta->eht_capab);
+	os_free(sta->s1g_capab);
 	hostapd_free_psk_list(sta->psk);
 	os_free(sta->identity);
 	os_free(sta->radius_cui);
@@ -602,7 +603,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
 	int reason;
 	int max_inactivity = hapd->conf->ap_max_inactivity;
 
-	wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
+	wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%lx timeout_next=%d",
 		   hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
 		   sta->timeout_next);
 	if (sta->timeout_next == STA_REMOVE) {
@@ -2115,7 +2116,7 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
 	if (hostapd_sta_add(hapd, sta->addr, 0, 0,
 			    sta->supported_rates,
 			    sta->supported_rates_len,
-			    0, NULL, NULL, NULL, 0, NULL, 0, NULL,
+			    0, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL,
 			    sta->flags, 0, 0, 0, 0,
 			    mld_link_addr, mld_link_sta, eml_cap, epp_sta)) {
 		hostapd_logger(hapd, sta->addr,
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9810eb22f9a4..10dfdb935892 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -49,6 +49,7 @@
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
+#define WLAN_STA_S1G 1ull << 32
 
 /* Maximum number of supported rates (from both Supported Rates and Extended
  * Supported Rates IEs). */
@@ -112,7 +113,7 @@ struct sta_info {
 	struct dl_list ip6addr; /* list head for struct ip6addr */
 	u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
 	u16 disconnect_reason_code; /* RADIUS server override */
-	u32 flags; /* Bitfield of WLAN_STA_* */
+	u64 flags; /* Bitfield of WLAN_STA_* */
 	u16 capability;
 	u16 listen_interval; /* or beacon_int for APs */
 	u8 supported_rates[WLAN_SUPP_RATES_MAX];
@@ -226,6 +227,7 @@ struct sta_info {
 	struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
 	struct ieee80211_eht_capabilities *eht_capab;
 	size_t eht_capab_len;
+	struct ieee80211_s1g_capabilities *s1g_capab;
 
 	int sa_query_count; /* number of pending SA Query requests;
 			     * 0 = no SA Query in progress */
diff --git a/src/common/defs.h b/src/common/defs.h
index ec602d660ace..0ba6f5ae5a59 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -418,6 +418,7 @@ enum hostapd_hw_mode {
 	HOSTAPD_MODE_IEEE80211G,
 	HOSTAPD_MODE_IEEE80211A,
 	HOSTAPD_MODE_IEEE80211AD,
+	HOSTAPD_MODE_IEEE80211AH,
 	HOSTAPD_MODE_IEEE80211ANY,
 	NUM_HOSTAPD_MODES
 };
@@ -510,6 +511,11 @@ enum oper_chan_width {
 	CONF_OPER_CHWIDTH_8640MHZ,
 	CONF_OPER_CHWIDTH_40MHZ_6GHZ,
 	CONF_OPER_CHWIDTH_320MHZ,
+	CONF_OPER_CHWIDTH_1MHZ,
+	CONF_OPER_CHWIDTH_2MHZ,
+	CONF_OPER_CHWIDTH_4MHZ,
+	CONF_OPER_CHWIDTH_8MHZ,
+	CONF_OPER_CHWIDTH_16MHZ,
 };
 
 enum key_flag {
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 32471ce36651..cd17bb6d5546 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -485,13 +485,15 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    int channel, int enable_edmg,
 			    u8 edmg_channel, int ht_enabled,
 			    int vht_enabled, int he_enabled,
-			    bool eht_enabled, int sec_channel_offset,
+			    bool eht_enabled, int s1g_enabled,
+			    int sec_channel_offset,
 			    enum oper_chan_width oper_chwidth,
 			    int center_segment0,
 			    int center_segment1, u32 vht_caps,
 			    struct he_capabilities *he_cap,
 			    struct eht_capabilities *eht_cap,
-			    u16 punct_bitmap)
+			    u16 punct_bitmap, int op_class,
+			    bool s1g_primary_2mhz)
 {
 	enum oper_chan_width oper_chwidth_legacy;
 	u8 seg0_legacy, seg1_legacy;
@@ -509,10 +511,12 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
 	data->vht_enabled = vht_enabled;
 	data->he_enabled = he_enabled;
 	data->eht_enabled = eht_enabled;
+	data->s1g_enabled = s1g_enabled;
 	data->sec_channel_offset = sec_channel_offset;
 	data->center_freq1 = freq + sec_channel_offset * 10;
 	data->center_freq2 = 0;
 	data->punct_bitmap = punct_bitmap;
+	data->s1g_primary_2mhz = s1g_primary_2mhz;
 	if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
 		data->bandwidth = 80;
 	else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
@@ -529,7 +533,40 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
 	hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel,
 				 &data->edmg);
 
-	if (is_6ghz_freq(freq)) {
+	if (is_s1ghz_freq(freq)) {
+		if (oper_chwidth == CONF_OPER_CHWIDTH_16MHZ)
+			data->bandwidth = 16;
+		else if (oper_chwidth == CONF_OPER_CHWIDTH_8MHZ)
+			data->bandwidth = 8;
+		else if (oper_chwidth == CONF_OPER_CHWIDTH_4MHZ)
+			data->bandwidth = 4;
+		else if (oper_chwidth == CONF_OPER_CHWIDTH_2MHZ)
+			data->bandwidth = 2;
+		else
+			data->bandwidth = 1;
+
+		if (!center_segment0) {
+			data->center_freq1 = data->freq;
+			data->center_freq1_offset = data->freq_offset;
+		} else {
+			int freq1 = ieee80211_chan_to_freq_khz(NULL, op_class, center_segment0);
+			if (freq1 < 0) {
+				wpa_printf(MSG_ERROR,
+					   "Invalid segment 0 center frequency for S1G");
+				return -1;
+			}
+
+			data->center_freq1 = KHZ_TO_MHZ(freq1);
+			data->center_freq1_offset = KHZ_TO_S1G_OFFSET(freq1);
+		}
+
+		data->ht_enabled  = 0;
+		data->vht_enabled = 0;
+		data->he_enabled  = 0;
+		data->eht_enabled = 0;
+		data->center_freq2 = 0;
+		return 0;
+	} else if (is_6ghz_freq(freq)) {
 		if (!data->he_enabled && !data->eht_enabled) {
 			wpa_printf(MSG_ERROR,
 				   "Can't set 6 GHz mode - HE or EHT aren't enabled");
@@ -962,6 +999,12 @@ int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
 	u32 bw_mask;
 
 	switch (bw) {
+	case 4:
+		return chan->allowed_bw & HOSTAPD_CHAN_WIDTH_4;
+	case 8:
+		return chan->allowed_bw & HOSTAPD_CHAN_WIDTH_8;
+	case 16:
+		return chan->allowed_bw & HOSTAPD_CHAN_WIDTH_16;
 	case 20:
 		bw_mask = HOSTAPD_CHAN_WIDTH_20;
 		break;
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 63c0893e2c2b..58138c49fe42 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -45,13 +45,15 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    int channel, int edmg, u8 edmg_channel,
 			    int ht_enabled,
 			    int vht_enabled, int he_enabled,
-			    bool eht_enabled, int sec_channel_offset,
+			    bool eht_enabled, int s1g_enabled,
+			    int sec_channel_offset,
 			    enum oper_chan_width oper_chwidth,
 			    int center_segment0,
 			    int center_segment1, u32 vht_caps,
 			    struct he_capabilities *he_caps,
 			    struct eht_capabilities *eht_cap,
-			    u16 punct_bitmap);
+			    u16 punct_bitmap, int op_class,
+			    bool s1g_primary_2mhz);
 void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
 		      int disabled);
 int ieee80211ac_cap_check(u32 hw, u32 conf);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index a3b9592e23bc..88dbe0fc83ba 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -702,7 +702,7 @@ static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len,
 		case WLAN_EID_S1G_CAPABILITIES:
 			if (elen < 15)
 				break;
-			elems->s1g_capab = pos;
+			elems->s1g_capabilities = pos;
 			break;
 		case WLAN_EID_FRAGMENT:
 			wpa_printf(MSG_MSGDUMP,
@@ -714,6 +714,16 @@ static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len,
 						       len, show_errors))
 				unknown++;
 			break;
+		case WLAN_EID_S1G_OPERATION:
+			if (elen < sizeof(struct ieee80211_s1g_operation))
+				break;
+			elems->s1g_operation = pos;
+			break;
+		case WLAN_EID_AID_RESPONSE:
+			if (elen < sizeof(struct ieee80211_aid_response))
+				break;
+			elems->aid_response = pos;
+			break;
 		default:
 			unknown++;
 			if (!show_errors)
@@ -917,7 +927,10 @@ void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems,
 			elems->dils_len = 0;
 			break;
 		case WLAN_EID_S1G_CAPABILITIES:
-			elems->s1g_capab = NULL;
+			elems->s1g_capabilities = NULL;
+			break;
+		case WLAN_EID_S1G_OPERATION:
+			elems->s1g_operation = NULL;
 			break;
 		}
 	}
@@ -1515,6 +1528,9 @@ ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
 
 	/* TODO: more operating classes */
 
+	if (is_s1ghz_freq(freq))
+		return HOSTAPD_MODE_IEEE80211AH;
+
 	if (sec_channel > 1 || sec_channel < -1)
 		return NUM_HOSTAPD_MODES;
 
@@ -2022,10 +2038,6 @@ static int ieee80211_chan_to_freq_khz_global(u8 op_class, u8 chan)
 {
 	/* Table E-4 in IEEE Std 802.11-2020 - Global operating classes */
 	switch (op_class) {
-	case 50:
-	case 51:
-	case 52:
-	case 53:
 	case 68:
 	case 69:
 	case 70:
@@ -3165,6 +3177,12 @@ bool is_same_band(int freq1, int freq2)
 }
 
 
+bool is_s1ghz_freq(int freq)
+{
+	return freq < 1000;
+}
+
+
 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
 				    size_t nei_rep_len)
 {
@@ -3453,6 +3471,16 @@ int op_class_to_bandwidth(u8 op_class)
 enum oper_chan_width op_class_to_ch_width(u8 op_class)
 {
 	switch (op_class) {
+	case 68: /* S1G 2024 US 1MHz */
+		return CONF_OPER_CHWIDTH_1MHZ;
+	case 69: /* S1G 2024 US 2MHz */
+		return CONF_OPER_CHWIDTH_2MHZ;
+	case 70: /* S1G 2024 US 4MHz */
+		return CONF_OPER_CHWIDTH_4MHZ;
+	case 71: /* S1G 2024 US 8MHz */
+		return CONF_OPER_CHWIDTH_8MHZ;
+	case 72: /* S1G 2024 US 16MHz */
+		return CONF_OPER_CHWIDTH_16MHZ;
 	case 81:
 	case 82:
 		return CONF_OPER_CHWIDTH_USE_HT;
@@ -4311,3 +4339,18 @@ int ieee80211_get_center_freq(int ctrl_freq, u32 bw)
 		return -1;
 	}
 }
+
+bool is_supported_s1g_op_class(u8 op_class)
+{
+	switch (op_class) {
+		/* IEEE80211-2024 US */
+		case 68:
+		case 69:
+		case 70:
+		case 71:
+		case 72:
+			return true;
+		default:
+			return false;
+	}
+}
\ No newline at end of file
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ed0147812fde..12a0eb6ca252 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -111,7 +111,7 @@ struct ieee802_11_elems {
 	const u8 *short_ssid_list;
 	const u8 *he_6ghz_band_cap;
 	const u8 *sae_pk;
-	const u8 *s1g_capab;
+	const u8 *s1g_capabilities;
 	const u8 *pasn_params;
 	const u8 *eht_capabilities;
 	const u8 *eht_operation;
@@ -131,6 +131,8 @@ struct ieee802_11_elems {
 	const u8 *akm_suite_selector;
 	const u8 *supported_groups;
 	const u8 *nan_ie;
+	const u8 *s1g_operation;
+	const u8 *aid_response;
 
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -331,6 +333,8 @@ int get_6ghz_sec_channel(int channel);
 bool is_same_band(int freq1, int freq2);
 #define IS_2P4GHZ(n) (n >= 2412 && n <= 2484)
 #define IS_5GHZ(n) (n > 4000 && n < 5895)
+bool is_s1ghz_freq(int freq);
+bool is_supported_s1g_op_class(u8 op_class);
 
 u8 op_class_idx_to_chan(const struct oper_class_map *op, u8 idx);
 int op_class_chan_to_idx(const struct oper_class_map *op, u8 chan);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index febaab8f1be3..992585859dd8 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -89,6 +89,12 @@
 #define WLAN_FC_STYPE_DMG_BEACON	0
 #define WLAN_FC_STYPE_S1G_BEACON	1
 
+#define WLAN_S1G_BSS_BW_MIN_1_MAX_16	7
+
+#define WLAN_S1G_FC_BSS_BW_SHIFT        11
+#define WLAN_S1G_FC_BSS_BW_MASK         (0x7 << WLAN_S1G_FC_BSS_BW_SHIFT)
+#define WLAN_S1G_FC_BSS_BW(bw)          (((bw) & 0x7) << WLAN_S1G_FC_BSS_BW_SHIFT)
+
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN			0
 #define WLAN_AUTH_SHARED_KEY		1
@@ -482,7 +488,10 @@
 #define WLAN_EID_DEVICE_LOCATION 204
 #define WLAN_EID_WHITE_SPACE_MAP 205
 #define WLAN_EID_FTM_PARAMETERS 206
+#define WLAN_EID_AID_REQUEST 210
+#define WLAN_EID_AID_RESPONSE 211
 #define WLAN_EID_S1G_BCN_COMPAT 213
+#define WLAN_EID_S1G_SHORT_BCN_INTERVAL 214
 #define WLAN_EID_TWT 216
 #define WLAN_EID_S1G_CAPABILITIES 217
 #define WLAN_EID_VENDOR_SPECIFIC 221
@@ -1009,6 +1018,7 @@ struct ieee80211_hdr {
 
 #define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
 
+/* TODO this needs to be removed */
 struct ieee80211_hdr_s1g_beacon {
 	le16 frame_control;
 	le16 duration_id;
@@ -1060,6 +1070,11 @@ struct ieee80211_mgmt {
 			/* followed by Supported rates */
 			u8 variable[];
 		} STRUCT_PACKED assoc_resp, reassoc_resp;
+		struct {
+			le16 capab_info;
+			le16 status_code;
+			u8 variable[];
+		} STRUCT_PACKED s1g_assoc_resp, s1g_reassoc_resp;
 		struct {
 			le16 capab_info;
 			le16 listen_interval;
@@ -1231,6 +1246,18 @@ struct ieee80211_mgmt {
 	} u;
 } STRUCT_PACKED;
 
+struct ieee80211_ext {
+	le16 frame_control;
+	le16 duration;
+	u8 sa[6];
+	union {
+		struct {
+			u8 timestamp[4];
+			u8 change_seq;
+			u8 variable[];
+		} STRUCT_PACKED beacon;
+	} u;
+} STRUCT_PACKED;
 
 #define IEEE80211_MIN_ACTION_LEN(type)	\
 	(offsetof(struct ieee80211_mgmt, u.action.u.type) + \
@@ -2691,6 +2718,34 @@ struct ieee80211_he_mu_edca_parameter_set {
 /* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
 #define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
 
+struct ieee80211_s1g_capabilities {
+	u8 capab_info[10];
+	u8 supp_mcs_nss[5];
+} STRUCT_PACKED;
+
+struct ieee80211_s1g_operation {
+	u8 ch_width;
+	u8 oper_class;
+	u8 primary_ch;
+	u8 oper_ch;
+	le16 basic_mcs_nss;
+} STRUCT_PACKED;
+
+struct ieee80211_aid_response {
+	u16 aid;
+	u8 switch_count;
+	u16 response_interval;
+} STRUCT_PACKED;
+
+#define S1G_OPER_IE_CHANWIDTH_PRIM_CH_MASK     (BIT(0))
+#define S1G_OPER_IE_CHANWIDTH_OPER_CH_MASK     (BIT(1) | BIT(2) | \
+						BIT(3) | BIT(4))
+#define S1G_OPER_IE_CHANWIDTH_PRIM_OFFSET      (BIT(5))
+#define S1G_OPER_IE_MAX_MCS_1_NSS_SHIFT        (2)
+#define S1G_OPER_IE_MAX_MCS_2_NSS_SHIFT        (6)
+#define S1G_OPER_IE_MAX_MCS_3_NSS_SHIFT        (10)
+#define S1G_OPER_IE_MAX_MCS_4_NSS_SHIFT        (14)
+
 /*
  * IEEE Std 802.11-2020 and IEEE Std 802.11ax-2021
  * 9.4.2.170 Reduced Neighbor Report element
diff --git a/wlantest/bss.c b/wlantest/bss.c
index 0e94ab1cc240..5879b8b0ba70 100644
--- a/wlantest/bss.c
+++ b/wlantest/bss.c
@@ -178,7 +178,7 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
 	 * Probe Response frames. Note this assumes short beacons were dropped
 	 * due to missing SSID above.
 	 */
-	if (!elems->rsn_ie && (!elems->s1g_capab || beacon != 1)) {
+	if (!elems->rsn_ie && (!elems->s1g_capabilities || beacon != 1)) {
 		if (bss->rsnie[0]) {
 			add_note(wt, MSG_INFO, "BSS " MACSTR
 				 " - RSN IE removed", MAC2STR(bss->bssid));
-- 
2.43.0




More information about the Hostap mailing list