Cumulative patch from commit ee48f48ba

The following commits are merged as well as changes in
./wpa_supplicant/hidl/1.3 to fix compilation errors.

ee48f48ba hostapd: Support showing neighbor list through hostapd_cli
3204795d7 STA OBSS: Add check for overlapping BSSs
3af78a4e0 Extract BSS coex 40 MHz check into a separate function
70755e658 Allow removing neighbor DB entries by BSSID alone
bf3ab50f4 Change some RRM debug messages from wpa_printf() to wpa_dbg()
a737e40b5 drivers: Support of dynamic VLAN requires Linux ioctls
9b391715c mesh: Allow group management cipher to be configured
65d0b67c2 mesh: Increase plink action frame AMPY buffer length for max GTK/IGTK
b1b62a136 WPS: Add WPS-PIN-ACTIVE and WPS-CANCEL events
0b1839405 Add "reconnect" cmdline argument to hostapd_cli/wpa_cli
4318a635a DBus: Update dont_quote[] with new network profile parameters
26a00ba8b DBus: Remove not existing network profile params from dont_quote[]
23d87687c dbus: Move roam metrics to the correct interface
8e111157e nl80211: Relax bridge setup
3626e72c8 l2_packet: Fix bridge workaround for repeater configuration
84972999b FT: More debug prints for RSNE modification for EAPOL-Key msg 2/4
4cfa8b92b Fix wpa_insert_pmkid() when buffer includes extra IEs
32289112c wpa_passphrase: Output errors to stderr
07fe134d9 EAP-SIM peer: Do not accept SIM/Challenge without SIM/Start
b2e2a8588 OpenSSL: Extend key_block size determination to support GCM/CCM ciphers
efaa6256e More detailed documentation on ieee80211w configuration parameter
1730a6a5e nl80211: Fix couple of typos in a comment
307cfc328 Strip trailing zero data in EAPOL-Key msg 1/4 when no PMKID to send
2c5ccfa60 nl80211: Initialize full channel info struct even if channel is not known
e6d3aca9c WPS: Add prefixes to public event_* functions
2ba6aa604 Fix memory leak in case allocation of token fails during JSON parsing
84877f253 wpa_supplicant: Do not try to detect PSK mismatch during PTK rekeying
78d338d1b DPP: Fix a memory leak on an error path
9be30ffc1 DPP: Abort ongoing scan if connection status needs to be sent
3f3876344 SAE: Enable NEED_DH_GROUPS_ALL for CONFIG_TESTING_OPTIONS=y builds
1f1567d2a QCA vendor command for getting STA information
e5620bf02 6 GHz: Select channel width using configured op_class
0bfc04b8d Do not enable HT/VHT when operating in 6 GHz band
da8570f4c Allow non-PCS 6 GHz channels to be excluded from ACS
59bb72642 Allow ACS channel list to be configured as frequencies (in MHz)
5f9b4afdf Use frequency in HT/VHT validation steps done before starting AP
59e33b4a9 ACS: Select current hw_mode based on the selected frequency
bb781c763 AP: Populate iface->freq before starting AP
41cac481a ACS: Use frequency params in ACS (offload) completed event interface
840532aea Search through all hw_features sets in hw_get_channel_freq()
15d356873 ACS: Add channels from all modes matching with configured hw mode
996662250 P2P: Add support for EDMG channels
f86e34168 Update operating classes and channels for the 60 GHz band
a19277a28 Add EDMG bandwidth to channel frequency APIs
5a563a3d3 Avoid compiler warning on shadowing a local variable
e3c476bd8 SAE H2E: Fix RSNXE override in EAPOL-Key msg 2/4 for testing purposes
7fde39fb1 Add sae_rejected_groups to hostapd STA control interface command
5661ebd77 DPP: Configurator netRole for Enrollee
740457445 DPP: Replace ap boolean with netRole enum in Configurator params
f2c4b44b4 SAE H2E: RSNXE override in EAPOL-Key msg 3/4
132565539 SAE H2E: RSNXE override for testing purposes
a889e9a70 SAE: Reject invalid rejected group report in SAE commit explicitly (AP)
c88e01e1b SAE H2E: Fix validation of rejected groups list
b834e9700 SAE H2E: Testing option to report extra rejected groups
918df2227 SAE: Reject unexpected Status Code in SAE commit explicitly (AP)
405946d76 SAE: Testing option to ignore H2E requirement mismatch
23acdd9f3 Fix memory leak in ACS offload operation
e86ba912a ACS: Remove redundant ch_list parameters from do_acs interface
3cf360b8e DFS: Don't handle DFS ops for 6 GHz channels
ee0030e81 6 GHz: Do not check for HT capability on 6 GHz channels
e780b4bf2 DPP: Bootstrapping via NFC URI Record
3c0d6eb8a Sync with mac80211-next.git include/uapi/linux/nl80211.h
38203148e Extend hostapd to support setband to driver via QCA vendor command
3c13af557 hostapd: Register wpa_msg callback even if only global ctrl_iface is used
e92080568 hostapd: Extend global control interface notifications
9f50538e1 SAE H2E: Do not use sae_h2e param in AP mode if SAE is disabled
181bf9336 DPP2: Report received ssid_charset as DPP-CONFOBJ-SSID-CHARSET event
71e2848ea DPP2: ssid64/ssid_charset in Configurator
57a63b131 DPP2: Add parsing of ssid64/ssid_charset in Config Object
590bc64d6 DPP: Use JSON token builder helpers
e75ab5322 JSON: Add helper functions for building tokens
8e5e36a18 Clean up base64_{encode,decode} pointer types
b22608423 Clean up base64_url_{encode,decode} pointer types
a4255a207 Simplify base64_url_encode() prototype
c54227c26 DPP2: Replace connectionStatus object ssid with ssid64
31b6eb417 tests: Update SAE H2E test case to match SSWU parameter z change
0432237a4 SAE H2E: Update SSWU curve-specific parameter z values
5b50265e1 WMM: Do not modify input TSPEC buffer during processing
783a99b73 HS2.0: Skip check for roaming_consortium for NAI realm query
f3c077929 P2P: Fix listen state machine getting stuck in send_action() scheduled case
530b8ee3c hostapd: Update DFS status in VHT80+80 mode
93ba13bcf Fix status code in SAE/DPP association PMKID mismatch (driver-AP-SME)
b90d2f7ff Fix a typo in a comment

Bug: 146900007
Test: Device boots up and connects to wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: Regression test Passed (Bug: 146905211)
Change-Id: Idc3584b491429a2e4935068a293bff572fc9d62e
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 5815b86..309127e 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -263,6 +263,9 @@
 NEED_ECC=y
 NEED_DH_GROUPS=y
 NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
 endif
 
 ifdef CONFIG_DPP
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index b478466..68ef5a2 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -265,6 +265,9 @@
 NEED_ECC=y
 NEED_DH_GROUPS=y
 NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
 endif
 
 ifdef CONFIG_DPP
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 59ca153..e552306 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -775,7 +775,8 @@
 		ssid->frequency = 2462; /* default channel 11 */
 	params.freq.freq = ssid->frequency;
 
-	if (ssid->mode == WPAS_MODE_AP && ssid->enable_edmg) {
+	if ((ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO) &&
+	    ssid->enable_edmg) {
 		u8 primary_channel;
 
 		if (ieee80211_freq_to_chan(ssid->frequency, &primary_channel) ==
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index d100c46..2d1c126 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4950,6 +4950,7 @@
 	{ INT(p2p_go_ht40), 0 },
 	{ INT(p2p_go_vht), 0 },
 	{ INT(p2p_go_he), 0 },
+	{ INT(p2p_go_edmg), 0 },
 	{ INT(p2p_disabled), 0 },
 	{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
 	{ INT(p2p_no_group_iface), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 922a75e..d00c4ec 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1090,6 +1090,16 @@
 	int p2p_go_vht;
 
 	/**
+	 * p2p_go_edmg - Default mode for EDMG enable when operating as GO
+	 *
+	 * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+	 * Note that regulatory constraints and driver capabilities are
+	 * consulted anyway, so setting it to 1 can't do real harm.
+	 * By default: 0 (disabled)
+	 */
+	int p2p_go_edmg;
+
+	/**
 	 * p2p_go_he - Default mode for 11ax HE enable when operating as GO
 	 *
 	 * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 7651465..305291e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -296,7 +296,7 @@
 {
 	struct wpa_config_blob *blob;
 	char buf[256], *pos;
-	unsigned char *encoded = NULL, *nencoded;
+	char *encoded = NULL, *nencoded;
 	int end = 0;
 	size_t encoded_len = 0, len;
 
@@ -1098,7 +1098,7 @@
 #ifndef CONFIG_NO_CONFIG_BLOBS
 static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
 {
-	unsigned char *encoded;
+	char *encoded;
 
 	encoded = base64_encode(blob->data, blob->len, NULL);
 	if (encoded == NULL)
@@ -1287,6 +1287,8 @@
 		fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht);
 	if (config->p2p_go_he)
 		fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he);
+	if (config->p2p_go_edmg)
+		fprintf(f, "p2p_go_edmg=%d\n", config->p2p_go_edmg);
 	if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
 		fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow);
 	if (config->p2p_disabled)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 7f8ec4a..be5ea17 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -663,6 +663,42 @@
 		wpa_s->ignore_assoc_disallow = !!atoi(value);
 		wpa_drv_ignore_assoc_disallow(wpa_s,
 					      wpa_s->ignore_assoc_disallow);
+	} else if (os_strcasecmp(cmd, "ignore_sae_h2e_only") == 0) {
+		wpa_s->ignore_sae_h2e_only = !!atoi(value);
+	} else if (os_strcasecmp(cmd, "extra_sae_rejected_groups") == 0) {
+		char *pos;
+
+		os_free(wpa_s->extra_sae_rejected_groups);
+		wpa_s->extra_sae_rejected_groups = NULL;
+		pos = value;
+		while (pos && pos[0]) {
+			int group;
+
+			group = atoi(pos);
+			wpa_printf(MSG_DEBUG,
+				   "TESTING: Extra rejection of SAE group %d",
+				   group);
+			if (group)
+				int_array_add_unique(
+					&wpa_s->extra_sae_rejected_groups,
+					group);
+			pos = os_strchr(pos, ' ');
+			if (!pos)
+				break;
+			pos++;
+		}
+	} else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) {
+		wpabuf_free(wpa_s->rsnxe_override_assoc);
+		if (os_strcmp(value, "NULL") == 0)
+			wpa_s->rsnxe_override_assoc = NULL;
+		else
+			wpa_s->rsnxe_override_assoc = wpabuf_parse_bin(value);
+	} else if (os_strcasecmp(cmd, "rsnxe_override_eapol") == 0) {
+		wpabuf_free(wpa_s->rsnxe_override_eapol);
+		if (os_strcmp(value, "NULL") == 0)
+			wpa_s->rsnxe_override_eapol = NULL;
+		else
+			wpa_s->rsnxe_override_eapol = wpabuf_parse_bin(value);
 	} else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
 		wpa_s->reject_btm_req_reason = atoi(value);
 	} else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
@@ -5637,6 +5673,7 @@
 	int freq = 0;
 	int pd;
 	int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+	int edmg;
 	u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
 	size_t group_ssid_len = 0;
 	int he;
@@ -5652,7 +5689,7 @@
 	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
 	 * [persistent|persistent=<network id>]
 	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
-	 * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */
+	 * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>] */
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
@@ -5684,6 +5721,7 @@
 	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
 		vht;
 	he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
+	edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
 
 	pos2 = os_strstr(pos, " go_intent=");
 	if (pos2) {
@@ -5754,7 +5792,7 @@
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
 				   persistent_group, automatic, join,
 				   auth, go_intent, freq, freq2, persistent_id,
-				   pd, ht40, vht, max_oper_chwidth, he,
+				   pd, ht40, vht, max_oper_chwidth, he, edmg,
 				   group_ssid, group_ssid_len);
 	if (new_pin == -2) {
 		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
@@ -6311,6 +6349,7 @@
 	u8 *_peer = NULL, peer[ETH_ALEN];
 	int freq = 0, pref_freq = 0;
 	int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
+	int edmg;
 
 	id = atoi(cmd);
 	pos = os_strstr(cmd, " peer=");
@@ -6348,6 +6387,7 @@
 	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
 		vht;
 	he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
+	edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
 
 	pos = os_strstr(cmd, "freq2=");
 	if (pos)
@@ -6362,7 +6402,7 @@
 		return -1;
 
 	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
-			       max_oper_chwidth, pref_freq, he);
+			       max_oper_chwidth, pref_freq, he, edmg);
 }
 
 
@@ -6411,7 +6451,7 @@
 static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
 					 int id, int freq, int vht_center_freq2,
 					 int ht40, int vht, int vht_chwidth,
-					 int he)
+					 int he, int edmg)
 {
 	struct wpa_ssid *ssid;
 
@@ -6425,7 +6465,8 @@
 
 	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
 					     vht_center_freq2, 0, ht40, vht,
-					     vht_chwidth, he, NULL, 0, 0);
+					     vht_chwidth, he, edmg,
+					     NULL, 0, 0);
 }
 
 
@@ -6435,6 +6476,7 @@
 	int vht = wpa_s->conf->p2p_go_vht;
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 	int he = wpa_s->conf->p2p_go_he;
+	int edmg = wpa_s->conf->p2p_go_edmg;
 	int max_oper_chwidth, chwidth = 0, freq2 = 0;
 	char *token, *context = NULL;
 #ifdef CONFIG_ACS
@@ -6459,6 +6501,8 @@
 			ht40 = 1;
 		} else if (os_strcmp(token, "he") == 0) {
 			he = 1;
+		} else if (os_strcmp(token, "edmg") == 0) {
+			edmg = 1;
 		} else if (os_strcmp(token, "persistent") == 0) {
 			persistent = 1;
 		} else {
@@ -6496,10 +6540,11 @@
 	if (group_id >= 0)
 		return p2p_ctrl_group_add_persistent(wpa_s, group_id,
 						     freq, freq2, ht40, vht,
-						     max_oper_chwidth, he);
+						     max_oper_chwidth, he,
+						     edmg);
 
 	return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
-				  max_oper_chwidth, he);
+				  max_oper_chwidth, he, edmg);
 }
 
 
@@ -8045,12 +8090,19 @@
 	wpa_s->ignore_auth_resp = 0;
 	wpa_s->ignore_assoc_disallow = 0;
 	wpa_s->testing_resend_assoc = 0;
+	wpa_s->ignore_sae_h2e_only = 0;
 	wpa_s->reject_btm_req_reason = 0;
 	wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
 	os_free(wpa_s->get_pref_freq_list_override);
 	wpa_s->get_pref_freq_list_override = NULL;
 	wpabuf_free(wpa_s->sae_commit_override);
 	wpa_s->sae_commit_override = NULL;
+	os_free(wpa_s->extra_sae_rejected_groups);
+	wpa_s->extra_sae_rejected_groups = NULL;
+	wpabuf_free(wpa_s->rsnxe_override_assoc);
+	wpa_s->rsnxe_override_assoc = NULL;
+	wpabuf_free(wpa_s->rsnxe_override_eapol);
+	wpa_s->rsnxe_override_eapol = NULL;
 #ifdef CONFIG_DPP
 	os_free(wpa_s->dpp_config_obj_override);
 	wpa_s->dpp_config_obj_override = NULL;
@@ -9465,16 +9517,16 @@
 
 		if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
 		    nr_len < NR_IE_MIN_LEN) {
-			wpa_printf(MSG_DEBUG,
-				   "CTRL: Invalid Neighbor Report element: id=%u len=%u",
-				   data[0], nr_len);
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"CTRL: Invalid Neighbor Report element: id=%u len=%u",
+				data[0], nr_len);
 			goto out;
 		}
 
 		if (2U + nr_len > len) {
-			wpa_printf(MSG_DEBUG,
-				   "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
-				   data[0], len, nr_len);
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+				data[0], len, nr_len);
 			goto out;
 		}
 		pos += 2;
@@ -9544,8 +9596,8 @@
 	ssid_s = os_strstr(cmd, "ssid=");
 	if (ssid_s) {
 		if (ssid_parse(ssid_s + 5, &ssid)) {
-			wpa_printf(MSG_ERROR,
-				   "CTRL: Send Neighbor Report: bad SSID");
+			wpa_msg(wpa_s, MSG_INFO,
+				"CTRL: Send Neighbor Report: bad SSID");
 			return -1;
 		}
 
@@ -10678,6 +10730,17 @@
 			if (os_snprintf_error(reply_size, reply_len))
 				reply_len = -1;
 		}
+	} else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
+		int res;
+
+		res = wpas_dpp_nfc_uri(wpa_s, buf + 12);
+		if (res < 0) {
+			reply_len = -1;
+		} else {
+			reply_len = os_snprintf(reply, reply_size, "%d", res);
+			if (os_snprintf_error(reply_size, reply_len))
+				reply_len = -1;
+		}
 	} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
 		int res;
 
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 5e6b522..e9e77bd 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -2855,30 +2855,6 @@
 	  NULL,
 	  NULL
 	},
-	{
-	  "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-	  wpas_dbus_getter_roam_time,
-	  NULL,
-	  NULL
-	},
-	{
-	  "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
-	  wpas_dbus_getter_roam_complete,
-	  NULL,
-	  NULL
-	},
-	{
-	  "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-	  wpas_dbus_getter_session_length,
-	  NULL,
-	  NULL
-	},
-	{
-	  "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-	  wpas_dbus_getter_bss_tm_status,
-	  NULL,
-	  NULL
-	},
 	{ NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
@@ -3786,6 +3762,30 @@
 	  NULL,
 	  NULL
 	},
+	{
+	  "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+	  wpas_dbus_getter_roam_time,
+	  NULL,
+	  NULL
+	},
+	{
+	  "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+	  wpas_dbus_getter_roam_complete,
+	  NULL,
+	  NULL
+	},
+	{
+	  "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+	  wpas_dbus_getter_session_length,
+	  NULL,
+	  NULL
+	},
+	{
+	  "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+	  wpas_dbus_getter_bss_tm_status,
+	  NULL,
+	  NULL
+	},
 #ifdef CONFIG_MESH
 	{ "MeshPeers", WPAS_DBUS_NEW_IFACE_MESH, "aay",
 	  wpas_dbus_getter_mesh_peers,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 2582092..4b6dabc 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -137,8 +137,15 @@
 
 static const char * const dont_quote[] = {
 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
-	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-	"bssid", "scan_freq", "freq_list", NULL
+	"bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
+	"bssid_blacklist", "bssid_whitelist", "group_mgmt",
+#ifdef CONFIG_MESH
+	"mesh_basic_rates",
+#endif /* CONFIG_MESH */
+#ifdef CONFIG_P2P
+	"go_p2p_dev_addr", "p2p_client_list", "psk_list",
+#endif /* CONFIG_P2P */
+	NULL
 };
 
 static dbus_bool_t should_quote_opt(const char *key)
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 19715eb..7a65673 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -425,14 +425,14 @@
 			goto inv_args;
 
 		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
-						  0, 0, 0, NULL, 0, 0)) {
+						  0, 0, 0, 0, NULL, 0, 0)) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
 			goto out;
 		}
 	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
-				      0, 0))
+				      0, 0, 0))
 		goto inv_args;
 
 out:
@@ -652,7 +652,7 @@
 
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
 				   persistent_group, 0, join, authorize_only,
-				   go_intent, freq, 0, -1, 0, 0, 0, 0, 0,
+				   go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
 				   NULL, 0);
 
 	if (new_pin >= 0) {
@@ -810,7 +810,7 @@
 			goto err;
 
 		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
-				    0, 0) < 0) {
+				    0, 0, 0) < 0) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index a436930..73649c2 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -89,6 +89,24 @@
 }
 
 
+/**
+ * wpas_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+	struct dpp_bootstrap_info *bi;
+
+	bi = dpp_add_nfc_uri(wpa_s->dpp, cmd);
+	if (!bi)
+		return -1;
+
+	return bi->id;
+}
+
+
 static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -180,6 +198,8 @@
 		result = DPP_STATUS_NO_AP;
 	else
 		result = 255; /* What to report here for unexpected state? */
+	if (wpa_s->wpa_state == WPA_SCANNING)
+		wpas_abort_ongoing_scan(wpa_s);
 	wpas_dpp_send_conn_status_result(wpa_s, result);
 }
 
@@ -663,7 +683,12 @@
 	pos = os_strstr(cmd, " netrole=");
 	if (pos) {
 		pos += 9;
-		wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
+		if (os_strncmp(pos, "ap", 2) == 0)
+			wpa_s->dpp_netrole = DPP_NETROLE_AP;
+		else if (os_strncmp(pos, "configurator", 12) == 0)
+			wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+		else
+			wpa_s->dpp_netrole = DPP_NETROLE_STA;
 	}
 
 	pos = os_strstr(cmd, " neg_freq=");
@@ -815,7 +840,12 @@
 		wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
 			DPP_CAPAB_ENROLLEE;
 	wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
-	wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
+	if (os_strstr(cmd, " netrole=ap"))
+		wpa_s->dpp_netrole = DPP_NETROLE_AP;
+	else if (os_strstr(cmd, " netrole=configurator"))
+		wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+	else
+		wpa_s->dpp_netrole = DPP_NETROLE_STA;
 	if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
 		wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
 			   freq);
@@ -1120,6 +1150,9 @@
 	if (conf->ssid_len)
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
 			wpa_ssid_txt(conf->ssid, conf->ssid_len));
+	if (conf->ssid_charset)
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID_CHARSET "%d",
+			conf->ssid_charset);
 	if (conf->connector) {
 		/* TODO: Save the Connector and consider using a command
 		 * to fetch the value instead of sending an event with
@@ -1283,7 +1316,7 @@
 
 	supp_op_classes = wpas_supp_op_classes(wpa_s);
 	buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
-					wpa_s->dpp_netrole_ap,
+					wpa_s->dpp_netrole,
 					wpa_s->conf->dpp_mud_url,
 					supp_op_classes);
 	os_free(supp_op_classes);
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index b337982..607036a 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -13,6 +13,7 @@
 enum dpp_status_error;
 
 int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
 void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 524724f..53d7585 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -439,7 +439,7 @@
 static void eapol_test_write_cert(FILE *f, const char *subject,
 				  const struct wpabuf *cert)
 {
-	unsigned char *encoded;
+	char *encoded;
 
 	encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
 	if (encoded == NULL)
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 139402e..15ef0f7 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -857,6 +857,13 @@
 					if (debug_print)
 						wpa_dbg(wpa_s, MSG_DEBUG,
 							"   SAE H2E disabled");
+#ifdef CONFIG_TESTING_OPTIONS
+					if (wpa_s->ignore_sae_h2e_only) {
+						wpa_dbg(wpa_s, MSG_DEBUG,
+							"TESTING: Ignore SAE H2E requirement mismatch");
+						continue;
+					}
+#endif /* CONFIG_TESTING_OPTIONS */
 					return 0;
 				}
 				continue;
