]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
MLD: Also mark links as failed after association failure
authorBenjamin Berg <benjamin.berg@intel.com>
Mon, 20 Nov 2023 23:51:25 +0000 (01:51 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 25 Nov 2023 14:44:01 +0000 (16:44 +0200)
Parse the link status values out of Multi-Link association response. If
the AP rejects ML association and marks the links as failed with a
reason code other than TX_LINK_NOT_ACCEPTED, also report these links to
wpas_connection_failed() and ignore them.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/sme.h
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index c404f4597f724b6994bf8113f6979353bdfcbbdf..7430e51b63cb5cb513da79b012e3c34959a3be69 100644 (file)
@@ -3642,6 +3642,262 @@ static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
 }
 
 
+static unsigned int wpas_ml_parse_assoc(struct wpa_supplicant *wpa_s,
+                                       struct ieee802_11_elems *elems,
+                                       struct ml_sta_link_info *ml_info)
+{
+       struct wpabuf *mlbuf;
+       struct ieee80211_eht_ml *ml;
+       size_t ml_len;
+       struct eht_ml_basic_common_info *common_info;
+       const u8 *pos;
+       u16 eml_capa = 0, mld_capa = 0;
+       const u16 control =
+               host_to_le16(MULTI_LINK_CONTROL_TYPE_BASIC |
+                            BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
+                            BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT);
+       u8 expected_common_info_len = 9;
+       unsigned int i = 0;
+       u16 ml_control;
+
+       if (!wpa_s->valid_links || !elems->basic_mle || !elems->basic_mle_len)
+               return 0;
+
+       mlbuf = ieee802_11_defrag(elems->basic_mle, elems->basic_mle_len, true);
+       if (!mlbuf)
+               return 0;
+
+       ml = (struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
+       ml_len = wpabuf_len(mlbuf);
+       if (ml_len < sizeof(*ml))
+               goto out;
+
+       os_memset(ml_info, 0, sizeof(*ml_info) * MAX_NUM_MLD_LINKS);
+
+       ml_control = le_to_host16(ml->ml_control);
+
+       if ((ml_control & control) != control) {
+               wpa_printf(MSG_DEBUG, "MLD: Invalid presence BM=0x%x",
+                          ml_control);
+               goto out;
+       }
+
+       if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) {
+               wpa_printf(MSG_DEBUG, "MLD: EML capabilities included");
+               expected_common_info_len += 2;
+       }
+
+       if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) {
+               wpa_printf(MSG_DEBUG, "MLD: MLD capabilities included");
+               expected_common_info_len += 2;
+       }
+
+       if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) {
+               wpa_printf(MSG_DEBUG,
+                          "MLD: Unexpected: medium sync delay info present");
+               expected_common_info_len += 2;
+       }
+
+       if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID) {
+               wpa_printf(MSG_DEBUG,
+                          "MLD: Unexpected: MLD ID present");
+               expected_common_info_len++;
+       }
+
+       if (sizeof(*ml) + expected_common_info_len > ml_len) {
+               wpa_printf(MSG_DEBUG,
+                          "MLD: Not enough bytes for common info. ml_len=%zu",
+                          ml_len);
+               goto out;
+       }
+
+       common_info = (struct eht_ml_basic_common_info *) ml->variable;
+       if (common_info->len != expected_common_info_len) {
+               wpa_printf(MSG_DEBUG,
+                          "MLD: Invalid common info len=%u. expected=%u",
+                          common_info->len, expected_common_info_len);
+               goto out;
+       }
+
+       wpa_printf(MSG_DEBUG, "MLD: address: " MACSTR,
+                  MAC2STR(common_info->mld_addr));
+
+       if (os_memcmp(wpa_s->ap_mld_addr, common_info->mld_addr, ETH_ALEN) !=
+           0) {
+               wpa_printf(MSG_DEBUG, "MLD: Mismatching MLD address (expected "
+                          MACSTR ")", MAC2STR(wpa_s->ap_mld_addr));
+               goto out;
+       }
+
+       pos = common_info->variable;
+
+       /* Store the information for the association link */
+       ml_info[i].link_id = *pos;
+       pos++;
+
+       /* Skip the BSS Parameters Change Count */
+       pos++;
+
+       /* Skip the Medium Synchronization Delay Information if present  */
+       if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO)
+               pos += 2;
+
+       if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) {
+               eml_capa = WPA_GET_LE16(pos);
+               pos += 2;
+       }
+
+       if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) {
+               mld_capa = WPA_GET_LE16(pos);
+               pos += 2;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "MLD: link_id=%u, eml=0x%x, mld=0x%x",
+                  ml_info[i].link_id, eml_capa, mld_capa);
+
+       i++;
+
+       pos = ((u8 *) common_info) + common_info->len;
+       ml_len -= sizeof(*ml) + common_info->len;
+       while (ml_len > 2 && i < MAX_NUM_MLD_LINKS) {
+               u8 sub_elem_len = pos[1];
+               u8 sta_info_len;
+               u8 nstr_bitmap_len = 0;
+               u16 ctrl;
+               const u8 *end;
+
+               wpa_printf(MSG_DEBUG, "MLD: Subelement len=%u", sub_elem_len);
+
+               if (sub_elem_len > ml_len - 2) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Invalid link info len: %u > %zu",
+                                  2 + sub_elem_len, ml_len);
+                       goto out;
+               }
+
+               switch (*pos) {
+               case EHT_ML_SUB_ELEM_PER_STA_PROFILE:
+                       break;
+               case EHT_ML_SUB_ELEM_FRAGMENT:
+               case EHT_ML_SUB_ELEM_VENDOR:
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Skip subelement id=%u, len=%u",
+                                  *pos, sub_elem_len);
+                       pos += 2 + sub_elem_len;
+                       ml_len -= 2 + sub_elem_len;
+                       continue;
+               default:
+                       wpa_printf(MSG_DEBUG, "MLD: Unknown subelement ID=%u",
+                                  *pos);
+                       goto out;
+               }
+
+               end = pos + 2 + sub_elem_len;
+
+               /* Skip the subelement ID and the length */
+               pos += 2;
+               ml_len -= 2;
+
+               if (end - pos < 2)
+                       goto out;
+
+               /* Get the station control field */
+               ctrl = WPA_GET_LE16(pos);
+
+               pos += 2;
+               ml_len -= 2;
+
+               if (!(ctrl & EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Per STA complete profile expected");
+                       goto out;
+               }
+
+               if (!(ctrl & EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Per STA MAC address not present");
+                       goto out;
+               }
+
+               if (!(ctrl & EHT_PER_STA_CTRL_TSF_OFFSET_PRESENT_MSK)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Per STA TSF offset not present");
+                       goto out;
+               }
+
+               if (!(ctrl & EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Beacon interval not present");
+                       goto out;
+               }
+
+               if (!(ctrl & EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD:  DTIM information not present");
+                       goto out;
+               }
+
+               if (ctrl & EHT_PER_STA_CTRL_NSTR_LINK_PAIR_PRESENT_MSK) {
+                       if (ctrl & EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK)
+                               nstr_bitmap_len = 2;
+                       else
+                               nstr_bitmap_len = 1;
+               }
+
+               if (!(ctrl & EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD:  BSS params change count not present");
+                       goto out;
+               }
+
+               sta_info_len = 1 + ETH_ALEN + 8 + 2 + 2 + 1 + nstr_bitmap_len;
+               if (sta_info_len > ml_len || sta_info_len > end - pos ||
+                   sta_info_len + 2 > sub_elem_len ||
+                   sta_info_len != *pos) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MLD: Invalid STA info len=%u, len=%u",
+                                  sta_info_len, *pos);
+                       goto out;
+               }
+
+               /* Get the link address */
+               wpa_printf(MSG_DEBUG,
+                          "MLD: link addr: " MACSTR " nstr BM len=%u",
+                          MAC2STR(pos + 1), nstr_bitmap_len);
+
+               ml_info[i].link_id = ctrl & EHT_PER_STA_CTRL_LINK_ID_MSK;
+               os_memcpy(ml_info[i].bssid, pos + 1, ETH_ALEN);
+
+               pos += sta_info_len;
+               ml_len -= sta_info_len;
+
+               wpa_printf(MSG_DEBUG, "MLD: sub_elem_len=%u, sta_info_len=%u",
+                          sub_elem_len, sta_info_len);
+
+               sub_elem_len -= sta_info_len + 2;
+               if (sub_elem_len < 4) {
+                       wpa_printf(MSG_DEBUG, "MLD: Per STA profile too short");
+                       goto out;
+               }
+
+               wpa_hexdump(MSG_MSGDUMP, "MLD: STA profile", pos, sub_elem_len);
+               ml_info[i].status = WPA_GET_LE16(pos + 2);
+
+               pos += sub_elem_len;
+               ml_len -= sub_elem_len;
+
+               i++;
+       }
+
+       wpabuf_free(mlbuf);
+       return i;
+out:
+       wpabuf_free(mlbuf);
+       return 0;
+}
+
+
 static int wpa_drv_get_mlo_info(struct wpa_supplicant *wpa_s)
 {
        struct driver_sta_mlo_info mlo;
@@ -4236,7 +4492,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
        if (is_zero_ether_addr(bssid))
                bssid = wpa_s->pending_bssid;
        if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
-               wpas_connection_failed(wpa_s, bssid);
+               wpas_connection_failed(wpa_s, bssid, NULL);
        wpa_sm_notify_disassoc(wpa_s->wpa);
        ptksa_cache_flush(wpa_s->ptksa, wpa_s->bssid, WPA_CIPHER_NONE);
 
@@ -5251,6 +5507,8 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
                                    union wpa_event_data *data)
 {
        const u8 *bssid = data->assoc_reject.bssid;
+       struct ieee802_11_elems elems;
+       const u8 *link_bssids[MAX_NUM_MLD_LINKS];
 #ifdef CONFIG_MBO
        struct wpa_bss *reject_bss;
 #endif /* CONFIG_MBO */
@@ -5305,7 +5563,7 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
                if (!bss) {
                        bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
                        if (!bss) {
-                               wpas_connection_failed(wpa_s, bssid);
+                               wpas_connection_failed(wpa_s, bssid, NULL);
                                wpa_supplicant_mark_disassoc(wpa_s);
                                return;
                        }
@@ -5340,7 +5598,7 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
                if (!bss || wpa_s->dpp_pfs_fallback) {
                        wpa_printf(MSG_DEBUG,
                                   "DPP: Updated PFS policy for next try");
-                       wpas_connection_failed(wpa_s, bssid);
+                       wpas_connection_failed(wpa_s, bssid, NULL);
                        wpa_supplicant_mark_disassoc(wpa_s);
                        return;
                }
@@ -5377,8 +5635,34 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_MBO */
 
+       /* Check for other failed links in the response */
+       os_memset(link_bssids, 0, sizeof(link_bssids));
+       if (ieee802_11_parse_elems(data->assoc_reject.resp_ies,
+                                  data->assoc_reject.resp_ies_len,
+                                  &elems, 1) != ParseFailed) {
+               struct ml_sta_link_info ml_info[MAX_NUM_MLD_LINKS];
+               unsigned int n_links, i, idx;
+
+               idx = 0;
+               n_links = wpas_ml_parse_assoc(wpa_s, &elems, ml_info);
+
+               for (i = 1; i < n_links; i++) {
+                       /* The status cannot be success here.
+                        * Add the link to the failed list if it is reporting
+                        * an error. The only valid "non-error" status is
+                        * TX_LINK_NOT_ACCEPTED as that means this link may
+                        * still accept an association from us.
+                        */
+                       if (ml_info[i].status !=
+                           WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED) {
+                               link_bssids[idx] = ml_info[i].bssid;
+                               idx++;
+                       }
+               }
+       }
+
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
-               sme_event_assoc_reject(wpa_s, data);
+               sme_event_assoc_reject(wpa_s, data, link_bssids);
                return;
        }
 
@@ -5415,7 +5699,7 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_FILS */
 
-       wpas_connection_failed(wpa_s, bssid);
+       wpas_connection_failed(wpa_s, bssid, link_bssids);
        wpa_supplicant_mark_disassoc(wpa_s);
 }
 
index 9af7a368a2d47528ba3953ec9f72c1cd1ec2acff..6a2f3602a30d14bb70b566dcf3b10682cf8e57b4 100644 (file)
@@ -1021,7 +1021,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
                else
                        resp = sme_auth_build_sae_confirm(wpa_s, 0);
                if (resp == NULL) {
-                       wpas_connection_failed(wpa_s, bss->bssid);
+                       wpas_connection_failed(wpa_s, bss->bssid, NULL);
                        return;
                }
                params.auth_data = wpabuf_head(resp);
@@ -1157,7 +1157,7 @@ no_fils:
                        if (wpas_p2p_handle_frequency_conflicts(wpa_s,
                                                                params.freq,
                                                                ssid) < 0) {
-                               wpas_connection_failed(wpa_s, bss->bssid);
+                               wpas_connection_failed(wpa_s, bss->bssid, NULL);
                                wpa_supplicant_mark_disassoc(wpa_s);
                                wpabuf_free(resp);
                                wpas_connect_work_done(wpa_s);
@@ -1180,7 +1180,7 @@ no_fils:
        if (wpa_drv_authenticate(wpa_s, &params) < 0) {
                wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
                        "driver failed");
-               wpas_connection_failed(wpa_s, bss->bssid);
+               wpas_connection_failed(wpa_s, bss->bssid, NULL);
                wpa_supplicant_mark_disassoc(wpa_s);
                wpabuf_free(resp);
                wpas_connect_work_done(wpa_s);
@@ -2002,7 +2002,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                                   data->auth.ies_len, 0, data->auth.peer,
                                   &ie_offset);
                if (res < 0) {
-                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
+                                              NULL);
                        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 
                }
