@@ -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"]
@@ -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. */
@@ -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;
};
@@ -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 */
@@ -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;
}
@@ -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");
@@ -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.
@@ -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);
@@ -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
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@nordicsemi.no> --- 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(-)