From: John Crispin <john@xxxxxxxxxxx> 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: John Crispin <john@xxxxxxxxxxx> Co-developed-by: Aloka Dixit <quic_alokad@xxxxxxxxxxx> Signed-off-by: Aloka Dixit <quic_alokad@xxxxxxxxxxx> --- 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 aa26ad4effd9..ce01fae2872d 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -3970,6 +3970,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; @@ -7546,4 +7563,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 ffa93f320f3d..8588832674a8 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -496,6 +496,8 @@ #define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110 +#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.31.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap