When selecting a network the default behaviour of WPA supplicant is to prefer higher throughput, it does this by capping the SNR. But in certain environments, reliability is important over throughput and choosing a lower SNR (thought it is greater than "Great SNR") might be sub-optimal. Introduce a configuration option to choose between the two options (throughput or reliability). Signed-off-by: Chaitanya Tata <Chaitanya.Tata@xxxxxxxxxxxxx> --- v2: Move to runtime configuration --- tests/hwsim/test_wpas_config.py | 3 ++- wpa_supplicant/config.c | 1 + wpa_supplicant/config.h | 8 ++++++++ wpa_supplicant/config_file.c | 2 ++ wpa_supplicant/p2p_supplicant.c | 1 + wpa_supplicant/scan.c | 16 ++++++++++++++-- wpa_supplicant/scan.h | 4 ++++ wpa_supplicant/wpa_cli.c | 4 +++- wpa_supplicant/wpa_supplicant.conf | 9 +++++++++ 9 files changed, 44 insertions(+), 4 deletions(-) diff --git a/tests/hwsim/test_wpas_config.py b/tests/hwsim/test_wpas_config.py index 2b6ab2ac0..decbdce4e 100644 --- a/tests/hwsim/test_wpas_config.py +++ b/tests/hwsim/test_wpas_config.py @@ -129,7 +129,8 @@ config_checks = [("ap_scan", "0"), ("p2p_device_random_mac_addr", "1"), ("p2p_device_persistent_mac_addr", "02:12:34:56:78:9a"), ("p2p_interface_random_mac_addr", "1"), - ("openssl_ciphers", "DEFAULT")] + ("openssl_ciphers", "DEFAULT"), + ("nw_sel_strategy", "1")] def supported_param(capa, field): mesh_params = ["user_mpm", "max_peer_links", "mesh_max_inactivity"] diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 2c756136c..80544a698 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -5589,6 +5589,7 @@ static const struct global_parse_data global_fields[] = { { FUNC(mld_connect_bssid_pref), 0 }, #endif /* CONFIG_TESTING_OPTIONS */ { INT_RANGE(ft_prepend_pmkid, 0, 1), CFG_CHANGED_FT_PREPEND_PMKID }, + { INT(nw_sel_strategy), 0 }, /* 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 8981305c2..38b4e920e 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1801,6 +1801,14 @@ struct wpa_config { int mld_force_single_link; #endif /* CONFIG_TESTING_OPTIONS */ + + /** + * nw_sel_strategy - Network selection strategy for scan results + * + * 0 = use the network with higher band preference + * 1 = use the network with highest SNR (no cap) + */ + int nw_sel_strategy; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 1a2c0c9be..3130e6ba7 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1625,6 +1625,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) #endif /* CONFIG_TESTING_OPTIONS */ if (config->ft_prepend_pmkid) fprintf(f, "ft_prepend_pmkid=%d", config->ft_prepend_pmkid); + if (config->nw_sel_strategy) + fprintf(f, "nw_sel_strategy=%d\n", config->nw_sel_strategy); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 70025f1e4..472fe0ae8 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2217,6 +2217,7 @@ do { \ d->go_venue_group = s->go_venue_group; d->go_venue_type = s->go_venue_type; d->p2p_add_cli_chan = s->p2p_add_cli_chan; + d->nw_sel_strategy = s->nw_sel_strategy; } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 2db4d8b91..f171c7af4 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -24,6 +24,9 @@ #include "scan.h" #include "mesh.h" +/* qsort_r is non-standard, so, use qsort and a global variable */ +static int nw_sel_strategy; + static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s); @@ -2376,6 +2379,7 @@ static int wpa_scan_result_compar(const void *a, const void *b) int snr_a, snr_b, snr_a_full, snr_b_full; size_t ies_len; const u8 *rsne_a, *rsne_b; + unsigned short snr_cap; /* WPA/WPA2 support preferred */ wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || @@ -2396,6 +2400,12 @@ static int wpa_scan_result_compar(const void *a, const void *b) (wb->caps & IEEE80211_CAP_PRIVACY) == 0) return -1; + if (nw_sel_strategy == 1) { + snr_cap = DISABLE_SNR_CAP; + } else { + snr_cap = GREAT_SNR; + } + if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) { /* * The scan result estimates SNR over 20 MHz, while Data frames @@ -2406,12 +2416,12 @@ static int wpa_scan_result_compar(const void *a, const void *b) snr_a_full = wpas_adjust_snr_by_chanwidth((const u8 *) (wa + 1), ies_len, wa->max_cw, wa->snr); - snr_a = MIN(snr_a_full, GREAT_SNR); + snr_a = MIN(snr_a_full, snr_cap); ies_len = wb->ie_len ? wb->ie_len : wb->beacon_ie_len; snr_b_full = wpas_adjust_snr_by_chanwidth((const u8 *) (wb + 1), ies_len, wb->max_cw, wb->snr); - snr_b = MIN(snr_b_full, GREAT_SNR); + snr_b = MIN(snr_b_full, snr_cap); } else { /* Level is not in dBm, so we can't calculate * SNR. Just use raw level (units unknown). */ @@ -3182,6 +3192,8 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, size_t i; int (*compar)(const void *, const void *) = wpa_scan_result_compar; + nw_sel_strategy = wpa_s->conf->nw_sel_strategy; + scan_res = wpa_drv_get_scan_results(wpa_s, bssid); if (scan_res == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results"); diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index d4c06c1ae..13b771a1e 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -30,6 +30,10 @@ */ #define GREAT_SNR 25 +/* Disabled capping of SNR for network selection */ +#define DISABLE_SNR_CAP 999 + + /* * IEEE Sts 802.11ax-2021, 9.4.2.161 (Transmit Power Envelope element) indicates * no max TX power limit if Maximum Transmit Power field is 63.5 dBm. diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 60f85624f..f71a37abf 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -517,6 +517,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos) #endif /* CONFIG_TESTING_OPTIONS */ "relative_rssi", "relative_band_adjust", "extended_key_id", + "nw_sel_strategy" }; int i, num_fields = ARRAY_SIZE(fields); @@ -617,7 +618,8 @@ static char ** wpa_cli_complete_get(const char *str, int pos) "tdls_external_control", "osu_dir", "wowlan_triggers", "p2p_search_delay", "mac_addr", "rand_addr_lifetime", "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", - "reassoc_same_bss_optim", "extended_key_id" + "reassoc_same_bss_optim", "extended_key_id", + "nw_sel_strategy" }; int i, num_fields = ARRAY_SIZE(fields); diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 2e36845f1..f65ab57ee 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -132,6 +132,15 @@ ap_scan=1 # 1: Do passive scans. #passive_scan=0 +# Network selection strategy +# +# 0 : Prefer the network with the higher band to get the best throughput. +# Cap the SNR value for comparing two networks to 25, and use the +# network with the higher band to get the best throughput. +# 1 : Prefer the network with the highest SNR ( +# Use the network with the highest SNR value without any capping. +nw_sel_strategy=0 + # MPM residency # By default, wpa_supplicant implements the mesh peering manager (MPM) for an # open mesh. However, if the driver can implement the MPM, you may set this to -- 2.34.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap