Cumulative patch from commit ed0a4ddc22526361a138c6b145561fcaac24e2a5

ed0a4dd nl80211: Update drv->ssid on connect/associate event based on BSS data
9f346fa nl80211: Fix scan_state update in no pending scan state
34f7c69 Add multicast to unicast support
5f2c0a2 Sync with mac80211-next.git include/uapi/linux/nl80211.h
08032c7 Remove inactivity timeout for wired interfaces
57f93d6 Defer scans while PNO is in progress instead of skipping them
a1fce39 nl80211: Optimize memory use in nl80211_get_assoc_freq()
da2c284 nl80211: Reduce nl80211_dump_scan() memory need
b72a01b nl80211: Split bss_info_handler() into a separate parser function
cfadab2 nl80211: Move duplicate scan result removal to bss.c
2a1cf26 nl80211: Add more debug details to duplicate scan entry removal
865081c privsep: Support frequency list for scan requests
da818ee privsep: Support multiple scan SSIDs
002b504 privsep: Coding style cleanup for struct definitions
d3c43e5 privsep: Fix scan result fetching with Beacon frame IEs
0771e91 wpa_priv: Document reduced functionality
6d97561 wpa_priv: Handler driver global_deinit() on termination path
ce0f899 wpa_priv: Explicitly clear padding in message structures
e064177 wpa_priv: Use fromlen instead sizeof(struct sockaddr_un)
128d3c6 wpa_priv: Add support for multiple l2_packet connections
c8fef78 nl80211: Split nl80211_check_bss_status() into a separate function
e35e137 nl80211: Separate channel noise fetch from scan result processing
cb2b666 Fix 4addr reassociation-without-deauthentication on AP
8c0ed37 wired: Mark some common helper functions static
ba5ea11 mka: Remove references to macsec_qca from wpa_supplicant.conf
f014d9d macsec_linux: Add a driver for macsec on Linux kernels
8618313 drivers: Move driver_wired_get_ssid() to a common file
d27c42b drivers: Move driver_wired_get_bssid() to a common file
9281e5c drivers: Move driver_wired_get_capa() to a common file
ec9cfb9 drivers: Move driver_wired_deinit_common() to a common file
ed5ae61 drivers: Move driver_wired_init_common() to a common file
5a55ec3 drivers: Move driver_wired_get_ifstatus() to a common file
d718a5d drivers: Move driver_wired_set_ifflags() to a common file
567b7d4 drivers: Move driver_wired_get_ifflags() to a common file
693124a drivers: Move driver_wired_multi() to a common file
b0906ef drivers: Move wired_multicast_membership() to a common file
0abc8d1 drivers: Move common definitions for wired drivers out
bf88401 Add support to abort vendor scan
eeb34a4 nl80211: Enhance abort scan to also abort the vendor scan
1a793f5 Define a QCA vendor command to abort vendor scan
47d74bf Add MGMT_RX_PROCESS test command for hostapd
2ab0965 AP: Do not drop STA entry if PMF is used with full AP client state
209dad0 FT: Explicitly check for MDE not present in non-FT association
d4f3003 nl80211: Configure Beacon frame TX rate if driver advertises support
29483a5 Add support for user configurable Beacon frame data rate for AP mode
346b333 Use random MAC address for scanning only in non-connected state
18f1611 D-Bus: Send P2P IP address assignment info with GroupStarted event
046fa6f D-Bus: Add getter and setter for P2P IP address config parameters
d503eee FT: Complete CONFIG_IEEE80211R_AP renaming for hostapd
e0d9fd3 wpa_supplicant: Allow configuring the MACsec port for MKA
1d3d066 mka: Add enable_encrypt op and call it from CP state machine
7b4d546 wpa_supplicant: Add macsec_integ_only setting for MKA
008e224 mka: Disable peer detection timeout for PSK mode
ad51731 wpa_supplicant: Allow pre-shared (CAK,CKN) pair for MKA
5acbf22 Fix hostapd usage entry style for -T
611d67a Add doxygen ref to eap_method structure
88f93c3 Android: Remove BoringSSL guard
7824bf7 nl80211: Fix get_inact_sec() returning -1 on failure
088d53d mka: Fix getting capabilities from the driver
5e785a6 Reserve QCA vendor specific nl80211 command 144
4051dd8 GAS: Add Capability List ANQP-element support for Info ID 270, 280..299
d50f518 Fix libap.a build
e65a87b Debug print scan results matching the currently selected network
8d1e693 Use estimated throughput to avoid signal based roaming decision

Test: Wifi Suite

Change-Id: Ic470ffe9004d28d34916e50221d631ac99d4163f
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 1a25d08..31f017b 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1596,9 +1596,7 @@
 
 # With BoringSSL we need libkeystore-engine in order to provide access to
 # keystore keys.
-ifneq (,$(wildcard external/boringssl/flavor.mk))
 LOCAL_SHARED_LIBRARIES += libkeystore-engine
-endif
 
 ifdef CONFIG_DRIVER_NL80211
 ifneq ($(wildcard external/libnl),)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 11ab01a..54564f6 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -965,6 +965,17 @@
 also possible to run multiple wpa_priv processes at the same time, if
 desired.
 
