[PATCH v4 04/15] mbssid: add multiple BSSID elements

Aloka Dixit quic_alokad at quicinc.com
Wed Nov 30 19:18:36 PST 2022


Add multiple BSSID element data as per IEEE Std 802.11ax-2021, 9.4.2.45.
Split the BSSes into multiple elements if the data does not fit in
the 255 bytes allowed for a single element.

Store the total count of elements created and the offset to the start
of each element in the provided buffer.

Set the DTIM periods of non-transmitted profiles equal to the EMA
profile periodicity if those are not a multiple of the latter already
as recommended in IEEE P802.11ax/D8.0, October 2020, Multiple BSSID
configuration examples, AA.1 Introduction.

Signed-off-by: Aloka Dixit <quic_alokad at quicinc.com>
Co-developed-by: John Crispin <john at phrozen.org>
Signed-off-by: John Crispin <john at phrozen.org>
---
 src/ap/ieee802_11.c          | 215 +++++++++++++++++++++++++++++++++++
 src/ap/ieee802_11.h          |   4 +
 src/common/ieee802_11_defs.h |   2 +
 3 files changed, 221 insertions(+)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index f0e3c55a985c..72b961bb2244 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -3115,6 +3115,23 @@ static void handle_auth(struct hostapd_data *hapd,
 }
 
 
+static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
+{
+	size_t num_bss_nontx;
+	u8 max_bssid_ind = 0;
+
+	if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
+		return 0;
+
+	num_bss_nontx = hapd->iface->num_bss - 1;
+	while (num_bss_nontx > 0) {
+		max_bssid_ind++;
+		num_bss_nontx >>= 1;
+	}
+	return max_bssid_ind;
+}
+
+
 int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	int i, j = 32, aid;
@@ -6704,4 +6721,202 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
 	return eid;
 }
 
