[PATCH 4/6] S1G: Add support for S1G Manangement frames

Bassem Dawood bassem at morsemicro.com
Tue Oct 31 22:34:29 PDT 2023


S1G beacons use the new extention frame format introduced in the ieee80211
specification to support 802.11ah. The new features included in this
commit are:
	- S1G short beacon
	- extention frame format

This commit additional adds support for the following new information
elements:
	- s1g_capabilities
	- s1g_operation
	- s1g_short_beacon_interval
	- s1g_aid_response
---
 hostapd/config_file.c             |   9 ++
 src/ap/ap_config.h                |   1 +
 src/ap/beacon.c                   |  94 +++++++++++++++++++--
 src/ap/hw_features.c              |   3 +-
 src/ap/ieee802_11.c               |  25 +++++-
 src/ap/ieee802_11.h               |   5 ++
 src/ap/ieee802_11_s1g.c           | 131 ++++++++++++++++++++++++++++++
 src/ap/ieee802_11_shared.c        |  14 ++++
 src/common/ieee802_11_defs.h      |  42 ++++++++++
 src/drivers/driver.h              |  16 +++-
 src/drivers/driver_nl80211.c      |   2 +
 src/drivers/driver_nl80211_capa.c |  20 +++++
 src/drivers/nl80211_copy.h        |   2 +
 13 files changed, 351 insertions(+), 13 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 6be294ed3..110de53c4 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3216,6 +3216,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 			return 1;
 		}
 		bss->dtim_period = val;
+	} else if (os_strcmp(buf, "short_beacon_int") == 0) {
+		int val = atoi(pos);
+
+		if (val < 1 || val > 65535) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid short_beacon_int %d",
+				   line, val);
+			return 1;
+		}
+		bss->short_beacon_int = val;
 	} else if (os_strcmp(buf, "bss_load_update_period") == 0) {
 		int val = atoi(pos);
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2901d2b86..74b3ef1bd 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -294,6 +294,7 @@ struct hostapd_bss_config {
 	int max_num_sta; /* maximum number of STAs in station table */
 
 	int dtim_period;
+	int short_beacon_int;
 	unsigned int bss_load_update_period;
 	unsigned int chan_util_avg_period;
 
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index b8431e4a9..a6e70cdd6 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -616,6 +616,13 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_IEEE80211BE */
 
+#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, WLAN_FC_STYPE_PROBE_RESP, NULL,
 					 known_bss, known_bss_len, NULL);
 	buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
@@ -775,6 +782,14 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 		pos = hostapd_eid_vendor_vht(hapd, pos);
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		pos = hostapd_eid_s1g_capab(hapd, pos);
+		pos = hostapd_eid_s1g_oper(hapd, pos);
+		pos = hostapd_eid_s1g_short_beacon_int(hapd, pos);
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 	/* WPA / OSEN */
 	pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
 	pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
@@ -1072,7 +1087,7 @@ void handle_probe_req(struct hostapd_data *hapd,
 		return;
 	}
 
-	if ((!elems.ssid || !elems.supp_rates)) {
+	if ((!elems.ssid || (!elems.supp_rates && !elems.s1g_capab))) {
 		wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
 			   "without SSID or supported rates element",
 			   MAC2STR(mgmt->sa));
@@ -1708,10 +1723,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 			       struct wpa_driver_ap_params *params)
 {
 	struct ieee80211_mgmt *head = NULL;
+	struct ieee80211_ext *ext_head = NULL;
 	u8 *tail = NULL;
 	size_t head_len = 0, tail_len = 0;
 	u8 *resp = NULL;
 	size_t resp_len = 0;
+#ifdef CONFIG_IEEE80211AH
+	u8 bss_bw;
+#endif
+
 #ifdef NEED_AP_MLME
 	u16 capab_info;
 	u8 *pos, *tailpos, *tailend, *csa_pos;
@@ -1724,6 +1744,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
 	head = os_zalloc(BEACON_HEAD_BUF_SIZE);
+	ext_head = os_zalloc(BEACON_HEAD_BUF_SIZE);
 	tail_len = BEACON_TAIL_BUF_SIZE;
 #ifdef CONFIG_WPS
 	if (hapd->conf->wps_state && hapd->wps_beacon_ie)
@@ -1782,6 +1803,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_IEEE80211BE */
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		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 */
@@ -1799,12 +1827,43 @@ 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) {
+		ext_head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_EXT, WLAN_FC_STYPE_S1G_BEACON);
+#ifdef CONFIG_IEEE80211AH
+		/* For the time being we are supporting only 2 MHz as the minimum BW */
+		switch (hapd->iconf->s1g_oper_chwidth) {
+		case 0:
+			/* No support in the spec for Maximum BSS BW for 1 MHz */
+			bss_bw = 0;
+			break;
+		case 1:
+			bss_bw = 0;
+			break;
+		case 2:
+			bss_bw = 3;
+			break;
+		case 3:
+			bss_bw = 5;
+			break;
+		case 4:
+			bss_bw = 7;
+			break;
+		default:
+			/* An S1G AP should always support the minimum bss_bw */
+			bss_bw = 0;
+			break;
+		}
+		ext_head->frame_control |= bss_bw << 11;
+#endif /* CONFIG_IEEE80211AH */
+	} else
+		head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_BEACON);
+
 	head->duration = host_to_le16(0);