+It should be noted that the interface used between wpa_supplicant and
+wpa_priv does not include all the capabilities of the wpa_supplicant
+driver interface and at times, this interface lacks update especially
+for recent addition. Consequently, use of wpa_priv does come with the
+price of somewhat reduced available functionality. The next section
+describing how wpa_supplicant can be used with reduced privileges
+without having to handle the complexity of separate wpa_priv. While that
+approve does not provide separation for network admin capabilities, it
+does allow other root privileges to be dropped without the drawbacks of
+the wpa_priv process.
+
 
 Linux capabilities instead of privileged process
 ------------------------------------------------
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 3a8778d..44a9a7b 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -595,6 +595,42 @@
 {
 	u32 changes;
 
+	if (bss->last_update_idx == wpa_s->bss_update_idx) {
+		struct os_reltime update_time;
+
+		/*
+		 * Some drivers (e.g., cfg80211) include multiple BSS entries
+		 * for the same BSS if that BSS's channel changes. The BSS list
+		 * implementation in wpa_supplicant does not do that and we need
+		 * to filter out the obsolete results here to make sure only the
+		 * most current BSS information remains in the table.
+		 */
+		wpa_printf(MSG_DEBUG, "BSS: " MACSTR
+			   " has multiple entries in the scan results - select the most current one",
+			   MAC2STR(bss->bssid));
+		calculate_update_time(fetch_time, res->age, &update_time);
+		wpa_printf(MSG_DEBUG,
+			   "Previous last_update: %u.%06u (freq %d%s)",
+			   (unsigned int) bss->last_update.sec,
+			   (unsigned int) bss->last_update.usec,
+			   bss->freq,
+			   (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
+		wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
+			   (unsigned int) update_time.sec,
+			   (unsigned int) update_time.usec,
+			   res->freq,
+			   (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
+		if ((bss->flags & WPA_BSS_ASSOCIATED) ||
+		    (!(res->flags & WPA_SCAN_ASSOCIATED) &&
+		     !os_reltime_before(&bss->last_update, &update_time))) {
+			wpa_printf(MSG_DEBUG,
+				   "Ignore this BSS entry since the previous update looks more current");
+			return bss;
+		}
+		wpa_printf(MSG_DEBUG,
+			   "Accept this BSS entry since it looks more current than the previous update");
+	}
+
 	changes = wpa_bss_compare_res(bss, res);
 	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
 		wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a0b64b2..2120a6e 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1828,6 +1828,69 @@
 #endif /* CONFIG_MESH */
 
 
+#ifdef CONFIG_MACSEC
+
+static int wpa_config_parse_mka_cak(const struct parse_data *data,
+				    struct wpa_ssid *ssid, int line,
+				    const char *value)
+{
+	if (hexstr2bin(value, ssid->mka_cak, MACSEC_CAK_LEN) ||
+	    value[MACSEC_CAK_LEN * 2] != '\0') {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
+			   line, value);
+		return -1;
+	}
+
+	ssid->mka_psk_set |= MKA_PSK_SET_CAK;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, MACSEC_CAK_LEN);
+	return 0;
+}
+
+
+static int wpa_config_parse_mka_ckn(const struct parse_data *data,
+				    struct wpa_ssid *ssid, int line,
+				    const char *value)
+{
+	if (hexstr2bin(value, ssid->mka_ckn, MACSEC_CKN_LEN) ||
+	    value[MACSEC_CKN_LEN * 2] != '\0') {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+			   line, value);
+		return -1;
+	}
+
+	ssid->mka_psk_set |= MKA_PSK_SET_CKN;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, MACSEC_CKN_LEN);
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mka_cak(const struct parse_data *data,
+				       struct wpa_ssid *ssid)
+{
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+		return NULL;
+
+	return wpa_config_write_string_hex(ssid->mka_cak, MACSEC_CAK_LEN);
+}
+
+
+static char * wpa_config_write_mka_ckn(const struct parse_data *data,
+				       struct wpa_ssid *ssid)
+{
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+		return NULL;
+	return wpa_config_write_string_hex(ssid->mka_ckn, MACSEC_CKN_LEN);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MACSEC */
+
+
 /* Helper macros for network block parser */
 
 #ifdef OFFSET
@@ -2062,6 +2125,10 @@
 	{ INT(beacon_int) },
 #ifdef CONFIG_MACSEC
 	{ INT_RANGE(macsec_policy, 0, 1) },
+	{ INT_RANGE(macsec_integ_only, 0, 1) },
+	{ INT_RANGE(macsec_port, 1, 65534) },
+	{ FUNC_KEY(mka_cak) },
+	{ FUNC_KEY(mka_ckn) },
 #endif /* CONFIG_MACSEC */
 #ifdef CONFIG_HS20
 	{ INT(update_identifier) },
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 7ae1654..2e3d57e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -662,6 +662,40 @@
 #endif /* CONFIG_P2P */
 
 
+#ifdef CONFIG_MACSEC
+
+static void write_mka_cak(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+		return;
+
+	value = wpa_config_get(ssid, "mka_cak");
+	if (!value)
+		return;
+	fprintf(f, "\tmka_cak=%s\n", value);
+	os_free(value);
+}
+
+
+static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+		return;
+
+	value = wpa_config_get(ssid, "mka_ckn");
+	if (!value)
+		return;
+	fprintf(f, "\tmka_ckn=%s\n", value);
+	os_free(value);
+}
+
+#endif /* CONFIG_MACSEC */
+
+
 static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
 {
 	int i;
@@ -772,6 +806,10 @@
 	INT(beacon_int);
 #ifdef CONFIG_MACSEC
 	INT(macsec_policy);
+	write_mka_cak(f, ssid);
+	write_mka_ckn(f, ssid);
+	INT(macsec_integ_only);
+	INT(macsec_port);
 #endif /* CONFIG_MACSEC */
 #ifdef CONFIG_HS20
 	INT(update_identifier);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 010b594..fe0f7fa 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -728,6 +728,47 @@
 	 *    determine whether to use a secure session or not.
 	 */
 	int macsec_policy;
+
+	/**
+	 * macsec_integ_only - Determines how MACsec are transmitted
+	 *
+	 * This setting applies only when MACsec is in use, i.e.,
+	 *  - macsec_policy is enabled
+	 *  - the key server has decided to enable MACsec
+	 *
+	 * 0: Encrypt traffic (default)
+	 * 1: Integrity only
+	 */
+	int macsec_integ_only;
+
+	/**
+	 * macsec_port - MACsec port (in SCI)
+	 *
+	 * Port component of the SCI.
+	 *
+	 * Range: 1-65534 (default: 1)
+	 */
+	int macsec_port;
+
+	/**
+	 * mka_ckn - MKA pre-shared CKN
+	 */
+#define MACSEC_CKN_LEN 32
+	u8 mka_ckn[MACSEC_CKN_LEN];
+
+	/**
+	 * mka_cak - MKA pre-shared CAK
+	 */
+#define MACSEC_CAK_LEN 16
+	u8 mka_cak[MACSEC_CAK_LEN];
+
+#define MKA_PSK_SET_CKN BIT(0)
+#define MKA_PSK_SET_CAK BIT(1)
+#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
+	/**
+	 * mka_psk_set - Whether mka_ckn and mka_cak are set
+	 */
+	u8 mka_psk_set;
 #endif /* CONFIG_MACSEC */
 
 #ifdef CONFIG_HS20
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 27b3012..69fb8f4 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1256,9 +1256,12 @@
  * @wpa_s: %wpa_supplicant network interface data
  * @client: this device is P2P client
  * @persistent: 0 - non persistent group, 1 - persistent group
+ * @ip: When group role is client, it contains local IP address, netmask, and
+ *	GO's IP address, if assigned; otherwise, NULL
  */
 void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-					int client, int persistent)
+					int client, int persistent,
+					const u8 *ip)
 {
 	DBusMessage *msg;
 	DBusMessageIter iter, dict_iter;
@@ -1300,6 +1303,13 @@
 	    !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
 	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
 					      wpa_s->dbus_groupobj_path) ||
+	    (ip &&
+	     (!wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddr",
+					       (char *) ip, 4) ||
+	      !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+					       (char *) ip + 4, 4) ||
+	      !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+					       (char *) ip + 8, 4))) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
 		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
 	} else {
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index d64fcee..2b0b775 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -190,7 +190,8 @@
 				     const u8 *src, u16 dev_passwd_id,
 				     u8 go_intent);
 void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-					int client, int persistent);
+					int client, int persistent,
+					const u8 *ip);
 void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
 						  const char *reason);
 void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
@@ -400,7 +401,8 @@
 
 static inline void
 wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-				   int client, int persistent)
+				   int client, int persistent,
+				   const u8 *ip)
 {
 }
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 73b9e20..f50420b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -28,6 +28,18 @@
 #include "../p2p_supplicant.h"
 #include "../wifi_display.h"
 
+
+static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
+{
+	if (entry.type != DBUS_TYPE_ARRAY ||
+	    entry.array_type != DBUS_TYPE_BYTE ||
+	    entry.array_len != 4)
+		return 0;
+
+	return 1;
+}
+
+
 /**
  * Parses out the mac address from the peer object path.
  * @peer_path - object path of the form
@@ -867,6 +879,35 @@
 			goto err_no_mem;
 	}
 
+	/* GO IP address */
+	if (WPA_GET_BE32(wpa_s->conf->ip_addr_go) &&
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+					     (char *) wpa_s->conf->ip_addr_go,
+					     4))
+		goto err_no_mem;
+
+	/* IP address mask */
+	if (WPA_GET_BE32(wpa_s->conf->ip_addr_mask) &&
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+					     (char *) wpa_s->conf->ip_addr_mask,
+					     4))
+		goto err_no_mem;
+
+	/* IP address start */
+	if (WPA_GET_BE32(wpa_s->conf->ip_addr_start) &&
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrStart",
+					     (char *)
+					     wpa_s->conf->ip_addr_start,
+					     4))
+		goto err_no_mem;
+
+	/* IP address end */
+	if (WPA_GET_BE32(wpa_s->conf->ip_addr_end) &&
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrEnd",
+					     (char *) wpa_s->conf->ip_addr_end,
+					     4))
+		goto err_no_mem;
+
 	/* Vendor Extensions */
 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
 		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
@@ -1051,6 +1092,26 @@
 			wpa_s->conf->p2p_intra_bss = entry.bool_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_INTRA_BSS;
+		} else if (os_strcmp(entry.key, "IpAddrGo") == 0) {
+			if (!wpas_dbus_validate_dbus_ipaddr(entry))
+				goto error;
+			os_memcpy(wpa_s->conf->ip_addr_go,
+				  entry.bytearray_value, 4);
+		} else if (os_strcmp(entry.key, "IpAddrMask") == 0) {
+			if (!wpas_dbus_validate_dbus_ipaddr(entry))
+				goto error;
+			os_memcpy(wpa_s->conf->ip_addr_mask,
+				  entry.bytearray_value, 4);
+		} else if (os_strcmp(entry.key, "IpAddrStart") == 0) {
+			if (!wpas_dbus_validate_dbus_ipaddr(entry))
+				goto error;
+			os_memcpy(wpa_s->conf->ip_addr_start,
+				  entry.bytearray_value, 4);
+		} else if (os_strcmp(entry.key, "IpAddrEnd") == 0) {
+			if (!wpas_dbus_validate_dbus_ipaddr(entry))
+				goto error;
+			os_memcpy(wpa_s->conf->ip_addr_end,
+				  entry.bytearray_value, 4);
 		} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
 			   entry.type == DBUS_TYPE_UINT32)
 			wpa_s->conf->p2p_group_idle = entry.uint32_value;
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index c9bb20d..4758c16 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -731,6 +731,14 @@
 	return wpa_s->driver->enable_protect_frames(wpa_s->drv_priv, enabled);
 }
 