@@ -2046,7 +2047,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
                    wpa_s->sme.auth_alg == data->auth.auth_type ||
                    wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
-                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
+                                              NULL);
                        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                        return;
                }
@@ -2095,7 +2097,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                                " reason=%d locally_generated=1",
                                MAC2STR(wpa_s->pending_bssid),
                                WLAN_REASON_DEAUTH_LEAVING);
-                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
+                                              NULL);
                        wpa_supplicant_mark_disassoc(wpa_s);
                        return;
                }
@@ -2119,7 +2122,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                                " reason=%d locally_generated=1",
                                MAC2STR(wpa_s->pending_bssid),
                                WLAN_REASON_DEAUTH_LEAVING);
-                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
+                                              NULL);
                        wpa_supplicant_mark_disassoc(wpa_s);
                        return;
                }
@@ -2133,7 +2137,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                                " reason=%d locally_generated=1",
                                MAC2STR(wpa_s->pending_bssid),
                                WLAN_REASON_DEAUTH_LEAVING);
-                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
+                                              NULL);
                        wpa_supplicant_mark_disassoc(wpa_s);
                        return;
                }
@@ -2591,7 +2596,7 @@ mscs_fail:
        if (wpa_drv_associate(wpa_s, &params) < 0) {
                wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
                        "driver failed");