@@ -1914,7 +1921,7 @@
 	if (wnm_scan_process(wpa_s, 1) > 0)
 		goto scan_work_done;
 
-	if (sme_proc_obss_scan(wpa_s) > 0)
+	if (sme_proc_obss_scan(wpa_s, scan_res) > 0)
 		goto scan_work_done;
 
 	if (own_request && data &&
@@ -2939,6 +2946,16 @@
 
 	wpa_s->last_eapol_matches_bssid = 0;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->rsnxe_override_eapol) {
+		wpa_printf(MSG_DEBUG,
+			   "TESTING: RSNXE EAPOL-Key msg 2/4 override");
+		wpa_sm_set_assoc_rsnxe(wpa_s->wpa,
+				       wpabuf_head(wpa_s->rsnxe_override_eapol),
+				       wpabuf_len(wpa_s->rsnxe_override_eapol));
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (wpa_s->pending_eapol_rx) {
 		struct os_reltime now, age;
 		os_get_reltime(&now);
@@ -3054,9 +3071,10 @@
 				 int locally_generated)
 {
 	if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
+	    !wpa_s->new_connection ||
 	    !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
 	    wpa_key_mgmt_sae(wpa_s->key_mgmt))
-		return 0; /* Not in 4-way handshake with PSK */
+		return 0; /* Not in initial 4-way handshake with PSK */
 
 	/*
 	 * It looks like connection was lost while trying to go through PSK
diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.cpp b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
index ee53f71..833d624 100644
--- a/wpa_supplicant/hidl/1.3/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
@@ -331,6 +331,7 @@
     const std::string& passphrase)
 {
 	int ret = 0;
+	int he = wpa_s->conf->p2p_go_he;
 	int vht = wpa_s->conf->p2p_go_vht;
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 
@@ -349,7 +350,7 @@
 
 	if (wpas_p2p_group_add_persistent(
 		wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
-		CHANWIDTH_USE_HT, 0, NULL, 0, 0)) {
+		CHANWIDTH_USE_HT, he, 0, NULL, 0, 0)) {
 		ret = -1;
 	}
 
@@ -1061,6 +1062,7 @@
 		wps_method = WPS_PIN_KEYPAD;
 		break;
 	}
+	int he = wpa_s->conf->p2p_go_he;
 	int vht = wpa_s->conf->p2p_go_vht;
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 	const char* pin =
@@ -1068,7 +1070,7 @@
 	int new_pin = wpas_p2p_connect(
 	    wpa_s, peer_address.data(), pin, wps_method, persistent, false,
 	    join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
-	    vht, CHANWIDTH_USE_HT, 0, nullptr, 0);
+	    vht, CHANWIDTH_USE_HT, he, 0, nullptr, 0);
 	if (new_pin < 0) {
 		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
 	}
@@ -1124,6 +1126,7 @@
     bool persistent, SupplicantNetworkId persistent_network_id)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	int he = wpa_s->conf->p2p_go_he;
 	int vht = wpa_s->conf->p2p_go_vht;
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 	struct wpa_ssid* ssid =
@@ -1131,7 +1134,7 @@
 	if (ssid == NULL) {
 		if (wpas_p2p_group_add(
 			wpa_s, persistent, 0, 0, ht40, vht,
-			CHANWIDTH_USE_HT, 0)) {
+			CHANWIDTH_USE_HT, he, 0)) {
 			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 		} else {
 			return {SupplicantStatusCode::SUCCESS, ""};
@@ -1139,7 +1142,7 @@
 	} else if (ssid->disabled == 2) {
 		if (wpas_p2p_group_add_persistent(
 			wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
-			CHANWIDTH_USE_HT, 0, NULL, 0, 0)) {
+			CHANWIDTH_USE_HT, he, 0, NULL, 0, 0)) {
 			return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
 				""};
 		} else {
@@ -1194,6 +1197,7 @@
     const std::array<uint8_t, 6>& peer_address)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	int he = wpa_s->conf->p2p_go_he;
 	int vht = wpa_s->conf->p2p_go_vht;
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 	struct wpa_ssid* ssid =
@@ -1203,7 +1207,7 @@
 	}
 	if (wpas_p2p_invite(
 		wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
-		CHANWIDTH_USE_HT, 0, 0)) {
+		CHANWIDTH_USE_HT, 0, he, 0)) {
 		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	return {SupplicantStatusCode::SUCCESS, ""};
@@ -1632,6 +1636,7 @@
     bool joinExistingGroup)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	int he = wpa_s->conf->p2p_go_he;
 	int vht = wpa_s->conf->p2p_go_vht;
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 
@@ -1659,7 +1664,7 @@
 
 		if (wpas_p2p_group_add(
 		    wpa_s, persistent, freq, 0, ht40, vht,
-		    CHANWIDTH_USE_HT, 0)) {
+		    CHANWIDTH_USE_HT, he, 0)) {
 			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 		}
 		return {SupplicantStatusCode::SUCCESS, ""};
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index e81fef1..741f925 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -341,7 +341,7 @@
 {
 	struct icon_entry *icon;
 	size_t out_size;
-	unsigned char *b64;
+	char *b64;
 	size_t b64_size;
 	int reply_size;
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 585b7f0..dc51418 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -176,7 +176,7 @@
 			continue;
 		if (!cred->eap_method)
 			return 1;
-		if (cred->realm && cred->roaming_consortium_len == 0)
+		if (cred->realm)
 			return 1;
 	}
 	return 0;
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 5c1a47d..b504124 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -114,8 +114,14 @@
 	}
 
 	conf->group_cipher = cipher;
-	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
-		conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		if (ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+		    ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_256 ||
+		    ssid->group_mgmt_cipher == WPA_CIPHER_BIP_CMAC_256)
+			conf->mgmt_group_cipher = ssid->group_mgmt_cipher;
+		else
+			conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+	}
 
 	/* defaults */
 	conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 4a163b6..308366f 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -231,7 +231,7 @@
 		  2 + 32 + /* mesh ID */
 		  2 + 7 +  /* mesh config */
 		  2 + 24 + /* peering management */
-		  2 + 96 + /* AMPE */
+		  2 + 96 + 32 + 32 + /* AMPE (96 + max GTKlen + max IGTKlen) */
 		  2 + 16;  /* MIC */
 #ifdef CONFIG_IEEE80211N
 	if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index fb509a1..a3c4574 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1885,6 +1885,83 @@
 }
 
 