+	ext_head->duration = host_to_le16(0);
 	os_memset(head->da, 0xff, ETH_ALEN);
 
 	os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(ext_head->sa, hapd->own_addr, ETH_ALEN);
 	os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
 	head->u.beacon.beacon_int =
 		host_to_le16(hapd->iconf->beacon_int);
@@ -1812,7 +1871,11 @@ 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);
-	pos = &head->u.beacon.variable[0];
+
+	if (hapd->iconf->ieee80211ah)
+		pos = &ext_head->u.beacon.variable[0];
+	else
+		pos = &head->u.beacon.variable[0];
 
 	/* SSID */
 	*pos++ = WLAN_EID_SSID;
@@ -1834,9 +1897,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	pos = hostapd_eid_supp_rates(hapd, pos);
 
 	/* DS Params */
-	pos = hostapd_eid_ds_params(hapd, pos);
+	if (!hapd->iconf->ieee80211ah)
+		pos = hostapd_eid_ds_params(hapd, pos);
 
-	head_len = pos - (u8 *) head;
+	if (hapd->iconf->ieee80211ah)
+		head_len = pos - (u8 *) ext_head;
+	else
+		head_len = pos - (u8 *) head;
 
 	tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
 
@@ -1963,6 +2030,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 		tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AH
+	if (hapd->iconf->ieee80211ah) {
+		tailpos = hostapd_eid_s1g_beacon_compat(hapd, tailpos);
+		tailpos = hostapd_eid_s1g_capab(hapd, tailpos);
+		tailpos = hostapd_eid_s1g_oper(hapd, tailpos);
+		tailpos = hostapd_eid_s1g_short_beacon_int(hapd, tailpos);
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 	/* WPA / OSEN */
 	tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
 	tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
@@ -2011,7 +2087,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
 #endif /* NEED_AP_MLME */
 
-	params->head = (u8 *) head;
+	if (hapd->iconf->ieee80211ah)
+		params->head = (u8 *) ext_head;
+	else
+		params->head = (u8 *) head;
 	params->head_len = head_len;
 	params->tail = tail;
 	params->tail_len = tail_len;
@@ -2021,6 +2100,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	params->beacon_int = hapd->iconf->beacon_int;
 	params->basic_rates = hapd->iface->basic_rates;
 	params->beacon_rate = hapd->iconf->beacon_rate;
+	params->short_beacon_int = hapd->conf->short_beacon_int;
 	params->rate_type = hapd->iconf->rate_type;
 	params->ssid = hapd->conf->ssid.ssid;
 	params->ssid_len = hapd->conf->ssid.ssid_len;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 963c3d45b..0009a19e5 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -242,7 +242,8 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
 	}
 
 	if ((iface->num_rates == 0 || num_basic_rates == 0) &&
-	    (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
+	    (!iface->conf->ieee80211n || !iface->conf->require_ht) &&
+	    !iface->conf->ieee80211ah) {
 		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
 			   "rate sets (%d,%d).",
 			   iface->num_rates, num_basic_rates);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index a9b3e8c60..9abac5867 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -111,6 +111,10 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
 	if (hapd->iface->current_rates == NULL)
 		return eid;
 
+	/* 802.11ah does not need to include the support rates element */
+	if (hapd->iconf->ieee80211ah)
+		return eid;
+
 	*pos++ = WLAN_EID_SUPP_RATES;
 	num = hapd->iface->num_rates;
 	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
@@ -3452,8 +3456,9 @@ 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)
+	if ((hapd->iface->current_mode &&
+	     hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) ||
+	    hapd->iconf->ieee80211ah)
 		return WLAN_STATUS_SUCCESS;
 
 	if (!elems->supp_rates) {
@@ -4710,6 +4715,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 	size_t buflen;
 	struct ieee80211_mgmt *reply;
 	u8 *p;
+	le16 aid = 0;
 	u16 res = WLAN_STATUS_SUCCESS;
 	const u8 *sa = hapd->own_addr;
 
@@ -4767,8 +4773,11 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 		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)
+		reply->u.assoc_resp.aid = aid;
+
 	/* Supported rates */
 	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
 	/* Extended supported rates */
