]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
BSS: Set valid_links for all links and return usable links
authorBenjamin Berg <benjamin.berg@intel.com>
Wed, 18 Jun 2025 12:35:25 +0000 (14:35 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 2 Oct 2025 16:52:15 +0000 (19:52 +0300)
This commit is a preparation to better define valid_links in struct
wpa_bss and move parsing to wpa_bss_update(). Before this, the value of
valid_links would depend on whether a neighbor is known and if a struct
wpa_ssid 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@intel.com>
tests/test-bss.c
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/events.c
wpa_supplicant/sme.c

index ac9fab864bb46b0041a13b574a788e7f1ac6dfec..c3f47281b7e2f0e618b15f5a66065821855d120a 100644 (file)
@@ -86,8 +86,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);
 }
index db73bfacf3e8efb02c451c581831fee9dfc4f5bc..17fb015c5ed788d1d5828f698e94848d7a81e6fc 100644 (file)
@@ -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);
@@ -1997,18 +2001,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;
 
@@ -2034,16 +2035,14 @@ 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,
@@ -2053,11 +2052,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;
 }
 
 
index fd560a9a8d9721c8bc030f915942470aa62f670c..f01accc50b67ef33aecd9c6221ce8bb88109492e 100644 (file)
@@ -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,
index 555023776fed82daefe44d6e31ead7f4d1a044a0..6f4cc5284951150df9adfa1e0d52867f6f2408c6 100644 (file)
@@ -1179,9 +1179,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;
 
@@ -1891,17 +1889,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);
index a2901b96f197ed05bace65d5462e179f01fa5b97..50b3d635dff0327cf1023b5aa178fd5940967329 100644 (file)
@@ -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,11 +624,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 
        os_memset(&params, 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);