-               wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+               wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL);
                wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
                return;
@@ -2633,7 +2638,7 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
 }
 
 
-static void sme_deauth(struct wpa_supplicant *wpa_s)
+static void sme_deauth(struct wpa_supplicant *wpa_s, const u8 **link_bssids)
 {
        int bssid_changed;
 
@@ -2646,7 +2651,7 @@ static void sme_deauth(struct wpa_supplicant *wpa_s)
        }
        wpa_s->sme.prev_bssid_set = 0;
 
-       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid, link_bssids);
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        os_memset(wpa_s->bssid, 0, ETH_ALEN);
        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
@@ -2656,7 +2661,8 @@ static void sme_deauth(struct wpa_supplicant *wpa_s)
 
 
 void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-                           union wpa_event_data *data)
+                           union wpa_event_data *data,
+                           const u8 **link_bssids)
 {
        wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association with " MACSTR " failed: "
                "status code %d", MAC2STR(wpa_s->pending_bssid),
@@ -2720,7 +2726,7 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
         * benefit from using the previous authentication, so this could be
         * optimized in the future.
         */
-       sme_deauth(wpa_s);
+       sme_deauth(wpa_s, link_bssids);
 }
 
 
@@ -2728,7 +2734,7 @@ void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
                              union wpa_event_data *data)
 {
        wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication timed out");
-       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL);
        wpa_supplicant_mark_disassoc(wpa_s);
 }
 