+/**
+ * wpas_p2p_freq_to_edmg_channel - Convert frequency into EDMG channel
+ * @freq: Frequency (MHz) to convert
+ * @op_class: Buffer for returning operating class
+ * @op_edmg_channel: Buffer for returning channel number
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to find the highest channel bonding which includes the
+ * specified frequency.
+ */
+static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s,
+					 unsigned int freq,
+					 u8 *op_class, u8 *op_edmg_channel)
+{
+	struct hostapd_hw_modes *hwmode;
+	struct ieee80211_edmg_config edmg;
+	unsigned int i;
+	enum chan_width chanwidth[] = {
+		CHAN_WIDTH_8640,
+		CHAN_WIDTH_6480,
+		CHAN_WIDTH_4320,
+	};
+
+	if (!wpa_s->hw.modes)
+		return -1;
+
+	hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+			  HOSTAPD_MODE_IEEE80211AD);
+	if (!hwmode) {
+		wpa_printf(MSG_ERROR,
+			   "Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
+		return -1;
+	}
+
+	/* Find the highest EDMG channel bandwidth to start the P2P GO */
+	for (i = 0; i < ARRAY_SIZE(chanwidth); i++) {
+		if (ieee80211_chaninfo_to_channel(freq, chanwidth[i], 0,
+						  op_class,
+						  op_edmg_channel) < 0)
+			continue;
+
+		hostapd_encode_edmg_chan(1, *op_edmg_channel, 0, &edmg);
+		if (edmg.channels &&
+		    ieee802_edmg_is_allowed(hwmode->edmg, edmg)) {
+			wpa_printf(MSG_DEBUG,
+				   "Freq %u to EDMG channel %u at opclass %u",
+				   freq, *op_edmg_channel, *op_class);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+			      struct p2p_go_neg_results *params)
+{
+	u8 op_channel, op_class;
+	int freq;
+
+	/* Try social channel as primary channel frequency */
+	freq = (!params->freq) ? 58320 + 1 * 2160 : params->freq;
+
+	if (wpas_p2p_freq_to_edmg_channel(wpa_s, freq, &op_class,
+					  &op_channel) == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "Freq %d will be used to set an EDMG connection (channel=%u opclass=%u)",
+			   freq, op_channel, op_class);
+		params->freq = freq;
+		return 0;
+	}
+
+	return -1;
+}
+
+
 static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
 			      struct p2p_go_neg_results *params,
 			      int group_formation)
@@ -1921,6 +1998,20 @@
 	ssid->max_oper_chwidth = params->max_oper_chwidth;
 	ssid->vht_center_freq2 = params->vht_center_freq2;
 	ssid->he = params->he;
+	if (params->edmg) {
+		u8 op_channel, op_class;
+
+		if (!wpas_p2p_freq_to_edmg_channel(wpa_s, params->freq,
+						   &op_class, &op_channel)) {
+			ssid->edmg_channel = op_channel;
+			ssid->enable_edmg = params->edmg;
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"P2P: Could not match EDMG channel, freq %d, for GO",
+				params->freq);
+		}
+	}
+
 	ssid->ssid = os_zalloc(params->ssid_len + 1);
 	if (ssid->ssid) {
 		os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -2270,6 +2361,8 @@
 		res->vht = 1;
 	if (wpa_s->p2p_go_he)
 		res->he = 1;
+	if (wpa_s->p2p_go_edmg)
+		res->edmg = 1;
 	res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
 	res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
 
@@ -3099,7 +3192,8 @@
 					       MAC2STR(sa), s->id);
 			}
 			wpas_p2p_group_add_persistent(
-				wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
+				wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0,
+				0, NULL,
 				go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
 				1);
 		} else if (bssid) {
@@ -3326,6 +3420,7 @@
 				      wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
 				      wpa_s->p2p_go_max_oper_chwidth,
 				      wpa_s->p2p_go_he,
+				      wpa_s->p2p_go_edmg,
 				      channels,
 				      ssid->mode == WPAS_MODE_P2P_GO ?
 				      P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3570,6 +3665,20 @@
 }
 
 
+static enum chan_allowed wpas_p2p_verify_edmg(struct wpa_supplicant *wpa_s,
+					      struct hostapd_hw_modes *mode,
+					      u8 channel)
+{
+	struct ieee80211_edmg_config edmg;
+
+	hostapd_encode_edmg_chan(1, channel, 0, &edmg);
+	if (edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+		return ALLOWED;
+
+	return NOT_ALLOWED;
+}
+
+
 static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
 						 struct hostapd_hw_modes *mode,
 						 u8 channel, u8 bw)
@@ -3590,6 +3699,8 @@
 		res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
 	} else if (bw == BW160) {
 		res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
+	} else if (bw == BW4320 || bw == BW6480 || bw == BW8640) {
+		return wpas_p2p_verify_edmg(wpa_s, mode, channel);
 	}
 
 	if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -4240,14 +4351,14 @@
 			if (response_done && persistent_go) {
 				wpas_p2p_group_add_persistent(
 					wpa_s, persistent_go,
-					0, 0, freq, 0, 0, 0, 0, 0, NULL,
+					0, 0, freq, 0, 0, 0, 0, 0, 0, NULL,
 					persistent_go->mode ==
 					WPAS_MODE_P2P_GO ?
 					P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
 					0, 0);
 			} else if (response_done) {
 				wpas_p2p_group_add(wpa_s, 1, freq,
-						   0, 0, 0, 0, 0);
+						   0, 0, 0, 0, 0, 0);
 			}
 
 			if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4363,11 +4474,12 @@
 
 	if (persistent_go) {
 		wpas_p2p_group_add_persistent(
-			wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
+			wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+			NULL,
 			persistent_go->mode == WPAS_MODE_P2P_GO ?
 			P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
 	} else {
-		wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0);
+		wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0);
 	}
 
 	return 1;
@@ -4950,6 +5062,7 @@
 					 wpa_s->p2p_go_vht,
 					 wpa_s->p2p_go_max_oper_chwidth,
 					 wpa_s->p2p_go_he,
+					 wpa_s->p2p_go_edmg,
 					 NULL, 0);
 			return;
 		}
@@ -5498,8 +5611,8 @@
 		     int persistent_group, int auto_join, int join, int auth,
 		     int go_intent, int freq, unsigned int vht_center_freq2,
 		     int persistent_id, int pd, int ht40, int vht,
-		     unsigned int vht_chwidth, int he, const u8 *group_ssid,
-		     size_t group_ssid_len)
+		     unsigned int vht_chwidth, int he, int edmg,
+		     const u8 *group_ssid, size_t group_ssid_len)
 {
 	int force_freq = 0, pref_freq = 0;
 	int ret = 0, res;
@@ -5544,6 +5657,7 @@
 	wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
 	wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
 	wpa_s->p2p_go_he = !!he;
+	wpa_s->p2p_go_edmg = !!edmg;
 
 	if (pin)
 		os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -5968,6 +6082,7 @@
 				   struct p2p_go_neg_results *params,
 				   int freq, int vht_center_freq2, int ht40,
 				   int vht, int max_oper_chwidth, int he,
+				   int edmg,
 				   const struct p2p_channels *channels)
 {
 	struct wpa_used_freq_data *freqs;
@@ -5983,6 +6098,7 @@
 	params->he = he;
 	params->max_oper_chwidth = max_oper_chwidth;
 	params->vht_center_freq2 = vht_center_freq2;
+	params->edmg = edmg;
 
 	freqs = os_calloc(wpa_s->num_multichan_concurrent,
 			  sizeof(struct wpa_used_freq_data));
@@ -6013,6 +6129,13 @@
 		}
 	}
 