+static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
+						Boolean enabled)
+{
+	if (!wpa_s->driver->enable_encrypt)
+		return -1;
+	return wpa_s->driver->enable_encrypt(wpa_s->drv_priv, enabled);
+}
+
 static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
 					     Boolean enabled, u32 window)
 {
@@ -908,11 +916,12 @@
 	return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq);
 }
 
-static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s)
+static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s,
+				     u64 scan_cookie)
 {
 	if (!wpa_s->driver->abort_scan)
 		return -1;
-	return wpa_s->driver->abort_scan(wpa_s->drv_priv);
+	return wpa_s->driver->abort_scan(wpa_s->drv_priv, scan_cookie);
 }
 
 static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 17f057a..67438e5 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -503,7 +503,7 @@
 
 static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
 					 struct wpa_ssid *ssid,
-					 struct wpa_bss *bss)
+					 struct wpa_bss *bss, int debug_print)
 {
 	struct wpa_ie_data ie;
 	int proto_match = 0;
@@ -526,40 +526,46 @@
 		proto_match++;
 
 		if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - parse "
-				"failed");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - parse failed");
 			break;
 		}
 
 		if (wep_ok &&
 		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
 		{
-			wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
-				"in RSN IE");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   selected based on TSN in RSN IE");
 			return 1;
 		}
 
 		if (!(ie.proto & ssid->proto)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - proto "
-				"mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - proto mismatch");
 			break;
 		}
 
 		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - PTK "
-				"cipher mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - PTK cipher mismatch");
 			break;
 		}
 
 		if (!(ie.group_cipher & ssid->group_cipher)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - GTK "
-				"cipher mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - GTK cipher mismatch");
 			break;
 		}
 
 		if (!(ie.key_mgmt & ssid->key_mgmt)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - key mgmt "
-				"mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - key mgmt mismatch");
 			break;
 		}
 
@@ -567,16 +573,18 @@
 		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
 		    wpas_get_ssid_pmf(wpa_s, ssid) ==
 		    MGMT_FRAME_PROTECTION_REQUIRED) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - no mgmt "
-				"frame protection");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - no mgmt frame protection");
 			break;
 		}
 #endif /* CONFIG_IEEE80211W */
 		if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
 		    wpas_get_ssid_pmf(wpa_s, ssid) ==
 		    NO_MGMT_FRAME_PROTECTION) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip RSN IE - no mgmt frame protection enabled but AP requires it");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - no mgmt frame protection enabled but AP requires it");
 			break;
 		}
 #ifdef CONFIG_MBO
@@ -584,20 +592,24 @@
 		    wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
 		    wpas_get_ssid_pmf(wpa_s, ssid) !=
 		    NO_MGMT_FRAME_PROTECTION) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip RSN IE - no mgmt frame protection enabled on MBO AP");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip RSN IE - no mgmt frame protection enabled on MBO AP");
 			break;
 		}
 #endif /* CONFIG_MBO */
 
-		wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on RSN IE");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   selected based on RSN IE");
 		return 1;
 	}
 
 #ifdef CONFIG_IEEE80211W
 	if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
-		wpa_dbg(wpa_s, MSG_DEBUG,
-			"   skip - MFP Required but network not MFP Capable");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - MFP Required but network not MFP Capable");
 		return 0;
 	}
 #endif /* CONFIG_IEEE80211W */
@@ -607,72 +619,87 @@
 		proto_match++;
 
 		if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - parse "
-				"failed");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip WPA IE - parse failed");
 			break;
 		}
 
 		if (wep_ok &&
 		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
 		{
-			wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
-				"in WPA IE");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   selected based on TSN in WPA IE");
 			return 1;
 		}
 
 		if (!(ie.proto & ssid->proto)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - proto "
-				"mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip WPA IE - proto mismatch");
 			break;
 		}
 
 		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - PTK "
-				"cipher mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip WPA IE - PTK cipher mismatch");
 			break;
 		}
 
 		if (!(ie.group_cipher & ssid->group_cipher)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - GTK "
-				"cipher mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip WPA IE - GTK cipher mismatch");
 			break;
 		}
 
 		if (!(ie.key_mgmt & ssid->key_mgmt)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - key mgmt "
-				"mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip WPA IE - key mgmt mismatch");
 			break;
 		}
 
-		wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on WPA IE");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   selected based on WPA IE");
 		return 1;
 	}
 
 	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
 	    !rsn_ie) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "   allow for non-WPA IEEE 802.1X");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   allow for non-WPA IEEE 802.1X");
 		return 1;
 	}
 
 	if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
 	    wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no WPA/RSN proto match");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - no WPA/RSN proto match");
 		return 0;
 	}
 
 	if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) &&
 	    wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "   allow in OSEN");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   allow in OSEN");
 		return 1;
 	}
 
 	if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "   allow in non-WPA/WPA2");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   allow in non-WPA/WPA2");
 		return 1;
 	}
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "   reject due to mismatch with "
-		"WPA/WPA2");
+	if (debug_print)
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"   reject due to mismatch with WPA/WPA2");
 
 	return 0;
 }
@@ -692,7 +719,8 @@
 }
 
 
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+		      int debug_print)
 {
 	const struct hostapd_hw_modes *mode = NULL, *modes;
 	const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -749,9 +777,9 @@
 			if (flagged && ((rate_ie[j] & 0x7f) ==
 					BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
 				if (!ht_supported(mode)) {
-					wpa_dbg(wpa_s, MSG_DEBUG,
-						"   hardware does not support "
-						"HT PHY");
+					if (debug_print)
+						wpa_dbg(wpa_s, MSG_DEBUG,
+							"   hardware does not support HT PHY");
 					return 0;
 				}
 				continue;
@@ -761,9 +789,9 @@
 			if (flagged && ((rate_ie[j] & 0x7f) ==
 					BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) {
 				if (!vht_supported(mode)) {
-					wpa_dbg(wpa_s, MSG_DEBUG,
-						"   hardware does not support "
-						"VHT PHY");
+					if (debug_print)
+						wpa_dbg(wpa_s, MSG_DEBUG,
+							"   hardware does not support VHT PHY");
 					return 0;
 				}
 				continue;
@@ -783,10 +811,11 @@
 				 * order to join a BSS all required rates
 				 * have to be supported by the hardware.
 				 */
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
-					r / 10, r % 10,
-					bss->freq, mode->mode, mode->num_rates);
+				if (debug_print)
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
+						r / 10, r % 10,
+						bss->freq, mode->mode, mode->num_rates);
 				return 0;
 			}
 		}
@@ -842,7 +871,7 @@
 struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 				     int i, struct wpa_bss *bss,
 				     struct wpa_ssid *group,
-				     int only_first_ssid)
+				     int only_first_ssid, int debug_print)
 {
 	u8 wpa_ie_len, rsn_ie_len;
 	int wpa;
@@ -863,15 +892,20 @@
 	ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
 	osen = ie != NULL;
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-		"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
-		i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
-		wpa_ie_len, rsn_ie_len, bss->caps, bss->level, bss->freq,
-		wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "",
-		(wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
-		 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ?
-		" p2p" : "",
-		osen ? " osen=1" : "");
+	if (debug_print) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR
+			" ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
+			i, MAC2STR(bss->bssid),
+			wpa_ssid_txt(bss->ssid, bss->ssid_len),
+			wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
+			bss->freq,
+			wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ?
+			" wps" : "",
+			(wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+			 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE))
+			? " p2p" : "",
+			osen ? " osen=1" : "");
+	}
 
 	e = wpa_blacklist_get(wpa_s, bss->bssid);
 	if (e) {
@@ -888,24 +922,30 @@
 			limit = 0;
 		}
 		if (e->count > limit) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