@@ -2737,7 +2743,7 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
                               union wpa_event_data *data)
 {
        wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association timed out");
-       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL);
        wpa_supplicant_mark_disassoc(wpa_s);
 }
 
@@ -2766,7 +2772,7 @@ static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx)
        struct wpa_supplicant *wpa_s = eloop_ctx;
        if (wpa_s->wpa_state == WPA_AUTHENTICATING) {
                wpa_msg(wpa_s, MSG_DEBUG, "SME: Authentication timeout");
-               sme_deauth(wpa_s);
+               sme_deauth(wpa_s, NULL);
        }
 }
 
@@ -2776,7 +2782,7 @@ static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx)
        struct wpa_supplicant *wpa_s = eloop_ctx;
        if (wpa_s->wpa_state == WPA_ASSOCIATING) {
                wpa_msg(wpa_s, MSG_DEBUG, "SME: Association timeout");
-               sme_deauth(wpa_s);
+               sme_deauth(wpa_s, NULL);
        }
 }
 
index 50524d13184e9b0adce452334259b50ddc1e8c31..f8fd06b95f5a38d5dc5e1c40fb1d586add1bef07 100644 (file)
@@ -19,7 +19,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data);
 int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
                      const u8 *ies, size_t ies_len);
 void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-                           union wpa_event_data *data);