+
+static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
+					  u32 frame_type, size_t *bss_index)
+{
+	size_t len = 3, i;
+
+	for (i = *bss_index; i < hapd->iface->num_bss; i++) {
+		struct hostapd_data *bss = hapd->iface->bss[i];
+		const u8 *auth, *rsn, *rsnx;
+		size_t nontx_profile_len, auth_len;
+
+		if (!bss || !bss->conf || !bss->started)
+			continue;
+
+		/*
+		 * Sublement ID: 1 byte
+		 * Length: 1 byte
+		 * Nontransmitted capabilities: 4 bytes
+		 * SSID element: 2 + variable
+		 * Multiple BSSID Index Element: 3 bytes (+2 bytes in beacons)
+		 * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
+		 */
+		nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
+
+		if (frame_type == WLAN_FC_STYPE_BEACON)
+			nontx_profile_len += 2;
+
+		auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
+		if (auth) {
+			rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
+			if (rsn)
+				nontx_profile_len += (2 + rsn[1]);
+
+			rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
+			if (rsnx)
+				nontx_profile_len += (2 + rsnx[1]);
+		}
+
+		if ((len + nontx_profile_len) > 255)
+			goto mbssid_too_big;
+
+		len += nontx_profile_len;
+	}
+
+mbssid_too_big:
+	*bss_index = i;
+	return len;
+}
+
+
+size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
+			      u8 *elem_count)
+{
+	size_t len = 0, bss_index = 1;
+
+	if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
+	    (frame_type != WLAN_FC_STYPE_BEACON &&
+	     frame_type != WLAN_FC_STYPE_PROBE_RESP))
+		return 0;
+
+	if (frame_type == WLAN_FC_STYPE_BEACON) {
+		if (!elem_count) {
+			wpa_printf(MSG_ERROR,
+				   "MBSSID: Insufficient data for beacons");
+			return 0;
+		}
+		*elem_count = 0;
+	}
+
+	while (bss_index < hapd->iface->num_bss) {
+		len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
+						   &bss_index);
+
+		if (frame_type == WLAN_FC_STYPE_BEACON)
+			*elem_count += 1;
+	}
+	return len;
+}
+
+
+static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
+				    u32 frame_type, u8 max_bssid_indicator,
+				    size_t *bss_index, u8 elem_count)
+{
+	size_t i;
+	u8 *eid_len_offset, *max_bssid_indicator_offset;
+
+	*eid++ = WLAN_EID_MULTIPLE_BSSID;
+	eid_len_offset = eid++;
+	max_bssid_indicator_offset = eid++;
+
+	for (i = *bss_index; i < hapd->iface->num_bss; i++) {
+		struct hostapd_data *bss = hapd->iface->bss[i];
+		struct hostapd_bss_config *conf;
+		u8 *eid_len_pos, *nontx_bss_start = eid;
+		const u8 *auth, *rsn, *rsnx;
+		size_t auth_len = 0;
+		u16 capab_info;
+
+		if (!bss || !bss->conf || !bss->started)
+			continue;
+		conf = bss->conf;
+
+		*eid++ = WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
+		eid_len_pos = eid++;
+
+		*eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
+		*eid++ = sizeof(capab_info);
+		capab_info = host_to_le16(hostapd_own_capab_info(bss));
+		os_memcpy(eid, (const void *)&capab_info, sizeof(capab_info));
+		eid += sizeof(capab_info);
+
+		*eid++ = WLAN_EID_SSID;
+		*eid++ = conf->ssid.ssid_len;
+		os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
+		eid += conf->ssid.ssid_len;
+
+		*eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
+		if (frame_type == WLAN_FC_STYPE_BEACON) {
+			*eid++ = 3;
+			*eid++ = i;
+			if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
+			    (conf->dtim_period % elem_count))
+				conf->dtim_period = elem_count;
+			*eid++ = conf->dtim_period;
+			*eid++ = 0xFF;
+		} else {
+			*eid++ = 1;
+			*eid++ = i;
+		}
+
+		auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
+		if (auth) {
+			rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
+			if (rsn) {
+				os_memcpy(eid, rsn, 2 + rsn[1]);
+				eid += (2 + rsn[1]);
+			}
+
+			rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
+			if (rsnx) {
+				os_memcpy(eid, rsnx, 2 + rsnx[1]);
+				eid += (2 + rsnx[1]);
+			}
+		}
+
+		*eid_len_pos = (eid - eid_len_pos) - 1;
+
+		if (((eid - eid_len_offset) - 1) > 255) {
+			eid = nontx_bss_start;
+			goto mbssid_too_big;
+		}
+	}
+
+mbssid_too_big:
+	*bss_index = i;
+	*max_bssid_indicator_offset = max_bssid_indicator;
+	if (*max_bssid_indicator_offset < 1)
+		*max_bssid_indicator_offset = 1;
+	*eid_len_offset = (eid - eid_len_offset) - 1;
+	return eid;
+}
+
+
+u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
+			u32 frame_type, u8 elem_count, u8 **elem_offset)
+{
+	size_t bss_index = 1;
+	u8 elem_index = 0;
+
+	if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
+	    (frame_type != WLAN_FC_STYPE_BEACON &&
+	     frame_type != WLAN_FC_STYPE_PROBE_RESP))
+		return eid;
+
+	if (frame_type == WLAN_FC_STYPE_BEACON && !elem_offset) {
+		wpa_printf(MSG_ERROR, "MBSSID: Insufficient data for beacons");
+		return eid;
+	}
+
+	while (bss_index < hapd->iface->num_bss) {
+		if (frame_type == WLAN_FC_STYPE_BEACON) {
+			if (elem_index == elem_count) {
+				wpa_printf(MSG_WARNING,
+					   "MBSSID: More number of elements than provided array");
+				break;
+			}
+
+			elem_offset[elem_index] = eid;
+			elem_index = elem_index + 1;
+		}
+		eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_type,
+					      hostapd_max_bssid_indicator(hapd),
+					      &bss_index, elem_count);
+	}
+	return eid;
+}
+
 #endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index fa1f47b957e4..1c545eff23e6 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -214,5 +214,9 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
 		       enum ieee80211_op_mode opmode,
 		       const u8 *he_capab, size_t he_capab_len,
 		       const u8 *eht_capab, size_t eht_capab_len);
+size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
+			      u8 *elem_count);
+u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
+			u32 frame_type, u8 elem_count, u8 **elem_offset);
 
 #endif /* IEEE802_11_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 310b7660e2ff..65d18e67c41f 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -497,6 +497,8 @@
 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
 #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
 
+#define WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0
+
 /* Extended Capabilities field */
 #define WLAN_EXT_CAPAB_20_40_COEX 0
 #define WLAN_EXT_CAPAB_GLK 1
-- 
2.25.1




More information about the Hostap mailing list