-				"(count=%d limit=%d)", e->count, limit);
+			if (debug_print) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - blacklisted (count=%d limit=%d)",
+					e->count, limit);
+			}
 			return NULL;
 		}
 	}
 
 	if (bss->ssid_len == 0) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID not known");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID not known");
 		return NULL;
 	}
 
 	if (disallowed_bssid(wpa_s, bss->bssid)) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID disallowed");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID disallowed");
 		return NULL;
 	}
 
 	if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID disallowed");
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID disallowed");
 		return NULL;
 	}
 
@@ -916,21 +956,25 @@
 		int res;
 
 		if (wpas_network_disabled(wpa_s, ssid)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
 			continue;
 		}
 
 		res = wpas_temp_disabled(wpa_s, ssid);
 		if (res > 0) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled "
-				"temporarily for %d second(s)", res);
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - disabled temporarily for %d second(s)",
+					res);
 			continue;
 		}
 
 #ifdef CONFIG_WPS
 		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
-				"(WPS)");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - blacklisted (WPS)");
 			continue;
 		}
 
@@ -956,13 +1000,17 @@
 		if (check_ssid &&
 		    (bss->ssid_len != ssid->ssid_len ||
 		     os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - SSID mismatch");
 			continue;
 		}
 
 		if (ssid->bssid_set &&
 		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - BSSID mismatch");
 			continue;
 		}
 
@@ -970,8 +1018,9 @@
 		if (ssid->num_bssid_blacklist &&
 		    addr_in_list(bss->bssid, ssid->bssid_blacklist,
 				 ssid->num_bssid_blacklist)) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - BSSID blacklisted");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - BSSID blacklisted");
 			continue;
 		}
 
@@ -979,71 +1028,85 @@
 		if (ssid->num_bssid_whitelist &&
 		    !addr_in_list(bss->bssid, ssid->bssid_whitelist,
 				  ssid->num_bssid_whitelist)) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - BSSID not in whitelist");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - BSSID not in whitelist");
 			continue;
 		}
 
-		if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
+		if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
+						   debug_print))
 			continue;
 
 		if (!osen && !wpa &&
 		    !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
 		    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
 		    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - non-WPA network "
-				"not allowed");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - non-WPA network not allowed");
 			continue;
 		}
 
 		if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
 		    has_wep_key(ssid)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - ignore WPA/WPA2 AP for WEP network block");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - ignore WPA/WPA2 AP for WEP network block");
 			continue;
 		}
 
 		if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - non-OSEN network "
-				"not allowed");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - non-OSEN network not allowed");
 			continue;
 		}
 
 		if (!wpa_supplicant_match_privacy(bss, ssid)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - privacy "
-				"mismatch");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - privacy mismatch");
 			continue;
 		}
 
 		if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
 		    !bss_is_pbss(bss)) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - not ESS, PBSS, or MBSS");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - not ESS, PBSS, or MBSS");
 			continue;
 		}
 
 		if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - PBSS mismatch (ssid %d bss %d)",
-				ssid->pbss, bss_is_pbss(bss));
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - PBSS mismatch (ssid %d bss %d)",
+					ssid->pbss, bss_is_pbss(bss));
 			continue;
 		}
 
 		if (!freq_allowed(ssid->freq_list, bss->freq)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - frequency not "
-				"allowed");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - frequency not allowed");
 			continue;
 		}
 
 #ifdef CONFIG_MESH
 		if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
 		    ssid->frequency != bss->freq) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - frequency not allowed (mesh)");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - frequency not allowed (mesh)");
 			continue;
 		}
 #endif /* CONFIG_MESH */
 
-		if (!rate_match(wpa_s, bss)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - rate sets do "
-				"not match");
+		if (!rate_match(wpa_s, bss, debug_print)) {
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - rate sets do not match");
 			continue;
 		}
 
@@ -1051,8 +1114,9 @@
 		if (ssid->mode == WPAS_MODE_IBSS &&
 		    !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
 					WPA_KEY_MGMT_WPA_NONE))) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - IBSS RSN not supported in the build");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - IBSS RSN not supported in the build");
 			continue;
 		}
 #endif /* !CONFIG_IBSS_RSN */
@@ -1061,7 +1125,9 @@
 		if (ssid->p2p_group &&
 		    !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
 		    !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no P2P IE seen");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - no P2P IE seen");
 			continue;
 		}
 
@@ -1071,20 +1137,26 @@
 
 			ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
 			if (ie == NULL) {
-				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no P2P element");
+				if (debug_print)
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   skip - no P2P element");
 				continue;
 			}
 			p2p_ie = wpa_bss_get_vendor_ie_multi(
 				bss, P2P_IE_VENDOR_TYPE);
 			if (p2p_ie == NULL) {
-				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - could not fetch P2P element");
+				if (debug_print)
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   skip - could not fetch P2P element");
 				continue;
 			}
 
 			if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
 			    || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
 					 ETH_ALEN) != 0) {
-				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no matching GO P2P Device Address in P2P element");
+				if (debug_print)
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   skip - no matching GO P2P Device Address in P2P element");
 				wpabuf_free(p2p_ie);
 				continue;
 			}
@@ -1104,8 +1176,9 @@
 
 			os_reltime_sub(&wpa_s->scan_min_time,
 				       &bss->last_update, &diff);
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - scan result not recent enough (%u.%06u seconds too old)",
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - scan result not recent enough (%u.%06u seconds too old)",
 				(unsigned int) diff.sec,
 				(unsigned int) diff.usec);
 			continue;
@@ -1118,15 +1191,17 @@
 		assoc_disallow = wpas_mbo_get_bss_attr(
 			bss, MBO_ATTR_ID_ASSOC_DISALLOW);
 		if (assoc_disallow && assoc_disallow[1] >= 1) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - MBO association disallowed (reason %u)",
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - MBO association disallowed (reason %u)",
 				assoc_disallow[2]);
 			continue;
 		}
 
 		if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - MBO retry delay has not passed yet");
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - MBO retry delay has not passed yet");
 			continue;
 		}
 #ifdef CONFIG_TESTING_OPTIONS
@@ -1151,6 +1226,25 @@
 {
 	unsigned int i;
 
+	if (wpa_s->current_ssid) {
+		struct wpa_ssid *ssid;
+
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Scan results matching the currently selected network");
+		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+			struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+			ssid = wpa_scan_res_match(wpa_s, i, bss, group,
+						  only_first_ssid, 0);
+			if (ssid != wpa_s->current_ssid)
+				continue;
+			wpa_dbg(wpa_s, MSG_DEBUG, "%u: " MACSTR
+				" freq=%d level=%d snr=%d est_throughput=%u",
+				i, MAC2STR(bss->bssid), bss->freq, bss->level,
+				bss->snr, bss->est_throughput);
+		}
+	}
+
 	if (only_first_ssid)
 		wpa_dbg(wpa_s, MSG_DEBUG, "Try to find BSS matching pre-selected network id=%d",
 			group->id);
@@ -1161,7 +1255,7 @@
 	for (i = 0; i < wpa_s->last_scan_res_used; i++) {
 		struct wpa_bss *bss = wpa_s->last_scan_res[i];
 		*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
-						    only_first_ssid);
+						    only_first_ssid, 1);
 		if (!*selected_ssid)
 			continue;
 		wpa_dbg(wpa_s, MSG_DEBUG, "   selected BSS " MACSTR
@@ -1396,8 +1490,9 @@
 {
 	struct wpa_bss *current_bss = NULL;
 #ifndef CONFIG_NO_ROAMING
-	int min_diff;
+	int min_diff, diff;
 	int to_5ghz;
+	int cur_est, sel_est;
 #endif /* CONFIG_NO_ROAMING */
 
 	if (wpa_s->reassociate)
@@ -1431,12 +1526,13 @@
 #ifndef CONFIG_NO_ROAMING
 	wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
 	wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
-		" level=%d snr=%d est_throughput=%u",
-		MAC2STR(current_bss->bssid), current_bss->level,
+		" freq=%d level=%d snr=%d est_throughput=%u",
+		MAC2STR(current_bss->bssid),
+		current_bss->freq, current_bss->level,
 		current_bss->snr, current_bss->est_throughput);
 	wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR
-		" level=%d snr=%d est_throughput=%u",
-		MAC2STR(selected->bssid), selected->level,
+		" freq=%d level=%d snr=%d est_throughput=%u",
+		MAC2STR(selected->bssid), selected->freq, selected->level,
 		selected->snr, selected->est_throughput);
 
 	if (wpa_s->current_ssid->bssid_set &&
@@ -1462,6 +1558,14 @@
 		return 0;
 	}
 
