From: Benjamin Berg <benjamin.berg@xxxxxxxxx> There is no point in re-parsing the ML element all the time if the relevant information is being cached in the BSS anyway. As such, move the parsing part to be done when adding/updating the BSS and add a separate function to retrieve the links that are usable or missing in the BSS cache. Overall, this is not going to save work, but it means that the multi-link information in the BSS is always up-to-date and also detangles the RNR/ML parsing from the later runtime checks whether the links are valid for the selected SSID. Signed-off-by: Benjamin Berg <benjamin.berg@xxxxxxxxx> --- tests/test-bss.c | 10 +- wpa_supplicant/bss.c | 282 +++++++++++++++++++--------------------- wpa_supplicant/bss.h | 13 +- wpa_supplicant/events.c | 9 +- wpa_supplicant/sme.c | 3 +- 5 files changed, 150 insertions(+), 167 deletions(-) diff --git a/tests/test-bss.c b/tests/test-bss.c index 10bcd17787..058cc1fad7 100644 --- a/tests/test-bss.c +++ b/tests/test-bss.c @@ -62,9 +62,8 @@ void test_parse_basic_ml(struct wpa_supplicant *wpa_s, u8 mld_id, u8 ies[sizeof(rnr_ie) + sizeof(ml_ie_mld_id) + sizeof(mbssid_idx_ie)]; } bss; - u16 missing_links; + u16 missing_links = 0; u8 ret; - bool nontransmitted; memcpy(bss.bss.ies, rnr_ie, sizeof(rnr_ie)); bss.bss.ie_len = sizeof(rnr_ie); @@ -84,14 +83,13 @@ void test_parse_basic_ml(struct wpa_supplicant *wpa_s, u8 mld_id, bss.bss.ie_len += sizeof(mbssid_idx_ie); } - ret = wpa_bss_parse_basic_ml_element(wpa_s, &bss.bss, - &missing_links, NULL, - &nontransmitted); + wpa_bss_parse_basic_ml_element(wpa_s, &bss.bss); + ret = wpa_bss_get_usable_links(wpa_s, &bss.bss, NULL, &missing_links); ASSERT_CMP_INT(ret, ==, 1); ASSERT_CMP_INT(bss.bss.valid_links, ==, 3); ASSERT_CMP_INT(missing_links, ==, 0x0002); - ASSERT_CMP_INT(nontransmitted, ==, mbssid_idx > 0); + ASSERT_CMP_INT(bss.bss.mld_bss_non_transmitted, ==, mbssid_idx > 0); } #define RUN_TEST(func, ...) do { \ diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index b8fe141935..b5b6305f13 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -590,10 +590,8 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, { struct wpa_bss *bss; char extra[100]; - const u8 *ml_ie; char *pos, *end; int ret = 0; - const u8 *mld_addr; bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (bss == NULL) @@ -608,13 +606,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); wpa_bss_set_hessid(bss); - os_memset(bss->mld_addr, 0, ETH_ALEN); - ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC); - if (ml_ie) { - mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1); - if (mld_addr) - os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN); - } + wpa_bss_parse_basic_ml_element(wpa_s, bss); if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count && wpa_bss_remove_oldest(wpa_s) != 0) { @@ -905,17 +897,9 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, dl_list_add(prev, &bss->list_id); } if (changes & WPA_BSS_IES_CHANGED_FLAG) { - const u8 *ml_ie, *mld_addr; - wpa_bss_set_hessid(bss); - os_memset(bss->mld_addr, 0, ETH_ALEN); - ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC); - if (ml_ie) { - mld_addr = get_basic_mle_mld_addr(&ml_ie[3], - ml_ie[1] - 1); - if (mld_addr) - os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN); - } + + wpa_bss_parse_basic_ml_element(wpa_s, bss); } dl_list_add_tail(&wpa_s->bss, &bss->list); @@ -1639,8 +1623,7 @@ static void wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 ap_mld_id, const struct ieee80211_neighbor_ap_info *ap_info, - size_t len, u16 *seen, u16 *usable, u16 *missing, - struct wpa_ssid *ssid) + size_t len, u16 *seen) { const u8 *pos, *end; const u8 *mld_params; @@ -1677,16 +1660,8 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "MLD: Reported link not part of MLD"); } else if (!(BIT(link_id) & *seen)) { - struct wpa_bss *neigh_bss; struct mld_link *l; - if (ssid && ssid->ssid_len) - neigh_bss = wpa_bss_get(wpa_s, pos + 1, - ssid->ssid, - ssid->ssid_len); - else - neigh_bss = wpa_bss_get_bssid(wpa_s, pos + 1); - *seen |= BIT(link_id); wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u", *mld_params, link_id); @@ -1699,17 +1674,6 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, l->freq = ieee80211_chan_to_freq(NULL, ap_info->op_class, ap_info->channel); - - if (!neigh_bss) { - *missing |= BIT(link_id); - } else if ((!ssid || - wpa_scan_res_match(wpa_s, 0, neigh_bss, - ssid, 1, 0, true)) && - !wpa_bssid_ignore_is_listed( - wpa_s, neigh_bss->bssid)) { - l->freq = neigh_bss->freq; - *usable |= BIT(link_id); - } } } } @@ -1792,15 +1756,93 @@ wpa_bss_validate_rsne_ml(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, /** - * wpa_bss_parse_basic_ml_element - Parse the Basic Multi-Link element + * wpa_bss_get_usable_links - Retrieve the usable links of the AP MLD * @wpa_s: Pointer to wpa_supplicant data * @bss: BSS table entry - * @link_info: Array to store link information (or %NULL), - * should be initialized and #MAX_NUM_MLD_LINKS elements long - * @missing_links: Result bitmask of links that were not discovered (or %NULL) * @ssid: Target SSID (or %NULL) - * @nontransmitted: Out parameter denoting whether the BSSID is nontransmitted - * (or %NULL) + * @missing_links: Result bitmask of links that were not discovered (or %NULL) + * Returns: bitmap of links that are usable, or 0 for non-MLD or failure + * + * Validate each link of the MLD to verify that it is compatible and connection + * to each of the links is allowed. + */ +u16 wpa_bss_get_usable_links(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_ssid *ssid, + u16 *missing_links) +{ + int rsne_type, key_mgmt; + u16 usable_links = 0; + u8 link_id; + + if (!bss->valid_links) + return 0; + + rsne_type = -1; + if (ssid && + !wpa_bss_validate_rsne_ml(wpa_s, ssid, bss, &key_mgmt, + &rsne_type)) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No valid key management"); + return 0; + } + + usable_links = BIT(bss->mld_link_id); + + for_each_link(bss->valid_links, link_id) { + struct wpa_bss *neigh_bss; + + if (link_id == bss->mld_link_id) + continue; + + if (ssid && ssid->ssid_len) + neigh_bss = wpa_bss_get(wpa_s, + bss->mld_links[link_id].bssid, + ssid->ssid, + ssid->ssid_len); + else + neigh_bss = wpa_bss_get_bssid(wpa_s, + bss->mld_links[link_id].bssid); + + if (!neigh_bss) { + if (missing_links) + *missing_links |= BIT(link_id); + continue; + } + + if (ssid) { + int neigh_key_mgmt; + + /* As per IEEE P802.11be/D7.0, 12.6.2 (RSNA selection), all APs + * affiliated with an AP MLD shall advertise at least one common + * AKM suite selector in the AKM Suite List field of an RSNE or + * RSNXE. Discard links that do not have compatibility + * configuration with the association link. + */ + if (!wpa_bss_validate_rsne_ml(wpa_s, ssid, neigh_bss, + &neigh_key_mgmt, &rsne_type) || + !(key_mgmt & neigh_key_mgmt)) { + wpa_printf(MSG_DEBUG, + "MLD: Discard link %u due to RSN parameter mismatch", + link_id); + continue; + } + } + + if ((!ssid || + wpa_scan_res_match(wpa_s, 0, neigh_bss, ssid, 1, 0, true)) && + !wpa_bssid_ignore_is_listed(wpa_s, neigh_bss->bssid)) { + usable_links |= BIT(link_id); + } + } + + return usable_links; +} + + +/** + * wpa_bss_parse_basic_ml_element - Parse the Basic Multi-Link element + * @wpa_s: Pointer to wpa_supplicant data + * @bss: BSS table entry * Returns: Usable links bitmask, or 0 for non-MLD or parsing failures * * Parses the Basic Multi-Link element of the BSS into @link_info using the scan @@ -1813,11 +1855,8 @@ wpa_bss_validate_rsne_ml(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, * AP MLD ID should not be included in an ML Probe Request sent to its BSSID, * otherwise it should be included and set to zero. */ -u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, - u16 *missing_links, - struct wpa_ssid *ssid, - bool *nontransmitted) +void wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) { struct ieee802_11_elems elems; struct wpabuf *mlbuf = NULL; @@ -1825,6 +1864,7 @@ u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, size_t ml_ie_len; const struct ieee80211_eht_ml *eht_ml; const struct eht_ml_basic_common_info *ml_basic_common_info; + const u8 *mbssid_idx_elem; u8 i, pos, link_id, ap_mld_id; const u16 control_mask = MULTI_LINK_CONTROL_TYPE_MASK | @@ -1836,11 +1876,9 @@ u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA; - u16 missing = 0; - u16 seen, usable = 0; + u16 seen; const u8 *ies_pos = wpa_bss_ie_ptr(bss); size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; - int rsne_type, key_mgmt; struct mld_link *l; if (ieee802_11_parse_elems(ies_pos, ies_len, &elems, 1) == @@ -1857,14 +1895,6 @@ u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, ml_ie_len = wpabuf_len(mlbuf); - rsne_type = -1; - if (ssid && - !wpa_bss_validate_rsne_ml(wpa_s, ssid, bss, &key_mgmt, - &rsne_type)) { - wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No valid key management"); - goto out; - } - /* * for ext ID + 2 control + common info len */ @@ -1922,59 +1952,51 @@ u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK; + os_memcpy(bss->mld_addr, ml_basic_common_info->mld_addr, ETH_ALEN); + bss->mld_link_id = link_id; bss->valid_links = BIT(link_id); - usable = seen = bss->valid_links; + seen = bss->valid_links; l = &bss->mld_links[link_id]; os_memcpy(l->bssid, bss->bssid, ETH_ALEN); l->freq = bss->freq; + bss->mld_bss_non_transmitted = false; - /* Read Multiple BSSID Index for *nontransmitted and AP MLD ID */ - if (nontransmitted || !(le_to_host16(eht_ml->ml_control) & - BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID)) { - const u8 *mbssid_idx_elem; - - /* - * We should be able to rely on the Multiple BSSID Index element - * to be included if the BSS is nontransmitted. Both if it was - * extracted from a beacon and if it came from an ML probe - * response (i.e. not listed in Draft P802.11be_D4.1, 35.3.3.4). - * - * Note that the AP MLD ID and the Multiple-BSSID Index will be - * identical if the information was reported by the - * corresponding transmitting AP (P802.11be_D4.1, 9.4.2.169.2). - * As an AP MLD ID will not be explicitly provided we need to - * rely on the Multiple-BSSID Index. This is generally the case - * when the BSS information was read from a - * Multiple-BSSID Element. - * - * The alternative scenario is a BSS discovered using a - * Multi-Link Probe Response. In that case, we can still - * determine whether the BSS is nontransmitted or not using the - * Multiple BSSID Index Element. However, the AP MLD ID may be - * different inside the ML Probe Response and the driver also - * needs to deal with this during inheritance. - * - * We assume the driver either - * - includes the appropriate AP MLD ID in the ML Element - * it generates (see above), or - * - rewrites the RNR so that the AP MLD ID matches the - * Multiple-BSSID Index. - */ - mbssid_idx_elem = wpa_bss_get_ie(bss, - WLAN_EID_MULTIPLE_BSSID_INDEX); - if (mbssid_idx_elem && mbssid_idx_elem[1] >= 1) { - if (!(le_to_host16(eht_ml->ml_control) & - BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID)) - ap_mld_id = mbssid_idx_elem[2]; - if (nontransmitted) - *nontransmitted = !!mbssid_idx_elem[2]; - } else { - if (nontransmitted) - *nontransmitted = false; - } + /* + * We should be able to rely on the Multiple BSSID Index element + * to be included if the BSS is nontransmitted. Both if it was + * extracted from a beacon and if it came from an ML probe + * response (i.e. not listed in Draft P802.11be_D4.1, 35.3.3.4). + * + * Note that the AP MLD ID and the Multiple-BSSID Index will be + * identical if the information was reported by the + * corresponding transmitting AP (P802.11be_D4.1, 9.4.2.169.2). + * As an AP MLD ID will not be explicitly provided we need to + * rely on the Multiple-BSSID Index. This is generally the case + * when the BSS information was read from a + * Multiple-BSSID Element. + * + * The alternative scenario is a BSS discovered using a + * Multi-Link Probe Response. In that case, we can still + * determine whether the BSS is nontransmitted or not using the + * Multiple BSSID Index Element. However, the AP MLD ID may be + * different inside the ML Probe Response and the driver also + * needs to deal with this during inheritance. + * + * We assume the driver either + * - includes the appropriate AP MLD ID in the ML Element + * it generates (see above), or + * - rewrites the RNR so that the AP MLD ID matches the + * Multiple-BSSID Index. + */ + mbssid_idx_elem = wpa_bss_get_ie(bss, WLAN_EID_MULTIPLE_BSSID_INDEX); + if (mbssid_idx_elem && mbssid_idx_elem[1] >= 1) { + if (!(le_to_host16(eht_ml->ml_control) & + BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID)) + ap_mld_id = mbssid_idx_elem[2]; + bss->mld_bss_non_transmitted = !!mbssid_idx_elem[2]; } for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT, @@ -1998,64 +2020,28 @@ u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, goto out; wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, ap_mld_id, - ap_info, ap_info_len, - &seen, &usable, &missing, - ssid); + ap_info, len, &seen); ap_info_pos += ap_info_len; len -= ap_info_len; } } - for_each_link(usable, i) { - struct wpa_bss *neigh_bss; - int neigh_key_mgmt; - - if (!ssid) - break; - - if (i == link_id) - continue; - - neigh_bss = wpa_bss_get_bssid(wpa_s, bss->mld_links[i].bssid); - if (!neigh_bss) /* cannot be NULL at this point */ - continue; - - /* As per IEEE P802.11be/D7.0, 12.6.2 (RSNA selection), all APs - * affiliated with an AP MLD shall advertise at least one common - * AKM suite selector in the AKM Suite List field of an RSNE or - * RSNXE. Discard links that do not have compatibility - * configuration with the association link. - */ - if (!wpa_bss_validate_rsne_ml(wpa_s, ssid, neigh_bss, - &neigh_key_mgmt, &rsne_type) || - !(key_mgmt & neigh_key_mgmt)) { - wpa_printf(MSG_DEBUG, - "MLD: Discard link %u due to RSN parameter mismatch", - i); - usable &= ~BIT(i); - continue; - } - } - - wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%04hx usable=0x%04hx (unresolved: 0x%04hx)", - bss->valid_links, usable, missing); + wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%04hx", + bss->valid_links); for_each_link(bss->valid_links, i) { wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR, i, MAC2STR(bss->mld_links[i].bssid)); } - if (missing_links) - *missing_links = missing; - wpabuf_free(mlbuf); - return usable; + return; out: + os_memset(bss->mld_addr, 0, ETH_ALEN); bss->valid_links = 0; wpabuf_free(mlbuf); - return 0; } diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index f01accc50b..4bd752fda2 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -125,6 +125,8 @@ struct wpa_bss { u8 mld_addr[ETH_ALEN]; /** Link ID of this affiliated AP of the AP MLD */ u8 mld_link_id; + /** For MLD, denotes if BSS is non-TX; useful for ML probe */ + bool mld_bss_non_transmitted; /** An array of MLD links, any link found in the RNR is "valid" */ u16 valid_links; @@ -217,11 +219,12 @@ void calculate_update_time(const struct os_reltime *fetch_time, unsigned int age_ms, struct os_reltime *update_time); -u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, - u16 *missing_links, - struct wpa_ssid *ssid, - bool *nontransmitted); +u16 wpa_bss_get_usable_links(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_ssid *ssid, + u16 *missing_links); +void wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b8db56921d..a411ea8f37 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1176,7 +1176,6 @@ static bool wpas_valid_ml_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { u16 removed_links; - wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL, NULL); if (!bss->valid_links) return true; @@ -1887,15 +1886,13 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s, { int *freqs; u16 missing_links = 0, removed_links, usable_links; - bool nontransmitted; if (!((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))) return 0; - usable_links = wpa_bss_parse_basic_ml_element(wpa_s, selected, - &missing_links, ssid, - &nontransmitted); + usable_links = wpa_bss_get_usable_links(wpa_s, selected, NULL, + &missing_links); if (!usable_links || !missing_links) return 0; @@ -1935,7 +1932,7 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s, * In case the ML probe requested is intended to retrieve information * from a non-transmitted BSS, the AP MLD ID should not be included. */ - if (nontransmitted) + if (selected->mld_bss_non_transmitted) wpa_s->ml_probe_mld_id = -1; else wpa_s->ml_probe_mld_id = 0; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 50b3d635df..55dcf41efc 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -534,8 +534,7 @@ static void wpas_sme_set_mlo_links(struct wpa_supplicant *wpa_s, if (!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) return; - usable_links = wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, - ssid, NULL); + usable_links = wpa_bss_get_usable_links(wpa_s, bss, ssid, NULL); if (!usable_links) return; -- 2.49.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap