@@ -267,6 +267,7 @@ void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
wpa_printf(MSG_DEBUG,
"BSS: Clear ml_connect_probe_bss due to bss removal");
wpa_s->ml_connect_probe_bss = NULL;
+ wpa_s->ml_probe_pending_links = 0;
}
for (j = 0; j < MAX_NUM_MLD_LINKS; j++) {
@@ -2016,11 +2016,105 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
}
+/*
+ * Scan the channel of one of the links that are still missing after the ML
+ * probe. The Probe Request frame is addressed to the affiliated AP of that
+ * link, so a Probe Request Multi-Link element is not used and the information
+ * is updated from the Probe Response frame of that AP. Only a single BSSID can
+ * be specified per scan request, so each link is scanned separately.
+ * Returns: true if a scan was started
+ */
+static bool wpas_ml_scan_missing_link(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss = wpa_s->ml_connect_probe_bss;
+ struct wpa_ssid *ssid = wpa_s->ml_connect_probe_ssid;
+ u16 missing_links = 0, pending;
+ int link_id;
+
+ if (!wpa_s->ml_probe_pending_links)
+ return false;
+
+ /*
+ * The AP MLD may have provided the information for some or all of the
+ * missing links in the ML probe response.
+ */
+ wpa_bss_get_usable_links(wpa_s, bss, ssid, &missing_links);
+ pending = wpa_s->ml_probe_pending_links & missing_links;
+ if (!pending) {
+ wpa_s->ml_probe_pending_links = 0;
+ return false;
+ }
+
+ for_each_link(pending, link_id) {
+ const u8 *bssid = bss->mld_links[link_id].bssid;
+ int freq = bss->mld_links[link_id].freq;
+ int *freqs;
+
+ /*
+ * Do not scan for this link again during this connection
+ * attempt even if it is not found.
+ */
+ wpa_s->ml_probe_pending_links &= ~BIT(link_id);
+
+ if (freq <= 0 || is_zero_ether_addr(bssid))
+ continue;
+
+ freqs = os_malloc(sizeof(int) * 2);
+ if (!freqs)
+ return false;
+ freqs[0] = freq;
+ freqs[1] = 0;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "MLD: Scan link %d (" MACSTR " %d MHz) that is still missing after the ML probe",
+ link_id, MAC2STR(bssid), freq);
+
+ wpa_s->manual_scan_passive = 0;
+ wpa_s->manual_scan_use_id = 0;
+ wpa_s->manual_scan_only_new = 0;
+ wpa_s->scan_id_count = 0;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = freqs;
+
+ os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
+
+ /* An explicit SSID is needed to keep this an active scan. */
+ if (ssid->ssid_len) {
+ os_free(wpa_s->ssids_from_scan_req);
+ wpa_s->num_ssids_from_scan_req = 0;
+
+ wpa_s->ssids_from_scan_req =
+ os_zalloc(sizeof(struct wpa_ssid_value));
+ if (wpa_s->ssids_from_scan_req) {
+ wpa_s->num_ssids_from_scan_req = 1;
+ wpa_s->ssids_from_scan_req[0].ssid_len =
+ ssid->ssid_len;
+ os_memcpy(wpa_s->ssids_from_scan_req[0].ssid,
+ ssid->ssid, ssid->ssid_len);
+ }
+ }
+
+ wpa_s->normal_scans = 0;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return true;
+ }
+
+ return false;
+}
+
+
static bool ml_link_probe_scan(struct wpa_supplicant *wpa_s)
{
if (!wpa_s->ml_connect_probe_ssid || !wpa_s->ml_connect_probe_bss)
return false;
+ if (wpas_ml_scan_missing_link(wpa_s))
+ return true;
+
wpa_msg(wpa_s, MSG_DEBUG,
"Request association with " MACSTR " after ML probe",
MAC2STR(wpa_s->ml_connect_probe_bss->bssid));
@@ -2030,6 +2124,7 @@ static bool ml_link_probe_scan(struct wpa_supplicant *wpa_s)
wpa_s->ml_connect_probe_ssid = NULL;
wpa_s->ml_connect_probe_bss = NULL;
+ wpa_s->ml_probe_pending_links = 0;
return true;
}
@@ -2110,6 +2205,7 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s,
}
wpa_s->ml_probe_links = missing_links;
+ wpa_s->ml_probe_pending_links = missing_links;
wpa_s->normal_scans = 0;
wpa_s->scan_req = MANUAL_SCAN_REQ;
@@ -417,6 +417,7 @@ void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
if (wpa_s->ml_connect_probe_ssid == ssid) {
wpa_s->ml_connect_probe_ssid = NULL;
wpa_s->ml_connect_probe_bss = NULL;
+ wpa_s->ml_probe_pending_links = 0;
}
if (wpa_s->connect_without_scan == ssid)
wpa_s->connect_without_scan = NULL;
@@ -5267,6 +5267,7 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
wpa_s->ml_connect_probe_ssid = NULL;
wpa_s->ml_connect_probe_bss = NULL;
+ wpa_s->ml_probe_pending_links = 0;
wpas_connect_work_done(wpa_s);
wpa_clear_keys(wpa_s, addr);
old_ssid = wpa_s->current_ssid;
@@ -1711,6 +1711,11 @@ struct wpa_supplicant {
struct wpa_ssid *ml_connect_probe_ssid;
struct wpa_bss *ml_connect_probe_bss;
+ /*
+ * Links of the AP MLD that have not yet been scanned separately after
+ * the ML probe
+ */
+ u16 ml_probe_pending_links;
#ifdef CONFIG_OWE
/* An array of frequencies to scan for OWE transition mode BSSs when
wpa_supplicant_connect_ml_missing() sends a multi-link probe request on the channel of the association link and then associates with whatever link information the AP MLD returned. Not all AP MLDs return the per-STA profiles of the requested APs, and the association then proceeds without those links (observed with a TP-Link Deco BE65 in a 5 GHz + 6 GHz AP MLD configuration). Once the multi-link probe response has been processed, check which of the links are still missing and scan the channel of each of them so that the information can be updated from the Probe Response frame of the affiliated AP itself. The channel and the BSSID of each link are known from the RNR information in the scan entry of the association link. Such a scan is addressed to the affiliated AP of the link that is being scanned and does not include a Probe Request Multi-Link element. The channels cannot be covered by the multi-link probe scan instead. IEEE Std 802.11be-2024, 35.3.4.2 requires the Address 3 field of a multi-link probe request to be the BSSID of an AP, only a single BSSID can be specified per scan request, and using the association link's BSSID would leave cfg80211 filtering the channel of a co-located 6 GHz affiliated AP out of the scan. This is why commit 517b0d7cc841 ("MLD: Scan the channels of missing links for the ML probe") was reverted. The cost is one additional scan for each link that the AP MLD did not describe. A link is removed from the set of links to scan when its scan is started, so a link that cannot be found is not scanned again during the same connection attempt. Suggested-by: Michael-cy Lee <Michael-cy.Lee@mediatek.com> Signed-off-by: Louis Kotze <loukot@gmail.com> --- wpa_supplicant/bss.c | 1 + wpa_supplicant/events.c | 96 +++++++++++++++++++++++++++++++ wpa_supplicant/notify.c | 1 + wpa_supplicant/wpa_supplicant.c | 1 + wpa_supplicant/wpa_supplicant_i.h | 5 ++ 5 files changed, 104 insertions(+)