From: Benjamin Berg <benjamin.berg@xxxxxxxxx> Parse the link statuses out of ML assoc response. If the AP rejects ML association and marks the links as failed with a reason code other than TX_LINK_NOT_ACCEPTED, then also report these links to wpas_connection_failed and ignore them. Signed-off-by: Benjamin Berg <benjamin.berg@xxxxxxxxx> Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@xxxxxxxxx> --- wpa_supplicant/events.c | 287 +++++++++++++++++++++++++++++- wpa_supplicant/sme.c | 40 +++-- wpa_supplicant/sme.h | 6 +- wpa_supplicant/wpa_supplicant.c | 12 +- wpa_supplicant/wpa_supplicant_i.h | 12 +- 5 files changed, 329 insertions(+), 28 deletions(-) diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index a0c8eb1c53..bd6630ea7e 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3624,6 +3624,256 @@ 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 = NULL; + 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; + u32 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); + + 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 += 1; + } + + 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)) { + wpa_printf(MSG_DEBUG, "MLD: invalid MLD address"); + goto out; + } + + pos = common_info->variable; + + /* Store the information for the association link */ + ml_info[i].link_id = *(pos); + + /* skip the BSS Parameters change count */ + pos += 2; + + /* 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); + + pos += common_info->len - + (sizeof(*common_info) + pos - common_info->variable); + i++; + + 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; + + wpa_printf(MSG_DEBUG, "MLD: sub element len=%u", + sub_elem_len); + + if (2 + sub_elem_len > (int)ml_len) { + 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 %u sub element, len=%u", + *pos, sub_elem_len); + + pos += 2 + sub_elem_len; + ml_len -= 2 + sub_elem_len; + continue; + default: + wpa_printf(MSG_DEBUG, "MLD: invalid subelement ID=%u", + *pos); + goto out; + } + + /* skip the subelement ID and the length */ + pos += 2; + ml_len -= 2; + + /* 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 != *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_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; + } else { + wpa_printf(MSG_DEBUG, + "MLD: per sta profile too short"); + goto out; + } + + 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; @@ -4221,7 +4471,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); @@ -5236,6 +5486,10 @@ 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; + struct ml_sta_link_info ml_info[MAX_NUM_MLD_LINKS]; + const u8 *link_bssids[MAX_NUM_MLD_LINKS]; + u8 n_links, i, idx; #ifdef CONFIG_MBO struct wpa_bss *reject_bss; #endif /* CONFIG_MBO */ @@ -5290,7 +5544,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; } @@ -5325,7 +5579,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; } @@ -5362,8 +5616,31 @@ 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)); + idx = 0; + if (ieee802_11_parse_elems(data->assoc_reject.resp_ies, + data->assoc_reject.resp_ies_len, + &elems, 1) != ParseFailed) { + 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; } @@ -5400,7 +5677,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); } diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 95d1858800..b4fe088149 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1022,7 +1022,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); @@ -1158,7 +1158,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); @@ -1181,7 +1181,7 @@ no_fils: if (wpa_drv_authenticate(wpa_s, ¶ms) < 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); @@ -2003,7 +2003,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); } @@ -2047,7 +2048,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; } @@ -2096,7 +2098,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; } @@ -2120,7 +2123,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; } @@ -2134,7 +2138,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; } @@ -2592,7 +2597,7 @@ mscs_fail: if (wpa_drv_associate(wpa_s, ¶ms) < 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; @@ -2634,7 +2639,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; @@ -2647,7 +2652,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); @@ -2657,7 +2662,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), @@ -2721,7 +2727,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); } @@ -2729,7 +2735,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); } @@ -2738,7 +2744,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); } @@ -2767,7 +2773,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); } } @@ -2777,7 +2783,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); } } diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h index 50524d1318..f8fd06b95f 100644 --- a/wpa_supplicant/sme.h +++ b/wpa_supplicant/sme.h @@ -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) { } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index a292f05da8..c4c77e1810 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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. diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index c3c766bbf9..35a9c0c9e0 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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); -- 2.38.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap