mbssid: Functions for building Multiple BSSID elements

Add Multiple BSSID element data 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 Std 802.11ax-2021, Annex AA (Multiple BSSID
configuration examples).

Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
Co-developed-by: John Crispin <john@phrozen.org>
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
Aloka Dixit 2022-11-30 19:18:36 -08:00 committed by Jouni Malinen
parent 931e5d4f9e
commit 920b56322d
3 changed files with 226 additions and 0 deletions

View file

@ -3116,6 +3116,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;
@ -6705,4 +6722,205 @@ 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 octet
* Length: 1 octet
* Nontransmitted capabilities: 4 octets
* SSID element: 2 + variable
* Multiple BSSID Index Element: 3 octets (+2 octets 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)
break;
len += nontx_profile_len;
}
*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_INFO,
"MBSSID: Insufficient data for Beacon frames");
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_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
eid_len_pos = eid++;
capab_info = hostapd_own_capab_info(bss);
*eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
*eid++ = sizeof(capab_info);
WPA_PUT_LE16(eid, 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; /* BSSID Index */
if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
(conf->dtim_period % elem_count))
conf->dtim_period = elem_count;
*eid++ = conf->dtim_period;
*eid++ = 0xFF; /* DTIM Count */
} else {
/* Probe Request frame does not include DTIM Period and
* DTIM Count fields. */
*eid++ = 1;
*eid++ = i; /* BSSID Index */
}
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;
break;
}
}
*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,
unsigned int frame_stype, 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_stype != WLAN_FC_STYPE_BEACON &&
frame_stype != WLAN_FC_STYPE_PROBE_RESP))
return eid;
if (frame_stype == WLAN_FC_STYPE_BEACON && !elem_offset) {
wpa_printf(MSG_INFO,
"MBSSID: Insufficient data for Beacon frames");
return eid;
}
while (bss_index < hapd->iface->num_bss) {
if (frame_stype == WLAN_FC_STYPE_BEACON) {
if (elem_index == elem_count) {
wpa_printf(MSG_WARNING,
"MBSSID: Larger number of elements than there is room in the provided array");
break;
}
elem_offset[elem_index] = eid;
elem_index = elem_index + 1;
}
eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_stype,
hostapd_max_bssid_indicator(hapd),
&bss_index, elem_count);
}
return eid;
}
#endif /* CONFIG_NATIVE_WINDOWS */

View file

@ -214,5 +214,10 @@ 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,
unsigned int frame_stype, u8 elem_count,
u8 **elem_offset);
#endif /* IEEE802_11_H */

View file

@ -588,6 +588,9 @@
#define WLAN_RSNX_CAPAB_SECURE_RTT 9
#define WLAN_RSNX_CAPAB_PROT_RANGE_NEG 10
/* Multiple BSSID element subelements */
#define WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
#define WLAN_ACTION_QOS 1