@@ -4862,6 +4871,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_aid_response(hapd, p, aid);
+		p = hostapd_eid_s1g_capab(hapd, p);
+		p = hostapd_eid_s1g_oper(hapd, p);
+	}
+#endif /* CONFIG_IEEE80211AH */
+
 	p = hostapd_eid_ext_capab(hapd, p, false);
 	p = hostapd_eid_bss_max_idle_period(hapd, p);
 	if (sta && sta->qos_map_enabled)
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index c23ffe365..201fc3d49 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -67,6 +67,11 @@ 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_s1g_short_beacon_int(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,
diff --git a/src/ap/ieee802_11_s1g.c b/src/ap/ieee802_11_s1g.c
index 34078a7f5..8f635de43 100644
--- a/src/ap/ieee802_11_s1g.c
+++ b/src/ap/ieee802_11_s1g.c
@@ -16,6 +16,137 @@
 #include "beacon.h"
 #include "ieee802_11.h"
 
+u8 * hostapd_eid_s1g_oper(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_s1g_operation *cap;
+	u8 max_mcs_nss_set;
+	u8 s1g_supp_oper_chwidth_mask = 0;
+	u8 s1g_prim_chwidth = 0;
+	u16 s1g_basic_min_max_mcs_nss_ie = 0;
+	u8 *pos = eid;
+
+	*pos++ = WLAN_EID_S1G_OPERATION;
+	*pos++ = sizeof(*cap);
+
+	cap = (struct ieee80211_s1g_operation *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+
+	switch(hapd->iconf->s1g_oper_chwidth) {
+	case 0:
+		s1g_supp_oper_chwidth_mask = 0;
+		s1g_prim_chwidth = 1;
+		cap->primary_ch = hapd->iconf->channel;
+		break;
+	case 1:
+		s1g_supp_oper_chwidth_mask = 1;
+		s1g_prim_chwidth = 0;
+		cap->primary_ch = hapd->iconf->channel;
+		break;
+	case 2:
+		s1g_supp_oper_chwidth_mask = 3;
+		s1g_prim_chwidth = 0;
+		cap->primary_ch = hapd->iconf->channel - 2;
+		break;
+	case 3:
+		s1g_supp_oper_chwidth_mask = 7;
+		s1g_prim_chwidth = 0;
+		cap->primary_ch = hapd->iconf->channel - 6;
+		break;
+	case 4:
+		s1g_supp_oper_chwidth_mask = 15;
+		s1g_prim_chwidth = 0;
+		cap->primary_ch = hapd->iconf->channel - 14;
+		break;
+	}
+
+	cap->primary_ch = hapd->iconf->channel;
+	cap->ch_width |= (s1g_prim_chwidth &
+		S1G_OPER_IE_CHANWIDTH_PRIM_CH_MASK);
+	cap->ch_width |= ((s1g_supp_oper_chwidth_mask << 1) &
+		S1G_OPER_IE_CHANWIDTH_OPER_CH_MASK);
+	cap->ch_width |= S1G_OPER_IE_CHANWIDTH_PRIM_OFFSET;
+
+	cap->oper_class = hapd->iconf->s1g_op_class;
+
+	cap->oper_ch = hapd->iconf->channel;
+
+	max_mcs_nss_set = hapd->iconf->s1g_basic_mcs_nss_set;
+
+	s1g_basic_min_max_mcs_nss_ie = (max_mcs_nss_set & 0x3) <<
+					S1G_OPER_IE_MAX_MCS_1_NSS_SHIFT |
+					    ((max_mcs_nss_set >> 2) & 0x3) <<
+					S1G_OPER_IE_MAX_MCS_2_NSS_SHIFT |
+					    ((max_mcs_nss_set >> 4) & 0x3) <<
+					S1G_OPER_IE_MAX_MCS_3_NSS_SHIFT |
+					    ((max_mcs_nss_set >> 6) & 0x3) <<
+					S1G_OPER_IE_MAX_MCS_4_NSS_SHIFT;
+	cap->basic_mcs_nss |= s1g_basic_min_max_mcs_nss_ie & 0xff;
+	cap->basic_mcs_nss |= (s1g_basic_min_max_mcs_nss_ie >> 8);
+
+	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->capab_info,
+		  hapd->iface->current_mode->s1g_capab,
+		  sizeof(cap->capab_info));
+	os_memcpy(cap->supp_mcs_nss,
+		  hapd->iface->current_mode->s1g_mcs,
+		  sizeof(cap->supp_mcs_nss));
+
+	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->conf->short_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 in by the driver to contain the 4
+	 MSB of the TSF timer at time of generation */
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	return pos;
+}
+
+
+u8 * hostapd_eid_s1g_short_beacon_int(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+
+	*pos++ = WLAN_EID_S1G_SHORT_BCN_INTERVAL;
+	*pos++ = 2;
+	*pos++ = hapd->iconf->beacon_int & 0xff;
+	*pos++ = (hapd->iconf->beacon_int >> 8) & 0xff;
+
+	return pos;
+}
+
 
 static u8 hostapd_s1g_get_oper_class_s1g(u16 s1g_op,
 					 struct hostapd_iface *iface) {
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 31dfb6254..0ad374491 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -455,6 +455,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;
+
+	*pos++ = aid;
+
+	memset(pos, 0, sizeof(*pos));
+
+	return pos;
+}
 
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid,
 			   bool mbssid_complete)
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 1dafba93a..ea519e680 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -36,6 +36,7 @@
 #define WLAN_FC_TYPE_MGMT		0
 #define WLAN_FC_TYPE_CTRL		1
 #define WLAN_FC_TYPE_DATA		2