+                           union wpa_event_data *data,
+                           const u8 **link_bssids);
 void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
                              union wpa_event_data *data);
 void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
@@ -63,7 +64,8 @@ static inline int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
 
 
 static inline void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-                                         union wpa_event_data *data)
+                                         union wpa_event_data *data,
+                                         const u8 **link_bssids)
 {
 }
 
index 38399d6400d05242151b267678135f19f4fe025b..c4c58b75707dd7e9e8578cb2ef54e172470cf266 100644 (file)
@@ -4420,7 +4420,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                         * can stop right here; the association will not
                         * succeed.
                         */
-                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
+                                              NULL);
                        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
                        return;
@@ -8169,7 +8170,8 @@ static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
 }
 
 
-void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                           const u8 **link_bssids)
 {
        int timeout;
        int count;
@@ -8199,6 +8201,12 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
                return;
        }
 
+       /* Also mark links as failed */
+       while (link_bssids && *link_bssids) {
+               wpa_bssid_ignore_add(wpa_s, *link_bssids);
+               link_bssids++;
+       }
+
        /*
         * Add the failed BSSID into the ignore list and speed up next scan
         * attempt if there could be other APs that could accept association.
index c3c766bbf903699af3270bfa051f92465336b515..35a9c0c9e05cd7e4f9b959d653c5630b6de3c65e 100644 (file)
@@ -661,6 +661,13 @@ struct active_scs_elem {
 };
 
 
+struct ml_sta_link_info {
+       u8 link_id;
+       u8 bssid[ETH_ALEN];
+       u16 status;
+};
+
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -723,7 +730,7 @@ struct wpa_supplicant {
        u8 ap_mld_addr[ETH_ALEN];
        u8 mlo_assoc_link_id;
        u16 valid_links; /* bitmap of valid MLO link IDs */
-       struct ml_sta_link_info {
+       struct {
                u8 addr[ETH_ALEN];
                u8 bssid[ETH_ALEN];
                unsigned int freq;
@@ -1688,7 +1695,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *own_addr,
                             enum frame_encryption encrypted);
 void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
-void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                           const u8 **link_bssids);
 void fils_connection_failure(struct wpa_supplicant *wpa_s);
 void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
 int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);