From 5f8e010965377c28ede4d09ef8cb4b321d69769f Mon Sep 17 00:00:00 2001
From: Jeffrey Isaacs <jeff.isaacs.ext@nokia.com>
Date: Mon, 15 Mar 2021 17:02:25 -0400
Subject: [PATCH 1/2] wpa_supplicant: Add is_secondary_scan_iface to wpa_config

This is the first in a series of commits that will implement
offloading active scanning for available access points to a
secondary interface. The motivation behind this is that
performing active scans is disruptive to the WiFi connection.
In mission critical applications, or when a constant high
throughput is required, roaming between APs can result in
unacceptable performance. When a client's rssi drops too low,
or all the BSS table entries expire, the interface performs
an active scan to find the next available AP.

The new parameter is_secondary_scan_iface will be specified in
the interface config file. When set to 1, scan results from that
interface will be used to update the BSS tables in all interfaces
whose is_secondary_scan_iface is set to 0. This allows the
primary interface to roam between BSSs without having to take time
to scan.

This parameter does not affect any other parameters. It would make
sense that if a secondary interface is specified, the frequency
of scans performed on that interface should be increased to fully
leverage this feature.

Signed-off-by: Jeffrey Isaacs <jeff.isaacs.ext@nokia.com>
---
 wpa_supplicant/config.c      |  2 ++
 wpa_supplicant/config.h      | 12 ++++++++++++
 wpa_supplicant/config_file.c |  3 +++
 3 files changed, 17 insertions(+)

diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index ce5c80d02..1935e097d 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4378,6 +4378,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	config->cert_in_cb = DEFAULT_CERT_IN_CB;
 	config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
 	config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
+	config->is_secondary_scan_iface = DEFAULT_IS_SECONDARY_SCAN_IFACE;
 
 #ifdef CONFIG_MBO
 	config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
@@ -5210,6 +5211,7 @@ static const struct global_parse_data global_fields[] = {
 	{ INT_RANGE(force_kdk_derivation, 0, 1), 0 },
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_PASN */
+	{ INT(is_secondary_scan_iface), 0 },
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index aac4a9dff..b10beaba4 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -46,6 +46,7 @@
 #define DEFAULT_OCE_SUPPORT OCE_STA
 #define DEFAULT_EXTENDED_KEY_ID 0
 #define DEFAULT_SCAN_RES_VALID_FOR_CONNECT 5
+#define DEFAULT_IS_SECONDARY_SCAN_IFACE 0
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -1650,6 +1651,17 @@ struct wpa_config {
 	int force_kdk_derivation;
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_PASN*/
+
+	/**
+	 * is_secondary_scan_iface - Enable dedicated scan interface
+	 *
+	 * 0 = Scan results are not shared with other interfaces
+	 * 1 = Scan results from this interface are used to update
+	 	   the BSS table of each other interface
+	 *
+	 * By default, scan results are not shared
+	 */
+	int is_secondary_scan_iface;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index a535e3f08..2f86263b8 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1530,6 +1530,9 @@ 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);
+	if (config->is_secondary_scan_iface)
+		fprintf(f, "is_secondary_scan_iface=%d\n",
+			config->is_secondary_scan_iface);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
-- 
2.17.1


From cbf7388a3cb99f67c240d1b41f9edef6d685732f Mon Sep 17 00:00:00 2001
From: Jeffrey Isaacs <jeff.isaacs.ext@nokia.com>
Date: Mon, 15 Mar 2021 17:36:56 -0400
Subject: [PATCH 2/2] wpa_supplicant: Implement active scanning from secondary
 interface

This commit implements the changes required for the
is_secondary_scan_iface parameter. When the parameter is set for a
given interface, when scan results are available on that interface,
wpa_bss_update is called using those results on all other interfaces
that have is_secondary_scan_interface set to 0.

Signed-off-by: Jeffrey Isaacs <jeff.isaacs.ext@nokia.com>
---
 wpa_supplicant/bss.c        | 20 +++++++++++++++++++-
 wpa_supplicant/bss.h        |  3 ++-
 wpa_supplicant/ctrl_iface.c |  2 +-
 wpa_supplicant/scan.c       |  2 +-
 wpa_supplicant/wnm_sta.c    |  2 +-
 5 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index e13783ce1..56121436e 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -747,8 +747,26 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
  */
 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
 			     struct wpa_scan_res *res,
-			     struct os_reltime *fetch_time)
+			     struct os_reltime *fetch_time,
+			     int secondary_scan)
 {
+	struct wpa_supplicant *iface;
+	iface = wpa_s->global->ifaces;
+
+	while (iface && !secondary_scan) {
+		if (wpa_s->conf->is_secondary_scan_iface && !iface->conf->is_secondary_scan_iface) {
+			wpa_bss_update_scan_res(iface, res, fetch_time, 1);
+		}
+		if (iface->p2pdev == wpa_s)
+			iface->p2pdev = iface->parent;
+		if (iface == wpa_s || iface->parent != wpa_s) {
+			iface = iface->next;
+			continue;
+		}
+		iface = iface->next;
+	}
+
+
 	const u8 *ssid, *p2p, *mesh;
 	struct wpa_bss *bss;
 
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 4078b9b9d..eb34b425d 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -135,7 +135,8 @@ void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
 void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
 			     struct wpa_scan_res *res,
-			     struct os_reltime *fetch_time);
+			     struct os_reltime *fetch_time,
+			     int secondary_scan);
 void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 		    const char *reason);
 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index c05175822..2c3cf2601 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -9291,7 +9291,7 @@ static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s,
 	}
 
 	os_get_reltime(&now);
-	wpa_bss_update_scan_res(wpa_s, res, &now);
+	wpa_bss_update_scan_res(wpa_s, res, &now, 0);
 	ret = 0;
 fail:
 	os_free(res);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index c53474dae..8684d1c97 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -2509,7 +2509,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
 	wpa_bss_update_start(wpa_s);
 	for (i = 0; i < scan_res->num; i++)
 		wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
-					&scan_res->fetch_time);
+					&scan_res->fetch_time, 0);
 	wpa_bss_update_end(wpa_s, info, new_scan);
 
 	return scan_res;
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index c4c6651d4..c9ebcaca8 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -1354,7 +1354,7 @@ static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
 			scan_snr(res);
 			scan_est_throughput(wpa_s, res);
 			wpa_bss_update_scan_res(wpa_s, res,
-						&scan_res->fetch_time);
+						&scan_res->fetch_time, 0);
 		}
 	}
 
-- 
2.17.1

