[PATCH 3/9] BSS: Set valid_links for all links and return usable links
Benjamin Berg
benjamin at sipsolutions.net
Wed Jun 18 05:35:25 PDT 2025
From: Benjamin Berg <benjamin.berg at intel.com>
This commit is a preparation to better define valid_links in the bss
structure and move parsing to wpa_bss_update. Before this, the value
of valid_links would depend on whether a neighbor is known and if an
SSID struct was passed to the parser.
With this change, valid_links is purely defined on whether there is an
entry in the RNR for the corresponding link.
Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
---
tests/test-bss.c | 4 +--
wpa_supplicant/bss.c | 62 ++++++++++++++++++++---------------------
wpa_supplicant/bss.h | 4 +--
wpa_supplicant/events.c | 14 ++++------
wpa_supplicant/sme.c | 21 ++++++++++----
5 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/tests/test-bss.c b/tests/test-bss.c
index 0b82bd6e9d..10bcd17787 100644
--- a/tests/test-bss.c
+++ b/tests/test-bss.c
@@ -88,8 +88,8 @@ void test_parse_basic_ml(struct wpa_supplicant *wpa_s, u8 mld_id,
&missing_links, NULL,
&nontransmitted);
- ASSERT_CMP_INT(ret, ==, 0);
- ASSERT_CMP_INT(bss.bss.valid_links, ==, 1);
+ 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);
}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 711dc7db26..b8fe141935 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1639,7 +1639,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 *missing,
+ size_t len, u16 *seen, u16 *usable, u16 *missing,
struct wpa_ssid *ssid)
{
const u8 *pos, *end;
@@ -1678,6 +1678,7 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s,
"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,
@@ -1690,6 +1691,15 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
*mld_params, link_id);
+ bss->valid_links |= BIT(link_id);
+ l = &bss->mld_links[link_id];
+ os_memcpy(l->bssid, pos + 1, ETH_ALEN);
+ l->disabled = mld_params[2] &
+ RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
+ l->freq = ieee80211_chan_to_freq(NULL,
+ ap_info->op_class,
+ ap_info->channel);
+
if (!neigh_bss) {
*missing |= BIT(link_id);
} else if ((!ssid ||
@@ -1697,14 +1707,8 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s,
ssid, 1, 0, true)) &&
!wpa_bssid_ignore_is_listed(
wpa_s, neigh_bss->bssid)) {
- struct mld_link *l;
-
- bss->valid_links |= BIT(link_id);
- l = &bss->mld_links[link_id];
- os_memcpy(l->bssid, pos + 1, ETH_ALEN);
l->freq = neigh_bss->freq;
- l->disabled = mld_params[2] &
- RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
+ *usable |= BIT(link_id);
}
}
}
@@ -1797,7 +1801,7 @@ wpa_bss_validate_rsne_ml(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
* @ssid: Target SSID (or %NULL)
* @nontransmitted: Out parameter denoting whether the BSSID is nontransmitted
* (or %NULL)
- * Returns: 0 on success or -1 for non-MLD or parsing failures
+ * 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
* information stored in the wpa_supplicant data to fill in information for
@@ -1809,14 +1813,14 @@ 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.
*/
-int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
+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)
{
struct ieee802_11_elems elems;
- struct wpabuf *mlbuf;
+ struct wpabuf *mlbuf = NULL;
const struct element *elem;
size_t ml_ie_len;
const struct ieee80211_eht_ml *eht_ml;
@@ -1833,23 +1837,22 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
u16 missing = 0;
- u16 seen;
+ u16 seen, usable = 0;
const u8 *ies_pos = wpa_bss_ie_ptr(bss);
size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
- int ret = -1, rsne_type, key_mgmt;
+ int rsne_type, key_mgmt;
struct mld_link *l;
- u16 valid_links;
if (ieee802_11_parse_elems(ies_pos, ies_len, &elems, 1) ==
ParseFailed) {
wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed to parse elements");
- return ret;
+ goto out;
}
mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
if (!mlbuf) {
wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No Multi-Link element");
- return ret;
+ goto out;
}
ml_ie_len = wpabuf_len(mlbuf);
@@ -1920,7 +1923,8 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK;
bss->mld_link_id = link_id;
- seen = bss->valid_links = BIT(link_id);
+ bss->valid_links = BIT(link_id);
+ usable = seen = bss->valid_links;
l = &bss->mld_links[link_id];
os_memcpy(l->bssid, bss->bssid, ETH_ALEN);
@@ -1995,18 +1999,15 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, ap_mld_id,
ap_info, ap_info_len,
- &seen, &missing, ssid);
+ &seen, &usable, &missing,
+ ssid);
ap_info_pos += ap_info_len;
len -= ap_info_len;
}
}
- wpa_printf(MSG_DEBUG, "MLD: valid_links=%04hx (unresolved: 0x%04hx)",
- bss->valid_links, missing);
-
- valid_links = bss->valid_links;
- for_each_link(bss->valid_links, i) {
+ for_each_link(usable, i) {
struct wpa_bss *neigh_bss;
int neigh_key_mgmt;
@@ -2032,16 +2033,13 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG,
"MLD: Discard link %u due to RSN parameter mismatch",
i);
- valid_links &= ~BIT(i);
+ usable &= ~BIT(i);
continue;
}
}
- if (valid_links != bss->valid_links) {
- wpa_printf(MSG_DEBUG, "MLD: Updated valid links=%04hx",
- valid_links);
- bss->valid_links = valid_links;
- }
+ wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%04hx usable=0x%04hx (unresolved: 0x%04hx)",
+ bss->valid_links, usable, missing);
for_each_link(bss->valid_links, i) {
wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR,
@@ -2051,11 +2049,13 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
if (missing_links)
*missing_links = missing;
+ wpabuf_free(mlbuf);
+ return usable;
- ret = 0;
out:
+ bss->valid_links = 0;
wpabuf_free(mlbuf);
- return ret;
+ return 0;
}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index fd560a9a8d..f01accc50b 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -126,7 +126,7 @@ struct wpa_bss {
/** Link ID of this affiliated AP of the AP MLD */
u8 mld_link_id;
- /** An array of MLD links */
+ /** An array of MLD links, any link found in the RNR is "valid" */
u16 valid_links;
struct mld_link {
u8 bssid[ETH_ALEN];
@@ -217,7 +217,7 @@ void calculate_update_time(const struct os_reltime *fetch_time,
unsigned int age_ms,
struct os_reltime *update_time);
-int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
+u16 wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss,
u16 *missing_links,
struct wpa_ssid *ssid,
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index fe9e358f5d..b8db56921d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1176,9 +1176,7 @@ static bool wpas_valid_ml_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
u16 removed_links;
- if (wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL, NULL))
- return true;
-
+ wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL, NULL);
if (!bss->valid_links)
return true;
@@ -1888,17 +1886,17 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
int *freqs;
- u16 missing_links = 0, removed_links;
+ 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;
- if (wpa_bss_parse_basic_ml_element(wpa_s, selected,
- &missing_links, ssid,
- &nontransmitted) ||
- !missing_links)
+ usable_links = wpa_bss_parse_basic_ml_element(wpa_s, selected,
+ &missing_links, ssid,
+ &nontransmitted);
+ if (!usable_links || !missing_links)
return 0;
removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, selected);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index d32d315766..50b3d635df 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -526,13 +526,24 @@ static int wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
static void wpas_sme_set_mlo_links(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
+ u16 usable_links;
u8 i;
+ wpas_reset_mlo_info(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);
+ if (!usable_links)
+ return;
+
os_memcpy(wpa_s->ap_mld_addr, bss->mld_addr, ETH_ALEN);
wpa_s->valid_links = 0;
wpa_s->mlo_assoc_link_id = bss->mld_link_id;
- for_each_link(bss->valid_links, i) {
+ for_each_link(usable_links, i) {
const u8 *bssid = bss->mld_links[i].bssid;
wpa_s->valid_links |= BIT(i);
@@ -613,12 +624,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memset(¶ms, 0, sizeof(params));
- if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
- !wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL,
- ssid, NULL) &&
- bss->valid_links) {
+ wpas_sme_set_mlo_links(wpa_s, bss, ssid);
+
+ if (wpa_s->valid_links) {
wpa_printf(MSG_DEBUG, "MLD: In authentication");
- wpas_sme_set_mlo_links(wpa_s, bss, ssid);
#ifdef CONFIG_TESTING_OPTIONS
bss = wpas_ml_connect_pref(wpa_s, bss, ssid);
--
2.49.0
More information about the Hostap
mailing list