+	/* Try to use EDMG channel */
+	if (params->edmg) {
+		if (wpas_p2p_try_edmg_channel(wpa_s, params) == 0)
+			goto success;
+		params->edmg = 0;
+	}
+
 	/* try using the forced freq */
 	if (freq) {
 		if (wpas_p2p_disallowed_freq(wpa_s->global, freq) ||
@@ -6330,6 +6453,7 @@
  * @ht40: Start GO with 40 MHz channel width
  * @vht:  Start GO with VHT support
  * @vht_chwidth: channel bandwidth for GO operating with VHT support
+ * @edmg: Start GO with EDMG support
  * Returns: 0 on success, -1 on failure
  *
  * This function creates a new P2P group with the local end as the Group Owner,
@@ -6337,7 +6461,7 @@
  */
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 		       int freq, int vht_center_freq2, int ht40, int vht,
-		       int max_oper_chwidth, int he)
+		       int max_oper_chwidth, int he, int edmg)
 {
 	struct p2p_go_neg_results params;
 
@@ -6358,7 +6482,8 @@
 	}
 
 	if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
-				    ht40, vht, max_oper_chwidth, he, NULL))
+				    ht40, vht, max_oper_chwidth, he, edmg,
+				    NULL))
 		return -1;
 
 	p2p_go_params(wpa_s->global->p2p, &params);
@@ -6438,6 +6563,7 @@
 				  int force_freq, int neg_freq,
 				  int vht_center_freq2, int ht40,
 				  int vht, int max_oper_chwidth, int he,
+				  int edmg,
 				  const struct p2p_channels *channels,
 				  int connection_timeout, int force_scan)
 {
@@ -6513,7 +6639,8 @@
 	}
 
 	if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
-				    ht40, vht, max_oper_chwidth, he, channels))
+				    ht40, vht, max_oper_chwidth, he, edmg,
+				    channels))
 		return -1;
 
 	params.role_go = 1;
@@ -7065,7 +7192,7 @@
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
 		    int vht_center_freq2, int ht40, int vht, int max_chwidth,
-		    int pref_freq, int he)
+		    int pref_freq, int he, int edmg)
 {
 	enum p2p_invite_role role;
 	u8 *bssid = NULL;
@@ -7086,6 +7213,7 @@
 	wpa_s->p2p_go_he = !!he;
 	wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
 	wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
+	wpa_s->p2p_go_edmg = !!edmg;
 	if (ssid->mode == WPAS_MODE_P2P_GO) {
 		role = P2P_INVITE_ROLE_GO;
 		if (peer_addr == NULL) {
@@ -7163,6 +7291,7 @@
 	wpa_s->p2p_go_vht = 0;
 	wpa_s->p2p_go_vht_center_freq2 = 0;
 	wpa_s->p2p_go_max_oper_chwidth = 0;
+	wpa_s->p2p_go_edmg = 0;
 
 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
 		if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -8108,7 +8237,9 @@
 			 wpa_s->p2p_go_ht40,
 			 wpa_s->p2p_go_vht,
 			 wpa_s->p2p_go_max_oper_chwidth,
-			 wpa_s->p2p_go_he, NULL, 0);
+			 wpa_s->p2p_go_he,
+			 wpa_s->p2p_go_edmg,
+			 NULL, 0);
 	return ret;
 }
 
@@ -8644,7 +8775,7 @@
 				WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
 				params->go_freq, wpa_s->p2p_go_vht_center_freq2,
 				-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
-				wpa_s->p2p_go_he,
+				wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
 				params->go_ssid_len ? params->go_ssid : NULL,
 				params->go_ssid_len);
 }
@@ -8724,7 +8855,8 @@
 				WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
 				forced_freq, wpa_s->p2p_go_vht_center_freq2,
 				-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
-				wpa_s->p2p_go_he, NULL, 0);
+				wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+				NULL, 0);
 }
 
 
@@ -8740,7 +8872,8 @@
 			       WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
 			       forced_freq, wpa_s->p2p_go_vht_center_freq2,
 			       -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
-			       wpa_s->p2p_go_he, NULL, 0);
+			       wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+			       NULL, 0);
 	if (res)
 		return res;
 
@@ -9125,7 +9258,8 @@
 	 * TODO: This function may not always work correctly. For example,
 	 * when we have a running GO and a BSS on a DFS channel.
 	 */
-	if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+	if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+				    NULL)) {
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"P2P CSA: Failed to select new frequency for GO");
 		return -1;
@@ -9237,7 +9371,8 @@
 	wpa_supplicant_ap_deinit(wpa_s);
 
 	/* Reselect the GO frequency */
-	if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+	if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+				    NULL)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
 		wpas_p2p_group_delete(wpa_s,
 				      P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 24ec2ca..941198e 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -37,18 +37,18 @@
 		     int persistent_group, int auto_join, int join, int auth,
 		     int go_intent, int freq, unsigned int vht_center_freq2,
 		     int persistent_id, int pd, int ht40, int vht,
-		     unsigned int vht_chwidth, int he, const u8 *group_ssid,
-		     size_t group_ssid_len);
+		     unsigned int vht_chwidth, int he, int edmg,
+		     const u8 *group_ssid, size_t group_ssid_len);
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
                                           int freq, struct wpa_ssid *ssid);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 		       int freq, int vht_center_freq2, int ht40, int vht,
-		       int max_oper_chwidth, int he);
+		       int max_oper_chwidth, int he, int edmg);
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid, int addr_allocated,
 				  int force_freq, int neg_freq,
-				  int vht_center_freq2, int ht40,
-				  int vht, int max_oper_chwidth, int he,
+				  int vht_center_freq2, int ht40, int vht,
+				  int max_oper_chwidth, int he, int edmg,
 				  const struct p2p_channels *channels,
 				  int connection_timeout, int force_scan);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
@@ -116,8 +116,8 @@
 int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-		    int vht_center_freq2, int ht40, int vht,
-		    int max_oper_chwidth, int pref_freq, int he);
+		    int vht_center_freq2, int ht40, int vht, int max_chwidth,
+		    int pref_freq, int he, int edmg);
 int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 			  const u8 *peer_addr, const u8 *go_dev_addr);
 int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
@@ -165,6 +165,8 @@
 				 const struct wpabuf *sel, int forced_freq);
 int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
 void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+			      struct p2p_go_neg_results *params);
 
 #ifdef CONFIG_P2P
 
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index b78ff10..7930e01 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -79,7 +79,7 @@
 			     NULL);
 
 	if (!wpa_s->rrm.notify_neighbor_rep) {
-		wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+		wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
 		return;
 	}
 
@@ -90,8 +90,8 @@
 		return;
 	}
 	wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
-	wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
-		   report[0]);
+	wpa_dbg(wpa_s, MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+		report[0]);
 	wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
 				       neighbor_rep);
 	wpa_s->rrm.notify_neighbor_rep = NULL;
@@ -148,12 +148,12 @@
 	const u8 *rrm_ie;
 
 	if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+		wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No connection, no RRM.");
 		return -ENOTCONN;
 	}
 
 	if (!wpa_s->rrm.rrm_used) {
-		wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+		wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No RRM in current connection.");
 		return -EOPNOTSUPP;
 	}
 
@@ -161,15 +161,15 @@
 				WLAN_EID_RRM_ENABLED_CAPABILITIES);
 	if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
 	    !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: No network support for Neighbor Report.");
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"RRM: No network support for Neighbor Report.");
 		return -EOPNOTSUPP;
 	}
 
 	/* Refuse if there's a live request */
 	if (wpa_s->rrm.notify_neighbor_rep) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Currently handling previous Neighbor Report.");
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"RRM: Currently handling previous Neighbor Report.");
 		return -EBUSY;
 	}
 
@@ -178,14 +178,15 @@
 			   (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
 			   (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
 	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Failed to allocate Neighbor Report Request");
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"RRM: Failed to allocate Neighbor Report Request");
 		return -ENOMEM;
 	}
 
