SME: MLD: Handle reconfiguration Multi-Link element

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>
This commit is contained in:
Andrei Otcheretianski 2023-06-12 22:59:50 +03:00 committed by Jouni Malinen
parent e933c4e5a3
commit e5ea30feef
5 changed files with 136 additions and 3 deletions

View file

@ -2700,9 +2700,17 @@ struct eht_ml_probe_req_common_info {
u8 variable[]; u8 variable[];
} STRUCT_PACKED; } 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 */ /* IEEE P802.11be/D2.0, 9.4.2.312.1 - Multi-Link element / General */

View file

@ -1708,3 +1708,83 @@ out:
wpabuf_free(mlbuf); wpabuf_free(mlbuf);
return ret; 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;
}

View file

@ -215,5 +215,7 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_bss *bss,
u8 *ap_mld_addr, u8 *ap_mld_addr,
u16 *missing_links); u16 *missing_links);
u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss);
#endif /* BSS_H */ #endif /* BSS_H */

View 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 disabled_freq(struct wpa_supplicant *wpa_s, int freq)
{ {
int i, j; int i, j;
@ -1579,6 +1599,13 @@ skip_assoc_disallow:
return false; 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 */ /* Matching configuration found */
return true; return true;
} }
@ -1856,7 +1883,7 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid) struct wpa_ssid *ssid)
{ {
int *freqs; int *freqs;
u16 missing_links = 0; u16 missing_links = 0, removed_links;
if (!((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) && if (!((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))) (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) &missing_links) || !missing_links)
return 0; 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, wpa_dbg(wpa_s, MSG_DEBUG,
"MLD: Doing an ML probe for missing links 0x%04x", "MLD: Doing an ML probe for missing links 0x%04x",
missing_links); missing_links);

View 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, static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
union wpa_event_data *data, union wpa_event_data *data,
int ie_offset) int ie_offset)
@ -639,6 +648,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
params.mld = true; params.mld = true;
params.mld_link_id = wpa_s->mlo_assoc_link_id; params.mld_link_id = wpa_s->mlo_assoc_link_id;
params.ap_mld_addr = wpa_s->ap_mld_addr; 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 || if (wpa_s->sme.ssid_len != params.ssid_len ||