+#define WLAN_FC_TYPE_EXT		3
 
 /* management */
 #define WLAN_FC_STYPE_ASSOC_REQ		0
@@ -77,6 +78,9 @@
 #define WLAN_FC_STYPE_QOS_CFPOLL	14
 #define WLAN_FC_STYPE_QOS_CFACKPOLL	15
 
+/* extension */
+#define WLAN_FC_STYPE_S1G_BEACON	1
+
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN			0
 #define WLAN_AUTH_SHARED_KEY		1
@@ -448,7 +452,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
@@ -1113,6 +1120,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_MAX_MMPDU_SIZE 2304
 
@@ -2446,6 +2465,29 @@ 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;
+
+#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/src/drivers/driver.h b/src/drivers/driver.h
index 7825dfca3..707764d70 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -318,6 +318,16 @@ struct hostapd_hw_modes {
 	 * eht_capab - EHT (IEEE 802.11be) capabilities
 	 */
 	struct eht_capabilities eht_capab[IEEE80211_MODE_NUM];
+
+	/**
+	 * s1g_capab - S1G (IEEE 802.11ah) capabilities
+	 */
+	u8 s1g_capab[10];
+
+	/**
+	 * s1g_mcs - S1G (IEEE 802 11ah) supported MCS and NSS params
+	 */
+	u8 s1g_mcs[5];
 };
 
 
@@ -1395,6 +1405,11 @@ struct wpa_driver_ap_params {
 	 */
 	int beacon_int;
 
+	/**
+	 * short_beacon_int - S1G short beacons per S1G beacon
+	 */
+	int short_beacon_int;
+
 	/**
 	 * basic_rates: -1 terminated array of basic rates in 100 kbps
 	 *
@@ -6570,7 +6585,6 @@ 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 582eddd98..4427cff03 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5066,6 +5066,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 	    nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
 				    params) ||
 	    nl80211_put_dtim_period(msg, params->dtim_period) ||
+	    nla_put_u32(msg, NL80211_ATTR_SHORT_BEACON_PERIOD,
+			params->short_beacon_int) ||
 	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
 		goto fail;
 
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 1ae381e49..81eeae358 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1613,6 +1613,24 @@ static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
 }
 
 
+static void phy_info_s1g_capa(struct hostapd_hw_modes *mode,
+			      struct nlattr *capability,
+			      struct nlattr *mcs_nss_set)
+{
+	if (capability && nla_len(capability) >= 10) {
+		u8 *capa;
+		capa = nla_data(capability);
+		os_memcpy(mode->s1g_capab, capa, 10);
+	}
+
+	if (mcs_nss_set && nla_len(mcs_nss_set) >= 5) {
+		u8 *mcs_nss;
+		mcs_nss = nla_data(mcs_nss_set);
+		os_memcpy(mode->s1g_mcs, mcs_nss, 5);
+	}
+}
+
+
 static int phy_info_edmg_capa(struct hostapd_hw_modes *mode,
 			      struct nlattr *bw_config,
 			      struct nlattr *channels)
@@ -2088,6 +2106,8 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
 			 tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
 	phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
 			  tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+	phy_info_s1g_capa(mode, tb_band[NL80211_BAND_ATTR_S1G_CAPA],
+			  tb_band[NL80211_BAND_ATTR_S1G_MCS_NSS_SET]);
 	ret = phy_info_edmg_capa(mode,
 				 tb_band[NL80211_BAND_ATTR_EDMG_BW_CONFIG],
 				 tb_band[NL80211_BAND_ATTR_EDMG_CHANNELS]);
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index c59fec406..759dfe968 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -3341,6 +3341,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_EMA_RNR_ELEMS,
 
+	NL80211_ATTR_SHORT_BEACON_PERIOD,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
-- 
2.25.1




More information about the Hostap mailing list