+	if (current_bss->est_throughput > selected->est_throughput + 5000) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Skip roam - Current BSS has better estimated throughput");
+		return 1;
+	}
+
+	cur_est = current_bss->est_throughput;
+	sel_est = selected->est_throughput;
 	min_diff = 2;
 	if (current_bss->level < 0) {
 		if (current_bss->level < -85)
@@ -1474,20 +1578,42 @@
 			min_diff = 4;
 		else
 			min_diff = 5;
+		if (cur_est > sel_est * 1.5)
+			min_diff += 10;
+		else if (cur_est > sel_est * 1.2)
+			min_diff += 5;
+		else if (cur_est > sel_est * 1.1)
+			min_diff += 2;
+		else if (cur_est > sel_est)
+			min_diff++;
 	}
 	if (to_5ghz) {
+		int reduce = 2;
+
 		/* Make it easier to move to 5 GHz band */
-		if (min_diff > 2)
-			min_diff -= 2;
+		if (sel_est > cur_est * 1.5)
+			reduce = 5;
+		else if (sel_est > cur_est * 1.2)
+			reduce = 4;
+		else if (sel_est > cur_est * 1.1)
+			reduce = 3;
+
+		if (min_diff > reduce)
+			min_diff -= reduce;
 		else
 			min_diff = 0;
 	}
-	if (abs(current_bss->level - selected->level) < min_diff) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
-			"in signal level");
+	diff = abs(current_bss->level - selected->level);
+	if (diff < min_diff) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Skip roam - too small difference in signal level (%d < %d)",
+			diff, min_diff);
 		return 0;
 	}
 
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Allow reassociation due to difference in signal level (%d >= %d)",
+		diff, min_diff);
 	return 1;
 #else /* CONFIG_NO_ROAMING */
 	return 0;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 6627b90..ba96548 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -682,12 +682,12 @@
 
 void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
 				   struct wpa_ssid *ssid, int persistent,
-				   int client)
+				   int client, const u8 *ip)
 {
 	/* Notify a group has been started */
 	wpas_dbus_register_p2p_group(wpa_s, ssid);
 
-	wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent);
+	wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent, ip);
 }
 
 
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 8cce0f3..e4d7fbf 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -114,7 +114,7 @@
 					 unsigned int generated_pin);
 void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
 				   struct wpa_ssid *ssid, int persistent,
-				   int client);
+				   int client, const u8 *ip);
 void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
 					     const char *reason);
 void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 6465e2f..2da92bf 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -308,6 +308,8 @@
 	}
 
 	ret = wpa_drv_scan(wpa_s, params);
+	if (ret == 0)
+		wpa_s->curr_scan_cookie = params->scan_cookie;
 	wpa_scan_free_params(params);
 	work->ctx = NULL;
 	if (ret) {
@@ -1383,7 +1385,7 @@
 	}
 
 	if (!client) {
-		wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0);
+		wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0, NULL);
 		os_get_reltime(&wpa_s->global->p2p_go_wait_client);
 	}
 }
@@ -1801,7 +1803,8 @@
 		}
 
 		wpas_notify_p2p_group_started(wpa_s, ssid,
-					      params->persistent_group, 0);
+					      params->persistent_group, 0,
+					      NULL);
 		wpas_p2p_cross_connect_setup(wpa_s);
 		wpas_p2p_set_group_idle_timeout(wpa_s);
 
@@ -7007,7 +7010,7 @@
 		wpas_p2p_store_persistent_group(wpa_s->p2pdev,
 						ssid, go_dev_addr);
 
-	wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1);
+	wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip);
 }
 
 
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 172772d..272e633 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -176,6 +176,17 @@
 		params->only_new_results = 1;
 	}
 	ret = wpa_drv_scan(wpa_s, params);
+	/*
+	 * Store the obtained vendor scan cookie (if any) in wpa_s context.
+	 * The current design is to allow only one scan request on each
+	 * interface, hence having this scan cookie stored in wpa_s context is
+	 * fine for now.
+	 *
+	 * Revisit this logic if concurrent scan operations per interface
+	 * is supported.
+	 */
+	if (ret == 0)
+		wpa_s->curr_scan_cookie = params->scan_cookie;
 	wpa_scan_free_params(params);
 	work->ctx = NULL;
 	if (ret) {
@@ -703,11 +714,6 @@
 	size_t max_ssids;
 	int connect_without_scan = 0;
 
-	if (wpa_s->pno || wpa_s->pno_sched_pending) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
-		return;
-	}
-
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
 		return;
@@ -768,6 +774,21 @@
 		return;
 	}
 
+	/*
+	 * Don't cancel the scan based on ongoing PNO; defer it. Some scans are
+	 * used for changing modes inside wpa_supplicant (roaming,
+	 * auto-reconnect, etc). Discarding the scan might hurt these processes.
+	 * The normal use case for PNO is to suspend the host immediately after
+	 * starting PNO, so the periodic 100 ms attempts to run the scan do not
+	 * normally happen in practice multiple times, i.e., this is simply
+	 * restarting scanning once the host is woken up and PNO stopped.
+	 */
+	if (wpa_s->pno || wpa_s->pno_sched_pending) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress");
+		wpa_supplicant_req_scan(wpa_s, 0, 100000);
+		return;
+	}
+
 	if (wpa_s->conf->ap_scan == 2)
 		max_ssids = 1;
 	else {
@@ -1047,7 +1068,8 @@
 	}
 #endif /* CONFIG_P2P */
 