-	wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
-		   (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
-		   wpa_s->rrm.next_neighbor_rep_token);
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"RRM: Neighbor report request (for %s), token=%d",
+		(ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+		wpa_s->rrm.next_neighbor_rep_token);
 
 	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
 	wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
@@ -267,8 +268,8 @@
 	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
 				wpa_s->own_addr, wpa_s->bssid,
 				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Failed to send Neighbor Report Request");
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"RRM: Failed to send Neighbor Report Request");
 		wpabuf_free(buf);
 		return -ECANCELED;
 	}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index cfb5bb3..08d7e3e 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -13,6 +13,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/ocv.h"
+#include "common/hw_features_common.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "common/wpa_common.h"
 #include "common/sae.h"
@@ -591,6 +592,18 @@
 		os_memcpy(pos, ext_capab, ext_capab_len);
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->rsnxe_override_assoc &&
+	    wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+	    sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+		wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+		os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+			  wpabuf_head(wpa_s->rsnxe_override_assoc),
+			  wpabuf_len(wpa_s->rsnxe_override_assoc));
+		wpa_s->sme.assoc_req_ie_len +=
+			wpabuf_len(wpa_s->rsnxe_override_assoc);
+	} else
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (wpa_s->rsnxe_len > 0 &&
 	    wpa_s->rsnxe_len <=
 	    sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
@@ -1263,7 +1276,7 @@
 		if (wpa_s->sme.sae.tmp &&
 		    sme_check_sae_rejected_groups(
 			    wpa_s,
-			    wpa_s->sme.sae.tmp->peer_rejected_groups) < 0)
+			    wpa_s->sme.sae.tmp->peer_rejected_groups))
 			return -1;
 
 		if (sae_process_commit(&wpa_s->sme.sae) < 0) {
@@ -2202,13 +2215,14 @@
 }
 
 
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res)
 {
-	struct wpa_bss *bss;
 	const u8 *ie;
-	u16 ht_cap;
 	u8 chan_list[P2P_MAX_CHANNELS], channel;
 	u8 num_channels = 0, num_intol = 0, i;
+	size_t j;
+	int pri_freq, sec_freq;
 
 	if (!wpa_s->sme.sched_obss_scan)
 		return 0;
@@ -2236,22 +2250,36 @@
 
 	os_memset(chan_list, 0, sizeof(chan_list));
 
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		/* Skip other band bss */
+	pri_freq = wpa_s->assoc_freq;
+
+	switch (wpa_s->sme.ht_sec_chan) {
+	case HT_SEC_CHAN_ABOVE:
+		sec_freq = pri_freq + 20;
+		break;
+	case HT_SEC_CHAN_BELOW:
+		sec_freq = pri_freq - 20;
+		break;
+	case HT_SEC_CHAN_UNKNOWN:
+	default:
+		wpa_msg(wpa_s, MSG_WARNING,
+			"Undefined secondary channel: drop OBSS scan results");
+		return 1;
+	}
+
+	for (j = 0; j < scan_res->num; j++) {
+		struct wpa_scan_res *bss = scan_res->res[j];
 		enum hostapd_hw_mode mode;
+		int res;
+
+		/* Skip other band bss */
 		mode = ieee80211_freq_to_chan(bss->freq, &channel);
 		if (mode != HOSTAPD_MODE_IEEE80211G &&
 		    mode != HOSTAPD_MODE_IEEE80211B)
 			continue;
 
-		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
-		ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
-		wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR
-			   " freq=%u chan=%u ht_cap=0x%x",
-			   MAC2STR(bss->bssid), bss->freq, channel, ht_cap);
-
-		if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
-			if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+		res = check_bss_coex_40mhz(bss, pri_freq, sec_freq);
+		if (res) {
+			if (res == 2)
 				num_intol++;
 
 			/* Check whether the channel is already considered */
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index 1a7f9e8..42d5a83 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -37,7 +37,8 @@
 void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
 void sme_deinit(struct wpa_supplicant *wpa_s);
 
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res);
 void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
 void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
 			       union wpa_event_data *data);
@@ -112,7 +113,8 @@
 {
 }
 
-static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+				     struct wpa_scan_results *scan_res)
 {
 	return 0;
 }
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 47cec0b..a1b0615 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -52,6 +52,7 @@
 static const char *global = NULL;
 static const char *pid_file = NULL;
 static const char *action_file = NULL;
+static int reconnect = 0;
 static int ping_interval = 5;
 static int interactive = 0;
 static char *ifname_prefix = NULL;
@@ -80,7 +81,7 @@
 
 static void usage(void)
 {
-	printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
+	printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvBr] "
 	       "[-a<action file>] \\\n"
 	       "        [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
 	       "\\\n"
@@ -91,6 +92,8 @@
 	       "  -a = run in daemon mode executing the action file based on "
 	       "events from\n"
 	       "       wpa_supplicant\n"
+	       "  -r = try to reconnect when client socket is disconnected.\n"
+	       "       This is useful only when used with -a.\n"
 	       "  -B = run a daemon in the background\n"
 	       "  default path: " CONFIG_CTRL_IFACE_DIR "\n"
 	       "  default interface: first interface found in socket path\n");
@@ -474,7 +477,7 @@
 		"p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
 		"p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
 		"p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
-		"ip_addr_start", "ip_addr_end",
+		"ip_addr_start", "ip_addr_end", "p2p_go_edmg",
 #endif /* CONFIG_P2P */
 		"country", "bss_max_count", "bss_expiration_age",
 		"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
@@ -1406,7 +1409,7 @@
 	"bssid_whitelist", "psk", "proto", "key_mgmt",
 	"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
 	"freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1",
-	"vht_center_freq2", "ht",
+	"vht_center_freq2", "ht", "edmg",
 #ifdef IEEE8021X_EAPOL
 	"eap", "identity", "anonymous_identity", "password", "ca_cert",
 	"ca_path", "client_cert", "private_key", "private_key_passwd",
@@ -4035,7 +4038,8 @@
 		wpa_cli_exec(action_file, ifname, pos);
 	} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
 		printf("wpa_supplicant is terminating - stop monitoring\n");
-		wpa_cli_quit = 1;
+		if (!reconnect)
+			wpa_cli_quit = 1;
 	}
 }
 
@@ -4227,6 +4231,10 @@
 	if (wpa_ctrl_pending(ctrl) < 0) {
 		printf("Connection to wpa_supplicant lost - trying to "
 		       "reconnect\n");
+		if (reconnect) {
+			eloop_terminate();
+			return;
+		}
 		wpa_cli_reconnect();
 	}
 }
@@ -4574,6 +4582,8 @@
 static void wpa_cli_terminate(int sig, void *ctx)
 {
 	eloop_terminate();
+	if (reconnect)
+		wpa_cli_quit = 1;
 }
 
 
@@ -4654,7 +4664,7 @@
 		return -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "a:Bg:G:hi:p:P:s:v");
+		c = getopt(argc, argv, "a:Bg:G:hi:p:P:rs:v");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -4686,6 +4696,9 @@
 		case 'P':
 			pid_file = optarg;
 			break;
+		case 'r':
+			reconnect = 1;
+			break;
 		case 's':
 			client_socket_dir = optarg;
 			break;
@@ -4711,7 +4724,22 @@
 	if (ctrl_ifname == NULL)
 		ctrl_ifname = wpa_cli_get_default_ifname();
 
