]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SME: MLD: Handle reconfiguration Multi-Link element
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Mon, 12 Jun 2023 19:59:50 +0000 (22:59 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 29 Oct 2023 14:43:34 +0000 (16:43 +0200)
Parse the reconfiguration Multi-Link element and:

- Don't select a BSS for connection if it is part of an MLD
  and is going to be removed.
- Don't scan for missing links that are to be removed.
- Don't include removed links in association.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
src/common/ieee802_11_defs.h
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/events.c
wpa_supplicant/sme.c

index a24e61fbea990125373ebb2982debe70e3f5332d..805a4024f32a17782743e3e81b9da027dab29ebf 100644 (file)
@@ -2700,9 +2700,17 @@ struct eht_ml_probe_req_common_info {
        u8 variable[];
 } STRUCT_PACKED;
 
-/* IEEE P802.11be/D2.0, 9.4.2.312.4 - Reconfiguration Multi-Link element */
+/* IEEE P802.11be/D4.0, 9.4.2.312.4 - Reconfiguration Multi-Link element */
 
-#define EHT_ML_PRES_BM_RECONFIGURE_MLD_ADDRESS 0x0001
+#define RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR   0x0001
+
+#define EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK        0x000f
+#define EHT_PER_STA_RECONF_CTRL_COMPLETE_PROFILE   0x0010
+#define EHT_PER_STA_RECONF_CTRL_MAC_ADDR           0x0020
+#define EHT_PER_STA_RECONF_CTRL_AP_REMOVAL_TIMER   0x0040
+#define EHT_PER_STA_RECONF_CTRL_OP_UPDATE_TYPE_MSK 0x0780
+#define EHT_PER_STA_RECONF_CTRL_OP_PARAMS          0x0800
+#define EHT_PER_STA_RECONF_CTRL_NSTR_BITMAP_SIZE   0x1000
 
 /* IEEE P802.11be/D2.0, 9.4.2.312.1 - Multi-Link element / General */
 
index 47c7094c8eded582ca320406e973ecd4d323f137..5ada34c4f49d5fffecf881e1d72a4d019ca231aa 100644 (file)
@@ -1708,3 +1708,83 @@ out:
        wpabuf_free(mlbuf);
        return ret;
 }
+
+
+/*
+ * wpa_bss_parse_reconf_ml_element - Parse the Reconfiguration ML element
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: BSS table entry
+ * Returns: The bitmap of links that are going to be removed
+ */
+u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
+                                   struct wpa_bss *bss)
+{
+       struct ieee802_11_elems elems;
+       struct wpabuf *mlbuf;
+       const u8 *pos = wpa_bss_ie_ptr(bss);
+       size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+       const struct ieee80211_eht_ml *ml;
+       u16 removed_links = 0;
+       u8 ml_common_len;
+
+       if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
+               return 0;
+
+       if (!elems.reconf_mle || !elems.reconf_mle_len)
+               return 0;
+
+       mlbuf = ieee802_11_defrag_mle(&elems, MULTI_LINK_CONTROL_TYPE_RECONF);
+       if (!mlbuf)
+               return 0;
+
+       ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
+       len = wpabuf_len(mlbuf);
+
+       if (len < sizeof(*ml))
+               goto out;
+
+       ml_common_len = 1;
+       if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR)
+               ml_common_len += ETH_ALEN;
+
+       if (len < sizeof(*ml) + ml_common_len) {
+               wpa_printf(MSG_DEBUG,
+                          "MLD: Unexpected Reconfiguration ML element length: (%zu < %zu)",
+                          len, sizeof(*ml) + ml_common_len);
+               goto out;
+       }
+
+       pos = ml->variable + ml_common_len;
+       len -= sizeof(*ml) + ml_common_len;
+
+       while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) {
+               size_t sub_elem_len = *(pos + 1);
+
+               if (2 + sub_elem_len > len) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Invalid link info len: %zu %zu",
+                                  2 + sub_elem_len, len);
+                       goto out;
+               }
+
+               if  (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) {
+                       const struct ieee80211_eht_per_sta_profile *sta_prof =
+                               (const struct ieee80211_eht_per_sta_profile *)
+                               (pos + 2);
+                       u16 control = le_to_host16(sta_prof->sta_control);
+                       u8 link_id;
+
+                       link_id = control & EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK;
+                       removed_links |= BIT(link_id);
+               }
+
+               pos += 2 + sub_elem_len;
+               len -= 2 + sub_elem_len;
+       }
+
+       wpa_printf(MSG_DEBUG, "MLD: Reconfiguration: removed_links=0x%x",
+                  removed_links);
+out:
+       wpabuf_free(mlbuf);
+       return removed_links;
+}
index 8a45814e40771032fdae296923542565129b9f7c..39dad868e71a91d59caa45933c07d3a53f0c4280 100644 (file)
@@ -215,5 +215,7 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
                                   struct wpa_bss *bss,
                                   u8 *ap_mld_addr,
                                   u16 *missing_links);
+u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
+                                   struct wpa_bss *bss);
 
 #endif /* BSS_H */
index ccdb63598876b8691282e7d73ba6ff856c108c3e..dec98f867854c18171a6a0637a940fdf36cfe9cf 100644 (file)
@@ -1177,6 +1177,26 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 }
 
 
+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))
+               return true;
+
+       if (bss->n_mld_links == 0)
+               return true;
+
+       /* Check if the current BSS is going to be removed */
+       removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss);
+       if (BIT(bss->mld_links[0].link_id) & removed_links)
+               return false;
+
+       return true;
+}
+
+
 int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
 {
        int i, j;
@@ -1579,6 +1599,13 @@ skip_assoc_disallow:
                return false;
        }
 
+       if (!wpas_valid_ml_bss(wpa_s, bss)) {
+               if (debug_print)
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "   skip - ML BSS going to be removed");
+               return false;
+       }
+
        /* Matching configuration found */
        return true;
 }
@@ -1856,7 +1883,7 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s,
                                             struct wpa_ssid *ssid)
 {
        int *freqs;
-       u16 missing_links = 0;
+       u16 missing_links = 0, removed_links;
 
        if (!((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
              (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)))
@@ -1867,6 +1894,12 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s,
                                           &missing_links) || !missing_links)
                return 0;
 
+       removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, selected);
+       missing_links &= ~removed_links;
+
+       if (!missing_links)
+               return 0;
+
        wpa_dbg(wpa_s, MSG_DEBUG,
                "MLD: Doing an ML probe for missing links 0x%04x",
                missing_links);
index bb04652f558e3b95c930d1eff44dcab0220e0ae2..ab64d467bfe074c19db1d7d78ef563848b03e6af 100644 (file)
@@ -541,6 +541,15 @@ out:
 }
 
 
+static void wpas_ml_handle_removed_links(struct wpa_supplicant *wpa_s,
+                                        struct wpa_bss *bss)
+{
+       u16 removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss);
+
+       wpa_s->valid_links &= ~removed_links;
+}
+
+
 static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
                             union wpa_event_data *data,
                             int ie_offset)
@@ -639,6 +648,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
                params.mld = true;
                params.mld_link_id = wpa_s->mlo_assoc_link_id;
                params.ap_mld_addr = wpa_s->ap_mld_addr;
+               wpas_ml_handle_removed_links(wpa_s, bss);
        }
 
        if (wpa_s->sme.ssid_len != params.ssid_len ||