-	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+	    wpa_s->wpa_state <= WPA_SCANNING) {
 		params.mac_addr_rand = 1;
 		if (wpa_s->mac_addr_scan) {
 			params.mac_addr = wpa_s->mac_addr_scan;
@@ -1469,7 +1491,8 @@
 
 	wpa_setband_scan_freqs(wpa_s, scan_params);
 
-	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
+	    wpa_s->wpa_state <= WPA_SCANNING) {
 		params.mac_addr_rand = 1;
 		if (wpa_s->mac_addr_sched_scan) {
 			params.mac_addr = wpa_s->mac_addr_sched_scan;
@@ -2524,7 +2547,8 @@
 		params.freqs = wpa_s->manual_sched_scan_freqs;
 	}
 
-	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) {
+	if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
+	    wpa_s->wpa_state <= WPA_SCANNING) {
 		params.mac_addr_rand = 1;
 		if (wpa_s->mac_addr_pno) {
 			params.mac_addr = wpa_s->mac_addr_pno;
@@ -2622,18 +2646,20 @@
 
 int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
 {
-	int scan_work = !!wpa_s->scan_work;
+	struct wpa_radio_work *work;
+	struct wpa_radio *radio = wpa_s->radio;
 
-#ifdef CONFIG_P2P
-	scan_work |= !!wpa_s->p2p_scan_work;
-#endif /* CONFIG_P2P */
-
-	if (scan_work && wpa_s->own_scan_running) {
+	dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+		if (work->wpa_s != wpa_s || !work->started ||
+		    (os_strcmp(work->type, "scan") != 0 &&
+		     os_strcmp(work->type, "p2p-scan") != 0))
+			continue;
 		wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
-		return wpa_drv_abort_scan(wpa_s);
+		return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie);
 	}
 
-	return 0;
+	wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort");
+	return -1;
 }
 
 
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 1b3409c..0b1a2db 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -562,7 +562,7 @@
 
 		if (wpa_s->current_ssid &&
 		    !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
-					1)) {
+					1, 0)) {
 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
 				   " (pref %d) does not match the current network profile",
 				   MAC2STR(nei->bssid),
@@ -756,7 +756,7 @@
 		struct wpa_bss *bss = wpa_s->last_scan_res[i];
 		int res;
 
-		if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
+		if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) {
 			res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
 			if (res == -2)
 				continue; /* could not build entry for BSS */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 4877989..f11028a 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1390,6 +1390,8 @@
 	"ap_max_inactivity", "dtim_period", "beacon_int",
 #ifdef CONFIG_MACSEC
 	"macsec_policy",
+	"macsec_integ_only",
+	"macsec_port",
 #endif /* CONFIG_MACSEC */
 #ifdef CONFIG_HS20
 	"update_identifier",
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index b36d195..9b81fc1 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -21,6 +21,7 @@
 #include "common/privsep_commands.h"
 #include "common/ieee802_11_defs.h"
 
+#define WPA_PRIV_MAX_L2 3
 
 struct wpa_priv_interface {
 	struct wpa_priv_interface *next;
@@ -35,11 +36,16 @@
 	void *drv_priv;
 	void *drv_global_priv;
 	struct sockaddr_un drv_addr;
+	socklen_t drv_addr_len;
 	int wpas_registered;
 
-	/* TODO: add support for multiple l2 connections */
-	struct l2_packet_data *l2;
-	struct sockaddr_un l2_addr;
+	struct l2_packet_data *l2[WPA_PRIV_MAX_L2];
+	struct sockaddr_un l2_addr[WPA_PRIV_MAX_L2];
+	socklen_t l2_addr_len[WPA_PRIV_MAX_L2];
+	struct wpa_priv_l2 {
+		struct wpa_priv_interface *parent;
+		int idx;
+	} l2_ctx[WPA_PRIV_MAX_L2];
 };
 
 struct wpa_priv_global {
@@ -48,8 +54,10 @@
 
 
 static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
-				  struct sockaddr_un *from)
+				  struct sockaddr_un *from, socklen_t fromlen)
 {
+	int i;
+
 	if (iface->drv_priv) {
 		wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
 		if (iface->driver->deinit)
@@ -62,11 +70,13 @@
 		iface->wpas_registered = 0;
 	}
 
-	if (iface->l2) {
-		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
-			   "instance");
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
+	for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+		if (iface->l2[i]) {
+			wpa_printf(MSG_DEBUG,
+				   "Cleaning up forgotten l2_packet instance");
+			l2_packet_deinit(iface->l2[i]);
+			iface->l2[i] = NULL;
+		}
 	}
 
 	if (iface->driver->init2) {
@@ -96,7 +106,8 @@
 	wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
 		   "'%s'", iface->driver_name, iface->ifname);
 
-	os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr));
+	os_memcpy(&iface->drv_addr, from, fromlen);
+	iface->drv_addr_len = fromlen;
 	iface->wpas_registered = 1;
 
 	if (iface->driver->set_param &&
@@ -123,18 +134,43 @@
 
 
 static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
-			      char *buf, size_t len)
+			      void *buf, size_t len)
 {
 	struct wpa_driver_scan_params params;
+	struct privsep_cmd_scan *scan;
+	unsigned int i;
+	int freqs[PRIVSEP_MAX_SCAN_FREQS + 1];
 
 	if (iface->drv_priv == NULL)
 		return;
 
+	if (len < sizeof(*scan)) {
+		wpa_printf(MSG_DEBUG, "Invalid scan request");
+		return;
+	}
+
+	scan = buf;
+
 	os_memset(&params, 0, sizeof(params));
-	if (len) {
-		params.ssids[0].ssid = (u8 *) buf;
-		params.ssids[0].ssid_len = len;
-		params.num_ssids = 1;
+	if (scan->num_ssids > WPAS_MAX_SCAN_SSIDS) {
+		wpa_printf(MSG_DEBUG, "Invalid scan request (num_ssids)");
+		return;
+	}
+	params.num_ssids = scan->num_ssids;
+	for (i = 0; i < scan->num_ssids; i++) {
+		params.ssids[i].ssid = scan->ssids[i];
+		params.ssids[i].ssid_len = scan->ssid_lens[i];
+	}
+
+	if (scan->num_freqs > PRIVSEP_MAX_SCAN_FREQS) {
+		wpa_printf(MSG_DEBUG, "Invalid scan request (num_freqs)");
+		return;
+	}
+	if (scan->num_freqs) {
+		for (i = 0; i < scan->num_freqs; i++)
+			freqs[i] = scan->freqs[i];
+		freqs[i] = 0;
+		params.freqs = freqs;
 	}
 
 	if (iface->driver->scan2)
@@ -143,7 +179,8 @@
 
 
 static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
-				       struct sockaddr_un *from)
+				       struct sockaddr_un *from,
+				       socklen_t fromlen)
 {
 	struct wpa_scan_results *res;
 	u8 *buf = NULL, *pos, *end;
@@ -165,7 +202,7 @@
 
 	for (i = 0; i < res->num; i++) {
 		struct wpa_scan_res *r = res->res[i];
-		val = sizeof(*r) + r->ie_len;
+		val = sizeof(*r) + r->ie_len + r->beacon_ie_len;
 		if (end - pos < (int) sizeof(int) + val)
 			break;
 		os_memcpy(pos, &val, sizeof(int));
@@ -174,8 +211,7 @@
 		pos += val;
 	}
 
-	sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
-	       sizeof(*from));
+	sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, fromlen);
 
 	os_free(buf);
 	wpa_scan_results_free(res);
@@ -184,21 +220,21 @@
 fail:
 	os_free(buf);
 	wpa_scan_results_free(res);
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
 }
 
 
 static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
-					  struct sockaddr_un *from)
+					  struct sockaddr_un *from,
+					  socklen_t fromlen)
 {
 	if (iface->drv_priv == NULL)
 		return;
 
 	if (iface->driver->get_scan_results2)
-		wpa_priv_get_scan_results2(iface, from);
+		wpa_priv_get_scan_results2(iface, from, fromlen);
 	else
-		sendto(iface->fd, "", 0, 0, (struct sockaddr *) from,
-		       sizeof(*from));
+		sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
 }
 
 
@@ -303,7 +339,7 @@
 
 
 static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
-				   struct sockaddr_un *from)
+				   struct sockaddr_un *from, socklen_t fromlen)
 {
 	u8 bssid[ETH_ALEN];
 
@@ -315,16 +351,16 @@
 		goto fail;
 
 	sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
-	       sizeof(*from));
+	       fromlen);
 	return;
 
 fail:
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
 }
 
 
 static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
-				  struct sockaddr_un *from)
+				  struct sockaddr_un *from, socklen_t fromlen)
 {
 	u8 ssid[sizeof(int) + SSID_MAX_LEN];
 	int res;
@@ -335,17 +371,18 @@
 	if (iface->driver->get_ssid == NULL)
 		goto fail;
 
+	os_memset(ssid, 0, sizeof(ssid));
 	res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
 	if (res < 0 || res > SSID_MAX_LEN)
 		goto fail;
 	os_memcpy(ssid, &res, sizeof(int));
 
 	sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from,
-	       sizeof(*from));
+	       fromlen);
 	return;
 
 fail:
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
 }
 
 
@@ -378,7 +415,7 @@
 
 
 static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
-				  struct sockaddr_un *from)
+				  struct sockaddr_un *from, socklen_t fromlen)
 {
 	struct wpa_driver_capa capa;
 
@@ -394,18 +431,19 @@
 	capa.extended_capa_mask = NULL;
 	capa.extended_capa_len = 0;
 	sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
-	       sizeof(*from));
+	       fromlen);
 	return;
 
 fail:
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
 }
 
 
 static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
 			   size_t len)
 {
-	struct wpa_priv_interface *iface = ctx;
+	struct wpa_priv_l2 *l2_ctx = ctx;
+	struct wpa_priv_interface *iface = l2_ctx->parent;
 	struct msghdr msg;
 	struct iovec io[2];
 
@@ -417,8 +455,8 @@
 	os_memset(&msg, 0, sizeof(msg));
 	msg.msg_iov = io;
 	msg.msg_iovlen = 2;
-	msg.msg_name = &iface->l2_addr;
-	msg.msg_namelen = sizeof(iface->l2_addr);
+	msg.msg_name = &iface->l2_addr[l2_ctx->idx];
+	msg.msg_namelen = iface->l2_addr_len[l2_ctx->idx];
 
 	if (sendmsg(iface->fd, &msg, 0) < 0) {
 		wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
@@ -426,14 +464,23 @@
 }
 
 
+static int wpa_priv_allowed_l2_proto(u16 proto)
+{
+	return proto == ETH_P_EAPOL || proto == ETH_P_RSN_PREAUTH ||
+		proto == ETH_P_80211_ENCAP;
+}
+
+
 static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
 				     struct sockaddr_un *from,
+				     socklen_t fromlen,
 				     void *buf, size_t len)
 {
 	int *reg_cmd = buf;
 	u8 own_addr[ETH_ALEN];
 	int res;
 	u16 proto;
+	int idx;
 
 	if (len != 2 * sizeof(int)) {
 		wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
@@ -442,50 +489,69 @@
 	}
 
 	proto = reg_cmd[0];
-	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH &&
-	    proto != ETH_P_80211_ENCAP) {
+	if (!wpa_priv_allowed_l2_proto(proto)) {
 		wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
 			   "ethertype 0x%x", proto);
 		return;
 	}
 
-	if (iface->l2) {
-		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
-			   "instance");
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
+	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+		if (!iface->l2[idx])
+			break;
+	}
+	if (idx == WPA_PRIV_MAX_L2) {
+		wpa_printf(MSG_DEBUG, "No free l2_packet connection found");
+		return;
 	}
 
-	os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr));
+	os_memcpy(&iface->l2_addr[idx], from, fromlen);
+	iface->l2_addr_len[idx] = fromlen;
 
-	iface->l2 = l2_packet_init(iface->ifname, NULL, proto,
-				   wpa_priv_l2_rx, iface, reg_cmd[1]);
-	if (iface->l2 == NULL) {
+	iface->l2_ctx[idx].idx = idx;
+	iface->l2_ctx[idx].parent = iface;
+	iface->l2[idx] = l2_packet_init(iface->ifname, NULL, proto,
+					wpa_priv_l2_rx, &iface->l2_ctx[idx],
+					reg_cmd[1]);
+	if (!iface->l2[idx]) {
 		wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
 			   "instance for protocol %d", proto);
 		return;
 	}
 
-	if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) {
+	if (l2_packet_get_own_addr(iface->l2[idx], own_addr) < 0) {
 		wpa_printf(MSG_DEBUG, "Failed to get own address from "
 			   "l2_packet");
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
+		l2_packet_deinit(iface->l2[idx]);
+		iface->l2[idx] = NULL;
 		return;
 	}
 
 	res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
-		     (struct sockaddr *) from, sizeof(*from));
-	wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res);
+		     (struct sockaddr *) from, fromlen);
+	wpa_printf(MSG_DEBUG, "L2 registration[idx=%d]: res=%d", idx, res);
 }
 
 
 static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
-				       struct sockaddr_un *from)
+				       struct sockaddr_un *from,
+				       socklen_t fromlen)
 {
-	if (iface->l2) {
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
+	int idx;
+
+	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+		if (iface->l2_addr_len[idx] == fromlen &&
+		    os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+			break;
+	}
+	if (idx == WPA_PRIV_MAX_L2) {
+		wpa_printf(MSG_DEBUG,
+			   "No registered l2_packet socket found for unregister request");
+		return;
+	}
+
+	if (iface->l2[idx]) {
+		l2_packet_deinit(iface->l2[idx]);
+		iface->l2[idx] = NULL;
 	}
 }
 
@@ -493,20 +559,36 @@
 static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
 					      struct sockaddr_un *from)
 {
-	if (iface->l2)
-		l2_packet_notify_auth_start(iface->l2);
+	int idx;
+
+	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+		if (iface->l2[idx])
+			l2_packet_notify_auth_start(iface->l2[idx]);
+	}
 }
 
 
 static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
-				 struct sockaddr_un *from,
+				 struct sockaddr_un *from, socklen_t fromlen,
 				 void *buf, size_t len)
 {
 	u8 *dst_addr;
 	u16 proto;
 	int res;
+	int idx;
 
-	if (iface->l2 == NULL)
+	for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+		if (iface->l2_addr_len[idx] == fromlen &&
+		    os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+			break;
+	}
+	if (idx == WPA_PRIV_MAX_L2) {
+		wpa_printf(MSG_DEBUG,
+			   "No registered l2_packet socket found for send request");
+		return;
+	}
+
+	if (iface->l2[idx] == NULL)
 		return;
 
 	if (len < ETH_ALEN + 2) {
@@ -518,15 +600,15 @@
 	dst_addr = buf;
 	os_memcpy(&proto, buf + ETH_ALEN, 2);
 
-	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
+	if (!wpa_priv_allowed_l2_proto(proto)) {
 		wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
 			   "0x%x", proto);
 		return;
 	}
 
-	res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2,
-			     len - ETH_ALEN - 2);
-	wpa_printf(MSG_DEBUG, "L2 send: res=%d", res);
+	res = l2_packet_send(iface->l2[idx], dst_addr, proto,
+			     buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+	wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
 }
 
 
@@ -571,7 +653,7 @@
 
 	switch (cmd) {
 	case PRIVSEP_CMD_REGISTER:
-		wpa_priv_cmd_register(iface, &from);
+		wpa_priv_cmd_register(iface, &from, fromlen);
 		break;
 	case PRIVSEP_CMD_UNREGISTER:
 		wpa_priv_cmd_unregister(iface, &from);
@@ -580,34 +662,35 @@
 		wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
 		break;
 	case PRIVSEP_CMD_GET_SCAN_RESULTS:
-		wpa_priv_cmd_get_scan_results(iface, &from);
+		wpa_priv_cmd_get_scan_results(iface, &from, fromlen);
 		break;
 	case PRIVSEP_CMD_ASSOCIATE:
 		wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
 		break;
 	case PRIVSEP_CMD_GET_BSSID:
-		wpa_priv_cmd_get_bssid(iface, &from);
+		wpa_priv_cmd_get_bssid(iface, &from, fromlen);
 		break;
 	case PRIVSEP_CMD_GET_SSID:
-		wpa_priv_cmd_get_ssid(iface, &from);
+		wpa_priv_cmd_get_ssid(iface, &from, fromlen);
 		break;
 	case PRIVSEP_CMD_SET_KEY:
 		wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
 		break;
 	case PRIVSEP_CMD_GET_CAPA:
-		wpa_priv_cmd_get_capa(iface, &from);
+		wpa_priv_cmd_get_capa(iface, &from, fromlen);
 		break;
 	case PRIVSEP_CMD_L2_REGISTER:
-		wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len);
+		wpa_priv_cmd_l2_register(iface, &from, fromlen,
+					 cmd_buf, cmd_len);
 		break;
 	case PRIVSEP_CMD_L2_UNREGISTER:
-		wpa_priv_cmd_l2_unregister(iface, &from);
+		wpa_priv_cmd_l2_unregister(iface, &from, fromlen);
 		break;
 	case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
 		wpa_priv_cmd_l2_notify_auth_start(iface, &from);
 		break;
 	case PRIVSEP_CMD_L2_SEND:
-		wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len);
+		wpa_priv_cmd_l2_send(iface, &from, fromlen, cmd_buf, cmd_len);
 		break;
 	case PRIVSEP_CMD_SET_COUNTRY:
 		pos = cmd_buf;
@@ -625,8 +708,14 @@
 
 static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
 {
-	if (iface->drv_priv && iface->driver->deinit)
-		iface->driver->deinit(iface->drv_priv);
+	int i;
+
+	if (iface->drv_priv) {
+		if (iface->driver->deinit)
+			iface->driver->deinit(iface->drv_priv);
+		if (iface->drv_global_priv)
+			iface->driver->global_deinit(iface->drv_global_priv);
+	}
 
 	if (iface->fd >= 0) {
 		eloop_unregister_read_sock(iface->fd);
@@ -634,8 +723,10 @@
 		unlink(iface->sock_name);
 	}
 
-	if (iface->l2)
-		l2_packet_deinit(iface->l2);
+	for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+		if (iface->l2[i])
+			l2_packet_deinit(iface->l2[i]);
+	}
 
 	os_free(iface->ifname);
 	os_free(iface->driver_name);
@@ -777,7 +868,7 @@
 	msg.msg_iov = io;
 	msg.msg_iovlen = data ? 2 : 1;
 	msg.msg_name = &iface->drv_addr;
-	msg.msg_namelen = sizeof(iface->drv_addr);
+	msg.msg_namelen = iface->drv_addr_len;
 
 	if (sendmsg(iface->fd, &msg, 0) < 0) {
 		wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
@@ -796,7 +887,7 @@
 	struct privsep_event_auth *auth;
 	u8 *buf, *pos;
 
-	buf = os_malloc(buflen);
+	buf = os_zalloc(buflen);
 	if (buf == NULL)
 		return;
 
@@ -1061,7 +1152,7 @@
 	msg.msg_iov = io;
 	msg.msg_iovlen = 3;
 	msg.msg_name = &iface->drv_addr;
-	msg.msg_namelen = sizeof(iface->drv_addr);
+	msg.msg_namelen = iface->drv_addr_len;
 
 	if (sendmsg(iface->fd, &msg, 0) < 0)
 		wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 8cfb488..531004f 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -329,7 +329,12 @@
 
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 
-	ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#ifdef CONFIG_MACSEC
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
+		ieee802_1x_create_preshared_mka(wpa_s, ssid);
+	else
+		ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* CONFIG_MACSEC */
 #endif /* IEEE8021X_EAPOL */
 }
 
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 047ca90..edb230d 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -98,9 +98,7 @@
 #    parameters (e.g., WPA IE generation); this mode can also be used with
 #    non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
 #    APs (i.e., external program needs to control association). This mode must
-#    also be used when using wired Ethernet drivers.
-#    Note: macsec_qca driver is one type of Ethernet driver which implements
-#    macsec feature.
+#    also be used when using wired Ethernet drivers (including MACsec).
 # 2: like 0, but associate with APs using security policy and SSID (but not
 #    BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
 #    enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -881,17 +879,36 @@
 # bit0 (1): require dynamically generated unicast WEP key
 # bit1 (2): require dynamically generated broadcast WEP key
 # 	(3 = require both keys; default)
-# Note: When using wired authentication (including macsec_qca driver),
+# Note: When using wired authentication (including MACsec drivers),
 # eapol_flags must be set to 0 for the authentication to be completed
 # successfully.
 #
 # macsec_policy: IEEE 802.1X/MACsec options
-# This determines how sessions are secured with MACsec. It is currently
-# applicable only when using the macsec_qca driver interface.
+# This determines how sessions are secured with MACsec (only for MACsec
+# drivers).
 # 0: MACsec not in use (default)
 # 1: MACsec enabled - Should secure, accept key server's advice to
 #    determine whether to use a secure session or not.
 #
+# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
+# This setting applies only when MACsec is in use, i.e.,
+#  - macsec_policy is enabled
+#  - the key server has decided to enable MACsec
+# 0: Encrypt traffic (default)
+# 1: Integrity only
+#
+# macsec_port: IEEE 802.1X/MACsec port
+# Port component of the SCI
+# Range: 1-65534 (default: 1)
+#
+# mka_cak and mka_ckn: IEEE 802.1X/MACsec pre-shared authentication mode
+# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
+# In this mode, instances of wpa_supplicant can act as peers, one of
+# which will become the key server and start distributing SAKs.
+# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-bytes (128 bit)
+# hex-string (32 hex-digits)
+# mka_ckn (CKN = CAK Name) takes a 32-bytes (256 bit) hex-string (64 hex-digits)
+#
 # mixed_cell: This option can be used to configure whether so called mixed
 # cells, i.e., networks that use both plaintext and encryption in the same
 # SSID, are allowed when selecting a BSS from scan results.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 4a7e3c7..ff3a531 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -652,6 +652,12 @@
 	int normal_scans; /* normal scans run before sched_scan */
 	int scan_for_connection; /* whether the scan request was triggered for
 				  * finding a connection */
+	/*
+	 * A unique cookie representing the vendor scan request. This cookie is
+	 * returned from the driver interface. 0 indicates that there is no
+	 * pending vendor scan request.
+	 */
+	u64 curr_scan_cookie;
 #define MAX_SCAN_ID 16
 	int scan_id[MAX_SCAN_ID];
 	unsigned int scan_id_count;
@@ -1310,6 +1316,6 @@
 struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 				     int i, struct wpa_bss *bss,
 				     struct wpa_ssid *group,
-				     int only_first_ssid);
+				     int only_first_ssid, int debug_print);
 
 #endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index e032330..d3fefda 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -50,6 +50,12 @@
 }
 
 
+static int wpas_enable_encrypt(void *wpa_s, Boolean enabled)
+{
+	return wpa_drv_enable_encrypt(wpa_s, enabled);
+}
+
+
 static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
 {
 	return wpa_drv_set_replay_protect(wpa_s, enabled, window);
@@ -187,7 +193,14 @@
 	if (!ssid || ssid->macsec_policy == 0)
 		return 0;
 
-	policy = ssid->macsec_policy == 1 ? SHOULD_SECURE : DO_NOT_SECURE;
+	if (ssid->macsec_policy == 1) {
+		if (ssid->macsec_integ_only == 1)
+			policy = SHOULD_SECURE;
+		else
+			policy = SHOULD_ENCRYPT;
+	} else {
+		policy = DO_NOT_SECURE;
+	}
 
 	kay_ctx = os_zalloc(sizeof(*kay_ctx));
 	if (!kay_ctx)
@@ -199,6 +212,7 @@
 	kay_ctx->macsec_deinit = wpas_macsec_deinit;
 	kay_ctx->macsec_get_capability = wpas_macsec_get_capability;
 	kay_ctx->enable_protect_frames = wpas_enable_protect_frames;
+	kay_ctx->enable_encrypt = wpas_enable_encrypt;
 	kay_ctx->set_replay_protect = wpas_set_replay_protect;
 	kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite;
 	kay_ctx->enable_controlled_port = wpas_enable_controlled_port;
@@ -218,8 +232,8 @@
 	kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa;
 	kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
 
-	res = ieee802_1x_kay_init(kay_ctx, policy, wpa_s->ifname,
-				  wpa_s->own_addr);
+	res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_port,
+				  wpa_s->ifname, wpa_s->own_addr);
 	if (res == NULL) {
 		os_free(kay_ctx);
 		return -1;
@@ -371,3 +385,51 @@
 
 	return res;
 }
+
+
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid)
+{
+	struct mka_key *cak;
+	struct mka_key_name *ckn;
+	void *res;
+
+	if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
+		return NULL;
+
+	if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0)
+		return NULL;
+
+	if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
+		return NULL;
+
+	ckn = os_zalloc(sizeof(*ckn));
+	if (!ckn)
+		goto dealloc;
+
+	cak = os_zalloc(sizeof(*cak));
+	if (!cak)
+		goto free_ckn;
+
+	cak->len = MACSEC_CAK_LEN;
+	os_memcpy(cak->key, ssid->mka_cak, cak->len);
+
+	ckn->len = MACSEC_CKN_LEN;
+	os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
+
+	res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
+	if (res)
+		return res;
+
+	/* Failed to create MKA */
+	os_free(cak);
+
+	/* fallthrough */
+
+free_ckn:
+	os_free(ckn);
+dealloc:
+	ieee802_1x_dealloc_kay_sm(wpa_s);
+
+	return NULL;
+}
diff --git a/wpa_supplicant/wpas_kay.h b/wpa_supplicant/wpas_kay.h
index b7236d0..81f8e0c 100644
--- a/wpa_supplicant/wpas_kay.h
+++ b/wpa_supplicant/wpas_kay.h
@@ -17,6 +17,9 @@
 				      const u8 *peer_addr);
 void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s);
 
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid);
+
 #else /* CONFIG_MACSEC */
 
 static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s,
@@ -36,6 +39,13 @@
 {
 }
 
+static inline void *
+ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+				struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
 #endif /* CONFIG_MACSEC */
 
 #endif /* WPAS_KAY_H */