-	if (interactive) {
+	if (reconnect && action_file && ctrl_ifname) {
+		while (!wpa_cli_quit) {
+			if (ctrl_conn)
+				wpa_cli_action(ctrl_conn);
+			else
+				os_sleep(1, 0);
+			wpa_cli_close_connection();
+			wpa_cli_open_connection(ctrl_ifname, 0);
+			if (ctrl_conn) {
+				if (wpa_ctrl_attach(ctrl_conn) != 0)
+					wpa_cli_close_connection();
+				else
+					wpa_cli_attached = 1;
+			}
+		}
+	} else if (interactive) {
 		wpa_cli_interactive();
 	} else {
 		if (!global &&
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index adca1cc..538997e 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -31,9 +31,9 @@
 	if (argc > 2) {
 		passphrase = argv[2];
 	} else {
-		printf("# reading passphrase from stdin\n");
+		fprintf(stderr, "# reading passphrase from stdin\n");
 		if (fgets(buf, sizeof(buf), stdin) == NULL) {
-			printf("Failed to read passphrase\n");
+			fprintf(stderr, "Failed to read passphrase\n");
 			return 1;
 		}
 		buf[sizeof(buf) - 1] = '\0';
@@ -50,11 +50,11 @@
 
 	len = os_strlen(passphrase);
 	if (len < 8 || len > 63) {
-		printf("Passphrase must be 8..63 characters\n");
+		fprintf(stderr, "Passphrase must be 8..63 characters\n");
 		return 1;
 	}
 	if (has_ctrl_char((u8 *) passphrase, len)) {
-		printf("Invalid passphrase character\n");
+		fprintf(stderr, "Invalid passphrase character\n");
 		return 1;
 	}
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e14bffd..73e63ab 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -500,6 +500,12 @@
 	wpa_s->get_pref_freq_list_override = NULL;
 	wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
 	wpa_s->last_assoc_req_wpa_ie = NULL;
+	os_free(wpa_s->extra_sae_rejected_groups);
+	wpa_s->extra_sae_rejected_groups = NULL;
+	wpabuf_free(wpa_s->rsnxe_override_assoc);
+	wpa_s->rsnxe_override_assoc = NULL;
+	wpabuf_free(wpa_s->rsnxe_override_eapol);
+	wpa_s->rsnxe_override_eapol = NULL;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	if (wpa_s->conf != NULL) {
@@ -1973,6 +1979,28 @@
 }
 
 
+static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
+{
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+	os_free(wpa_s->sme.sae_rejected_groups);
+	wpa_s->sme.sae_rejected_groups = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->extra_sae_rejected_groups) {
+		int i, *groups = wpa_s->extra_sae_rejected_groups;
+
+		for (i = 0; groups[i]; i++) {
+			wpa_printf(MSG_DEBUG,
+				   "TESTING: Indicate rejection of an extra SAE group %d",
+				   groups[i]);
+			int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+					     groups[i]);
+		}
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE && CONFIG_SME */
+}
+
+
 static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
 
 /**
@@ -2021,10 +2049,7 @@
 		}
 	} else {
 #ifdef CONFIG_SAE
-#ifdef CONFIG_SME
-		os_free(wpa_s->sme.sae_rejected_groups);
-		wpa_s->sme.sae_rejected_groups = NULL;
-#endif /* CONFIG_SME */
+		wpa_s_clear_sae_rejected(wpa_s);
 		wpa_s_setup_sae_pt(wpa_s->conf, ssid);
 #endif /* CONFIG_SAE */
 	}
@@ -2358,8 +2383,7 @@
 			return;
 		}
 
-		res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
-				     sec_chan->chan);
+		res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
 		switch (res) {
 		case 0:
 			/* Back to HT20 */
@@ -3006,6 +3030,17 @@
 	}
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->rsnxe_override_assoc &&
+	    wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+	    max_wpa_ie_len - wpa_ie_len) {
+		wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+		os_memcpy(wpa_ie + wpa_ie_len,
+			  wpabuf_head(wpa_s->rsnxe_override_assoc),
+			  wpabuf_len(wpa_s->rsnxe_override_assoc));
+		wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
+	} else
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (wpa_s->rsnxe_len > 0 &&
 	    wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
 		os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
@@ -4040,10 +4075,7 @@
 
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
-#if defined(CONFIG_SAE) && defined(CONFIG_SME)
-	os_free(wpa_s->sme.sae_rejected_groups);
-	wpa_s->sme.sae_rejected_groups = NULL;
-#endif /* CONFIG_SAE && CONFIG_SME */
+	wpa_s_clear_sae_rejected(wpa_s);
 	wpa_s->last_owe_group = 0;
 	if (ssid) {
 		ssid->owe_transition_bss_select_count = 0;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index ba511b9..328f91a 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -955,7 +955,8 @@
 # management frames) certification program are:
 # PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
 # PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
-# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+# WPA3-Personal-only mode: ieee80211w=2 and key_mgmt=SAE
 #
 # ocv: whether operating channel validation is enabled
 # This is a countermeasure against multi-channel man-in-the-middle attacks.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index b6fb491..dcc2a6d 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -931,6 +931,7 @@
 	unsigned int p2p_pd_before_go_neg:1;
 	unsigned int p2p_go_ht40:1;
 	unsigned int p2p_go_vht:1;
+	unsigned int p2p_go_edmg:1;
 	unsigned int p2p_go_he:1;
 	unsigned int user_initiated_pd:1;
 	unsigned int p2p_go_group_formation_completed:1;
@@ -1123,6 +1124,7 @@
 	unsigned int ignore_auth_resp:1;
 	unsigned int ignore_assoc_disallow:1;
 	unsigned int testing_resend_assoc:1;
+	unsigned int ignore_sae_h2e_only:1;
 	struct wpabuf *sae_commit_override;
 	enum wpa_alg last_tk_alg;
 	u8 last_tk_addr[ETH_ALEN];
@@ -1130,6 +1132,9 @@
 	u8 last_tk[WPA_TK_MAX_LEN];
 	size_t last_tk_len;
 	struct wpabuf *last_assoc_req_wpa_ie;
+	int *extra_sae_rejected_groups;
+	struct wpabuf *rsnxe_override_assoc;
+	struct wpabuf *rsnxe_override_eapol;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1232,7 +1237,7 @@
 	unsigned int dpp_listen_freq;
 	u8 dpp_allowed_roles;
 	int dpp_qr_mutual;
-	int dpp_netrole_ap;
+	int dpp_netrole;
 	int dpp_auth_ok_on_ack;
 	int dpp_in_response_listen;
 	int dpp_gas_client;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index f51340f..8387fc3 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1178,6 +1178,11 @@
 				/* P2P in 60 GHz uses PBSS */
 				ssid->pbss = 1;
 			}
+			if (wpa_s->go_params->edmg &&
+			    wpas_p2p_try_edmg_channel(wpa_s,
+						      wpa_s->go_params) == 0)
+				ssid->enable_edmg = 1;
+
 			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
 					  "SSID", ssid->ssid, ssid->ssid_len);
 		}
@@ -1261,6 +1266,11 @@
 				/* P2P in 60 GHz uses PBSS */
 				ssid->pbss = 1;
 			}
+			if (wpa_s->go_params->edmg &&
+			    wpas_p2p_try_edmg_channel(wpa_s,
+						      wpa_s->go_params) == 0)
+				ssid->enable_edmg = 1;
+
 			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
 					  "SSID", ssid->ssid, ssid->ssid_len);
 		}
@@ -1284,6 +1294,10 @@
 		wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
 		return -1;
 	}
+
+	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER)
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_PIN_ACTIVE);
+
 	if (wpa_s->wps_fragment_size)
 		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
@@ -1349,6 +1363,7 @@
 			wpas_clear_wps(wpa_s);
 	}
 
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
 	wpa_s->after_wps = 0;
 
 	return 0;