diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a0d151d7a..1aff67be2 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -4671,6 +4671,10 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->driver_param = os_strdup(driver_param); config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; +#ifdef CONFIG_TESTING_OPTIONS + config->mld_connect_band_pref = DEFAULT_MLD_CONNECT_BAND_PREF; +#endif /* CONFIG_TESTING_OPTIONS */ + return config; } @@ -5306,6 +5310,23 @@ static int wpa_config_get_ipv4(const char *name, struct wpa_config *config, #endif /* CONFIG_P2P */ +#ifdef CONFIG_TESTING_OPTIONS +static int wpa_config_process_mld_connect_bssid_pref( + const struct global_parse_data *data, + struct wpa_config *config, int line, const char *pos) +{ + if (hwaddr_aton2(pos, config->mld_connect_bssid_pref) < 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid mld_connect_bssid_pref '%s'", + line, pos); + return -1; + } + + return 0; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + #ifdef OFFSET #undef OFFSET #endif /* OFFSET */ @@ -5519,6 +5540,11 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(pasn_corrupt_mic, 0, 1), 0 }, #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN */ +#ifdef CONFIG_TESTING_OPTIONS + { INT_RANGE(mld_force_single_link, 0, 1), 0 }, + { INT_RANGE(mld_connect_band_pref, 0, MLD_CONNECT_BAND_PREF_MAX), 0 }, + { FUNC(mld_connect_bssid_pref), 0 }, +#endif /* CONFIG_TESTING_OPTIONS */ /* NOTE: When adding new parameters here, add_interface() in * wpa_supplicant/dbus_new_introspect.c may need to be modified to * increase the size of the iface->xml buffer. */ diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 7d2b57028..02139e6b2 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -47,6 +47,7 @@ #define DEFAULT_OCE_SUPPORT OCE_STA #define DEFAULT_EXTENDED_KEY_ID 0 #define DEFAULT_SCAN_RES_VALID_FOR_CONNECT 5 +#define DEFAULT_MLD_CONNECT_BAND_PREF MLD_CONNECT_BAND_PREF_AUTO #include "config_ssid.h" #include "wps/wps.h" @@ -1777,6 +1778,20 @@ struct wpa_config { #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN*/ + +#ifdef CONFIG_TESTING_OPTIONS + enum { + MLD_CONNECT_BAND_PREF_AUTO = 0, + MLD_CONNECT_BAND_PREF_2GHZ = 1, + MLD_CONNECT_BAND_PREF_5GHZ = 2, + MLD_CONNECT_BAND_PREF_6GHZ = 3, + MLD_CONNECT_BAND_PREF_MAX = 4, + } mld_connect_band_pref; + + u8 mld_connect_bssid_pref[ETH_ALEN]; + + int mld_force_single_link; +#endif /* CONFIG_TESTING_OPTIONS */ }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 9a474bd83..4db85f9c0 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1612,6 +1612,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->wowlan_disconnect_on_deinit) fprintf(f, "wowlan_disconnect_on_deinit=%d\n", config->wowlan_disconnect_on_deinit); +#ifdef CONFIG_TESTING_OPTIONS + if (config->mld_force_single_link) + fprintf(f, "mld_force_single_link=1\n"); + if (config->mld_connect_band_pref != MLD_CONNECT_BAND_PREF_AUTO) + fprintf(f, "mld_connect_band_pref=%d\n", + config->mld_connect_band_pref); + if (!is_zero_ether_addr(config->mld_connect_bssid_pref)) + fprintf(f, "mld_connect_bssid_pref=" MACSTR "\n", + MAC2STR(config->mld_connect_bssid_pref)); +#endif /* CONFIG_TESTING_OPTIONS */ } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 02114acae..26abdc69c 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -606,6 +606,88 @@ static void wpas_ml_handle_removed_links(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_TESTING_OPTIONS +static struct wpa_bss * wpas_ml_connect_pref(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + unsigned int low, high, i; + + wpa_printf(MSG_DEBUG, + "MLD: valid_links=%d, band_pref=%u, bssid_pref=" MACSTR, + wpa_s->valid_links, + wpa_s->conf->mld_connect_band_pref, + MAC2STR(wpa_s->conf->mld_connect_bssid_pref)); + + /* Check if there are more than one link */ + if (!(wpa_s->valid_links & (wpa_s->valid_links - 1))) + return bss; + + if (!is_zero_ether_addr(wpa_s->conf->mld_connect_bssid_pref)) { + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (!(wpa_s->valid_links & BIT(i))) + continue; + + if (wpa_s->mlo_assoc_link_id == i) + continue; + + if (os_memcmp(wpa_s->links[i].bssid, + wpa_s->conf->mld_connect_bssid_pref, + ETH_ALEN) == 0) + goto found; + } + } + + if (wpa_s->conf->mld_connect_band_pref == MLD_CONNECT_BAND_PREF_AUTO) + return bss; + + switch (wpa_s->conf->mld_connect_band_pref) { + case MLD_CONNECT_BAND_PREF_2GHZ: + low = 2412; + high = 2472; + break; + case MLD_CONNECT_BAND_PREF_5GHZ: + low = 5180; + high = 5985; + break; + case MLD_CONNECT_BAND_PREF_6GHZ: + low = 5955; + high = 7125; + break; + default: + return bss; + } + + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (!(wpa_s->valid_links & BIT(i))) + continue; + + if (wpa_s->mlo_assoc_link_id == i) + continue; + + if (wpa_s->links[i].freq >= low && wpa_s->links[i].freq <= high) + goto found; + } + +found: + if (i == MAX_NUM_MLD_LINKS) { + wpa_printf(MSG_DEBUG, "MLD: No match for connect/band pref"); + return bss; + } + + wpa_printf(MSG_DEBUG, + "MLD: Change BSS for connect: " MACSTR " -> " MACSTR, + MAC2STR(wpa_s->links[wpa_s->mlo_assoc_link_id].bssid), + MAC2STR(wpa_s->links[i].bssid)); + + /* Get the BSS entry and do the switch */ + bss = wpa_bss_get_bssid(wpa_s, wpa_s->links[i].bssid); + wpa_s->mlo_assoc_link_id = i; + + return bss; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data, int ie_offset) @@ -686,11 +768,27 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, return; } + os_memset(¶ms, 0, sizeof(params)); + if (wpas_ml_element(wpa_s, bss, ssid)) { + wpa_printf(MSG_DEBUG, "MLD: In authentication"); +#ifdef CONFIG_TESTING_OPTIONS + bss = wpas_ml_connect_pref(wpa_s, bss); + + if (wpa_s->conf->mld_force_single_link) { + wpa_printf(MSG_DEBUG, "MLD: Force single link"); + wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id); + } +#endif /* CONFIG_TESTING_OPTIONS */ + 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); + } + skip_auth = wpa_s->conf->reassoc_same_bss_optim && wpa_s->reassoc_same_bss; wpa_s->current_bss = bss; - os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; params.freq = bss->freq; @@ -699,14 +797,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, params.ssid_len = bss->ssid_len; params.p2p = ssid->p2p_group; - if (wpas_ml_element(wpa_s, bss, ssid)) { - wpa_printf(MSG_DEBUG, "MLD: In authentication"); - 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 || os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0) wpa_s->sme.prev_bssid_set = 0;