[wpa_supplicant] Cumulative patch from commit dd2daf084

Bug: 156933657
Test: Confirm random dialog token usage from logs
Test: Verify Passpoint ANQP functionality and Passpoint association
Test: act.py -c ../WifiDppConfig.json -tc WifiDppTest
Test: Connect to Passpoint, Open, WPA2, WPA3 networks and run traffic
Test: Regression test passed (Bug: 156969218)

dd2daf084 HE: Process HE 6 GHz band capab from associating HE STA
db603634a HE: Add 6 GHz Band Capabilities element in Beacon and response frames
88911a0aa HE: Add HE 6 GHz Band Capabilities into ieee802_11_parse_elems()
b2c0b83c6 HE: Remove VHT Operation Information from HE Operation element
e297a5bfd HE: Define 6 GHz band capability elements
39f29f250 defconfig: Enable TDLS
025ab330b ACS: Channel selection based freqlist
4ae3f3972 Add a helper function for recognizing BIP enum wpa_alg values
d3cab56c0 Rename WPA_ALG_IGTK to use the correct cipher name for BIP
bd1aebbd0 hostapd: Extend RESET_PN for BIGTK
df49c53f4 Fix a typo in a comment
4294d221d D-Bus: Increase introspection buffer size
79488da57 wolfssl: Do not hardcode include directory in wpa_supplicant build
eb595b3e3 wolfssl: Fix crypto_bignum_rand() implementation
6a28c4dbc wolfssl: Fix compiler warnings on size_t printf format use
f2dbaa8ac SAE: Fix a typo in a comment
038899290 wpa_gui: Fix build with Inkscape 1.0
3e1a13010 nl80211: Change AKM suite limit from warning to debug print
5a04a76aa Ignore Management frames while AP interface is not fully enabled
c82535edd Move deauthentication at AP start to be after beacon configuration
094c8a621 Remove unnecessary key clearing at AP start with nl80211
04030e8c0 nl80211: Remove AP mode interface from bridge for STA-mode-scan
7adea21d2 dpp-nfc: Enable hostapd beaconing for listen state
134ad50b0 dpp-nfc: Clean up debug prints when handover select is received
5d49c1bf7 dpp-nfc: Do not indicate a single channel 1 by default
d0e2d8091 dpp-nfc: Make handover request collision detection more robust
8791e7461 dpp-nfc: Write debug info to summary log
1e0bc897a dpp-nfc: Collision detection for handover request
9ad3fe934 dpp-nfc: Start handover server regardless of init-on-touch setting
24efcdf74 dpp-nfc: Own MAC address fetching from hostapd
8f96f2c3b dpp-nfc: Be more graceful when wpa_supplicant is not available
0b04d3c57 dpp-nfc: Allow wpa_supplicant control interface directory to be set
69dfbe6a9 dpp-nfc: Use Configurator/Enrollee parameters with tag reading
f85fb349f dpp-nfc: More robust determination of the script directory
98e4b3840 DPP2: Chirping in hostapd Enrollee
95471fc3e Handle hostapd_for_each_interface() at the process termination
99809c7a4 nl80211: Disable offchannel-ok in AP mode only if beaconing
0f58c88fc DPP2: Fix CONFIG_DPP2=y build with OpenSSL 1.0.2
44f786678 Clean up GET_CAPABILITY handling of 'strict' argument
3790f3a6e Use per-interface type driver key_mgmt capabilities when possible
8d7502809 Allow per interface type AKM capabilities to be fetched
b67bedf2e nl80211: Fetch information on supported AKMs from the driver
6fffb320f nl80211: Remove QCA vendor specific AKM capability handling
db59827a3 DPP2: Extend TCP encapsulation case to support Configurator as Initiator
0086c1452 DPP: Extend NFC bootstrapping script for more control by caller
890ae336c DPP2: Clean up CONFIG_DPP2 use with configurator connectivity IE
670e15337 DPP2: Fix DPP_CHIRP listen parameter value validation
7f20a3ebd DPP2: Reconfiguration support in Controller
6dcb8aaf1 DPP2: Reconfig Announcement relaying from AP to Controller
3b4f7dfaa DPP2: Fix Presence Announcement processing in Controller
5e2d877cc DPP: Mark internal-to-file functions static
3aaf269f6 DPP: Move TCP encapsulation into a separate source code file
21c612017 DPP: Move configurator backup into a separate source code file
fdbbb7406 DPP: Move authentication functionality into a separate source code file
182f6ae90 DPP2: Remove reconfigured network
3e48c5d4b DPP2: Reconfig Authentication Confirm processing
24b01c706 DPP2: Reconfig Authentication Response processing and Confirm generation
65e94351d DPP2: Reconfig Authentication Request processing and Response generation
3774b6bd0 DPP2: Reconfig Authentication Request generation and transmission
66ac616cd DPP2: Process received Reconfig Announcement frame
0c043d9de DPP2: Reconfig Announcement transmission
92492dd3a DPP2: Extend connector matching for reconfiguration
961435097 DPP2: Move connStatus object building into a helper function
94f73f90e DPP: Move signed connector checking into a helper function
94a28a494 DPP: Move parsing of own connector into a helper function
d4ae12355 DPP: Move PKEX functionality into a separate source code file
87b657261 DPP: Move crypto routines into a separate source code file
16626dff9 DPP2: Derive bk ("base key")
76029c6e1 DPP: Use EVP_PKEY_get0_EC_KEY() when a const reference is sufficient
0a488ef35 DPP: Track ending time for remain-on-channel operations
481fdfc46 DPP2: Fix URI version parser
7dd768c3c DPP2: Version information in bootstrapping info URI
cbafc8ef4 Fix truncated control interface command detection
5a0718a19 DPP2: Report MUD URL and bandSupport in control interface events
769139c49 DPP2: Do not include Protocol Version in Auth Req when testing v1
fad64b416 DPP: Move dppCon signing to a set of helper functions
12c8eacf7 DPP: Allow version number to be overridden for testing purposes
c3c38bc8b DPP2: Detect PFS downgrade attack while processing EAPOL-Key msg 3/4
9561925b4 DPP2: Detect PFS downgrade attack while processing EAPOL-Key msg 2/4
68422fedb DPP2: Parse DPP KDE in EAPOL-Key Key Data field
143e3d8bc DPP2: Add DPP KDE into EAPOL-Key msg 2/4 when using DPP AKM
b11a12401 DPP2: Add DPP KDE into EAPOL-Key msg 3/4 when using DPP AKM
85d545699 DPP2: Indicate if PFS was used in control interface STATUS
1f5f00008 DPP2: Try to negotiate PFS only if AP supports version 2 or newer
f6c22dcde Use a local pointer to simply current_ssid accesses in sme_associate()
42acf1292 DPP2: Add Protocol Version attribute to network introduction messages
96b6dd21a Increase wpa_supplicant control interface buffer size
a7d6098fb Add PRINTF_FORMAT for printf wrapper functions

Change-Id: I26a15ac578ce81d1e35f426085661e5c7b43b6ef
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 37432d9..8631775 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -277,6 +277,12 @@
 ifdef CONFIG_DPP
 L_CFLAGS += -DCONFIG_DPP
 OBJS += src/common/dpp.c
+OBJS += src/common/dpp_auth.c
+OBJS += src/common/dpp_backup.c
+OBJS += src/common/dpp_crypto.c
+OBJS += src/common/dpp_pkex.c
+OBJS += src/common/dpp_reconfig.c
+OBJS += src/common/dpp_tcp.c
 OBJS += dpp_supplicant.c
 NEED_AES_SIV=y
 NEED_HMAC_SHA256_KDF=y
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 738b0bd..b35d11e 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -279,6 +279,12 @@
 ifdef CONFIG_DPP
 CFLAGS += -DCONFIG_DPP
 OBJS += ../src/common/dpp.o
+OBJS += ../src/common/dpp_auth.o
+OBJS += ../src/common/dpp_backup.o
+OBJS += ../src/common/dpp_crypto.o
+OBJS += ../src/common/dpp_pkex.o
+OBJS += ../src/common/dpp_reconfig.o
+OBJS += ../src/common/dpp_tcp.o
 OBJS += dpp_supplicant.o
 NEED_AES_SIV=y
 NEED_HMAC_SHA256_KDF=y
@@ -1075,7 +1081,7 @@
 
 ifeq ($(CONFIG_TLS), wolfssl)
 ifdef TLS_FUNCS
-CFLAGS += -DWOLFSSL_DER_LOAD -I/usr/local/include/wolfssl
+CFLAGS += -DWOLFSSL_DER_LOAD
 OBJS += ../src/crypto/tls_wolfssl.o
 endif
 OBJS += ../src/crypto/crypto_wolfssl.o
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e0547f1..1507c48 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -696,6 +696,8 @@
 			ret = -1;
 		else
 			dpp_nonce_override_len = hex_len / 2;
+	} else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
+		dpp_version_override = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_DPP */
 #ifdef CONFIG_TESTING_OPTIONS
@@ -891,6 +893,8 @@
 
 	if (os_strcmp(cmd, "version") == 0) {
 		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+	} else if (os_strcasecmp(cmd, "max_command_len") == 0) {
+		res = os_snprintf(buf, buflen, "%u", CTRL_IFACE_MAX_LEN);
 	} else if (os_strcasecmp(cmd, "country") == 0) {
 		if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
 			res = os_snprintf(buf, buflen, "%c%c",
@@ -3977,7 +3981,7 @@
 };
 
 
-static int ctrl_iface_get_capability_pairwise(int res, char *strict,
+static int ctrl_iface_get_capability_pairwise(int res, bool strict,
 					      struct wpa_driver_capa *capa,
 					      char *buf, size_t buflen)
 {
@@ -4017,7 +4021,7 @@
 }
 
 
-static int ctrl_iface_get_capability_group(int res, char *strict,
+static int ctrl_iface_get_capability_group(int res, bool strict,
 					   struct wpa_driver_capa *capa,
 					   char *buf, size_t buflen)
 {
@@ -4065,7 +4069,7 @@
 }
 
 
-static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
+static int ctrl_iface_get_capability_group_mgmt(int res, bool strict,
 						struct wpa_driver_capa *capa,
 						char *buf, size_t buflen)
 {
@@ -4094,11 +4098,49 @@
 }
 
 
-static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
+static int iftype_str_to_index(const char *iftype_str)
+{
+	if (!iftype_str)
+		return WPA_IF_MAX;
+
+	if (os_strcmp(iftype_str, "STATION") == 0)
+		return WPA_IF_STATION;
+
+	if (os_strcmp(iftype_str, "AP_VLAN") == 0)
+		return WPA_IF_AP_VLAN;
+
+	if (os_strcmp(iftype_str, "AP") == 0)
+		return WPA_IF_AP_BSS;
+
+	if (os_strcmp(iftype_str, "P2P_GO") == 0)
+		return WPA_IF_P2P_GO;
+
+	if (os_strcmp(iftype_str, "P2P_CLIENT") == 0)
+		return WPA_IF_P2P_CLIENT;
+
+	if (os_strcmp(iftype_str, "P2P_DEVICE") == 0)
+		return WPA_IF_P2P_DEVICE;
+
+	if (os_strcmp(iftype_str, "MESH") == 0)
+		return WPA_IF_MESH;
+
+	if (os_strcmp(iftype_str, "IBSS") == 0)
+		return WPA_IF_IBSS;
+
+	if (os_strcmp(iftype_str, "NAN") == 0)
+		return WPA_IF_NAN;
+
+	return WPA_IF_MAX;
+}
+
+
+static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
 					      struct wpa_driver_capa *capa,
+					      const char *iftype_str,
 					      char *buf, size_t buflen)
 {
 	int ret;
+	unsigned int key_mgmt;
 	char *pos, *end;
 	size_t len;
 
@@ -4115,28 +4157,39 @@
 		return len;
 	}
 
+	if (iftype_str) {
+		enum wpa_driver_if_type iftype;
+
+		iftype = iftype_str_to_index(iftype_str);
+		if (iftype == WPA_IF_MAX)
+			return -1;
+		key_mgmt = capa->key_mgmt_iftype[iftype];
+	} else {
+		key_mgmt = capa->key_mgmt;
+	}
+
 	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
 	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
-	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+	if (key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+			WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
 		ret = os_snprintf(pos, end - pos, " WPA-EAP");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 
-	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+	if (key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+			WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
 		ret = os_snprintf(pos, end - pos, " WPA-PSK");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
 		ret = os_snprintf(pos, end - pos, " WPA-NONE");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4144,7 +4197,7 @@
 	}
 
 #ifdef CONFIG_SUITEB
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
 		ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4152,7 +4205,7 @@
 	}
 #endif /* CONFIG_SUITEB */
 #ifdef CONFIG_SUITEB192
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
 		ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4160,7 +4213,7 @@
 	}
 #endif /* CONFIG_SUITEB192 */
 #ifdef CONFIG_OWE
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
 		ret = os_snprintf(pos, end - pos, " OWE");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4168,7 +4221,7 @@
 	}
 #endif /* CONFIG_OWE */
 #ifdef CONFIG_DPP
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
 		ret = os_snprintf(pos, end - pos, " DPP");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4176,26 +4229,26 @@
 	}
 #endif /* CONFIG_DPP */
 #ifdef CONFIG_FILS
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
 		ret = os_snprintf(pos, end - pos, " FILS-SHA256");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
 		ret = os_snprintf(pos, end - pos, " FILS-SHA384");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 #ifdef CONFIG_IEEE80211R
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
 		ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
 		ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4204,7 +4257,7 @@
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
 		ret = os_snprintf(pos, end - pos, " FT-PSK");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4212,7 +4265,7 @@
 	}
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_SAE
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
+	if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
 		ret = os_snprintf(pos, end - pos, " SAE");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
@@ -4224,7 +4277,7 @@
 }
 
 
-static int ctrl_iface_get_capability_proto(int res, char *strict,
+static int ctrl_iface_get_capability_proto(int res, bool strict,
 					   struct wpa_driver_capa *capa,
 					   char *buf, size_t buflen)
 {
@@ -4267,7 +4320,7 @@
 
 
 static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
-					      int res, char *strict,
+					      int res, bool strict,
 					      struct wpa_driver_capa *capa,
 					      char *buf, size_t buflen)
 {
@@ -4345,7 +4398,7 @@
 }
 
 
-static int ctrl_iface_get_capability_modes(int res, char *strict,
+static int ctrl_iface_get_capability_modes(int res, bool strict,
 					   struct wpa_driver_capa *capa,
 					   char *buf, size_t buflen)
 {
@@ -4508,23 +4561,36 @@
 {
 	struct wpa_driver_capa capa;
 	int res;
-	char *strict;
-	char field[30];
+	char *next_param, *curr_param, *iftype = NULL;
+	bool strict = false;
+	char field[50];
 	size_t len;
 
 	/* Determine whether or not strict checking was requested */
 	len = os_strlcpy(field, _field, sizeof(field));
 	if (len >= sizeof(field))
 		return -1;
-	strict = os_strchr(field, ' ');
-	if (strict != NULL) {
-		*strict++ = '\0';
-		if (os_strcmp(strict, "strict") != 0)
+
+	next_param = os_strchr(field, ' ');
+	while (next_param) {
+		*next_param++ = '\0';
+		curr_param = next_param;
+		next_param = os_strchr(next_param, ' ');
+
+		if (next_param)
+			*next_param = '\0';
+
+		if (os_strcmp(curr_param, "strict") == 0)
+			strict = true;
+		else if (os_strncmp(curr_param, "iftype=", 7) == 0)
+			iftype = curr_param + 7;
+		else
 			return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
-		field, strict ? strict : "");
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'%s%s%s",
+		   field, iftype ? " iftype=" : "", iftype ? iftype : "",
+		   strict ? " strict" : "");
 
 	if (os_strcmp(field, "eap") == 0) {
 		return eap_get_names(buf, buflen);
@@ -4546,7 +4612,7 @@
 
 	if (os_strcmp(field, "key_mgmt") == 0)
 		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
-							  buf, buflen);
+							  iftype, buf, buflen);
 
 	if (os_strcmp(field, "proto") == 0)
 		return ctrl_iface_get_capability_proto(res, strict, &capa,
@@ -8158,6 +8224,11 @@
 	dpp_pkex_ephemeral_key_override_len = 0;
 	dpp_protocol_key_override_len = 0;
 	dpp_nonce_override_len = 0;
+#ifdef CONFIG_DPP2
+	dpp_version_override = 2;
+#else /* CONFIG_DPP2 */
+	dpp_version_override = 1;
+#endif /* CONFIG_DPP2 */
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_DPP */
 
@@ -11004,6 +11075,12 @@
 			reply_len = -1;
 	} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
 		wpas_dpp_chirp_stop(wpa_s);
+	} else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) {
+		struct wpa_ssid *ssid;
+
+		ssid = wpa_config_get_network(wpa_s->conf, atoi(buf + 13));
+		if (!ssid || wpas_dpp_reconfig(wpa_s, ssid) < 0)
+			reply_len = -1;
 #endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
 	} else {
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index d54cc07..510668d 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,10 @@
 
 #ifdef CONFIG_CTRL_IFACE
 
+#ifndef CTRL_IFACE_MAX_LEN
+#define CTRL_IFACE_MAX_LEN 8192
+#endif /* CTRL_IFACE_MAX_LEN */
+
 /* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */
 
 /**
diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c
index 9c0a47e..79ff787 100644
--- a/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -45,7 +45,7 @@
 
 /* Per-interface ctrl_iface */
 
-#define REQUEST_BUFSIZE 256
+#define REQUEST_BUFSIZE CTRL_IFACE_MAX_LEN
 #define REPLY_BUFSIZE 4096
 
 struct ctrl_iface_priv;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 1e92b97..1512080 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -219,7 +219,7 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct ctrl_iface_priv *priv = sock_ctx;
-	char buf[4096], *pos;
+	char *buf, *pos;
 	int res;
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
 	struct sockaddr_in6 from;
@@ -235,11 +235,15 @@
 	int new_attached = 0;
 	u8 cookie[COOKIE_LEN];
 
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+	if (!buf)
+		return;
+	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
 			   strerror(errno));
+		os_free(buf);
 		return;
 	}
 
@@ -249,6 +253,8 @@
 	if (os_strcmp(addr, "::1")) {
 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
 			   addr);
+		os_free(buf);
+		return;
 	}
 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
@@ -260,11 +266,17 @@
 		 */
 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
 			   "source %s", inet_ntoa(from.sin_addr));
+		os_free(buf);
 		return;
 	}
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
+	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+		os_free(buf);
+		return;
+	}
 	buf[res] = '\0';
 
 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -282,18 +294,21 @@
 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
 			   "drop request");
+		os_free(buf);
 		return;
 	}
 
 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
 			   "request - drop request");
+		os_free(buf);
 		return;
 	}
 
 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
 			   "drop request");
+		os_free(buf);
 		return;
 	}
 
@@ -339,6 +354,8 @@
 		       fromlen);
 	}
 
+	os_free(buf);
+
 	if (new_attached)
 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
 }
@@ -600,10 +617,13 @@
 {
 	struct wpa_global *global = eloop_ctx;
 	struct ctrl_iface_global_priv *priv = sock_ctx;
-	char buf[4096], *pos;
+	char *buf, *pos;
 	int res;
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
 	struct sockaddr_in6 from;
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+	char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 	struct sockaddr_in from;
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -612,16 +632,28 @@
 	size_t reply_len;
 	u8 cookie[COOKIE_LEN];
 
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+	if (!buf)
+		return;
+	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
 			   strerror(errno));
+		os_free(buf);
 		return;
 	}
 
 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
-#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+	inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
+	if (os_strcmp(addr, "::1")) {
+		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
+			   addr);
+		os_free(buf);
+		return;
+	}
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
 		/*
 		 * The OS networking stack is expected to drop this kind of
@@ -631,11 +663,17 @@
 		 */
 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
 			   "source %s", inet_ntoa(from.sin_addr));
+		os_free(buf);
 		return;
 	}
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
+	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+		os_free(buf);
+		return;
+	}
 	buf[res] = '\0';
 
 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -646,18 +684,21 @@
 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
 			   "drop request");
+		os_free(buf);
 		return;
 	}
 
 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
 			   "request - drop request");
+		os_free(buf);
 		return;
 	}
 
 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
 			   "drop request");
+		os_free(buf);
 		return;
 	}
 
@@ -694,6 +735,8 @@
 		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
 		       fromlen);
 	}
+
+	os_free(buf);
 }
 
 
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 71fe7ed..953fd2c 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -131,7 +131,7 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct ctrl_iface_priv *priv = sock_ctx;
-	char buf[4096];
+	char *buf;
 	int res;
 	struct sockaddr_storage from;
 	socklen_t fromlen = sizeof(from);
@@ -139,11 +139,20 @@
 	size_t reply_len = 0;
 	int new_attached = 0;
 
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+	if (!buf)
+		return;
+	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
 			   strerror(errno));
+		os_free(buf);
+		return;
+	}
+	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+		os_free(buf);
 		return;
 	}
 	buf[res] = '\0';
@@ -221,6 +230,7 @@
 		}
 	}
 	os_free(reply_buf);
+	os_free(buf);
 
 	if (new_attached)
 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -1046,18 +1056,27 @@
 {
 	struct wpa_global *global = eloop_ctx;
 	struct ctrl_iface_global_priv *priv = sock_ctx;
-	char buf[4096];
+	char *buf;
 	int res;
 	struct sockaddr_storage from;
 	socklen_t fromlen = sizeof(from);
 	char *reply = NULL, *reply_buf = NULL;
 	size_t reply_len;
 
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+	if (!buf)
+		return;
+	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
 			   strerror(errno));
+		os_free(buf);
+		return;
+	}
+	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+		os_free(buf);
 		return;
 	}
 	buf[res] = '\0';
@@ -1105,6 +1124,7 @@
 		}
 	}
 	os_free(reply_buf);
+	os_free(buf);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index aee105b..6c721bf 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -257,7 +257,7 @@
 	DBusMessage *reply;
 	struct wpabuf *xml;
 
-	xml = wpabuf_alloc(20000);
+	xml = wpabuf_alloc(30000);
 	if (xml == NULL)
 		return NULL;
 
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index c570775..7e06fdd 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -506,7 +506,7 @@
 CONFIG_P2P=y
 
 # Enable TDLS support
-#CONFIG_TDLS=y
+CONFIG_TDLS=y
 
 # Wi-Fi Display
 # This can be used to enable Wi-Fi Display extensions for P2P using an external
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 6dfa2e5..8c2e302 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -46,6 +46,10 @@
 			const u8 *src, const u8 *bssid,
 			const u8 *data, size_t data_len,
 			enum offchannel_send_action_result result);
+#ifdef CONFIG_DPP2
+static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+						 void *timeout_ctx);
+#endif /* CONFIG_DPP2 */
 
 static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -247,6 +251,35 @@
 
 #ifdef CONFIG_DPP2
 
+static void wpas_dpp_stop_listen_for_tx(struct wpa_supplicant *wpa_s,
+					unsigned int freq,
+					unsigned int wait_time)
+{
+	struct os_reltime now, res;
+	unsigned int remaining;
+
+	if (!wpa_s->dpp_listen_freq)
+		return;
+
+	os_get_reltime(&now);
+	if (os_reltime_before(&now, &wpa_s->dpp_listen_end)) {
+		os_reltime_sub(&wpa_s->dpp_listen_end, &now, &res);
+		remaining = res.sec * 1000 + res.usec / 1000;
+	} else {
+		remaining = 0;
+	}
+	if (wpa_s->dpp_listen_freq == freq && remaining > wait_time)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Stop listen on %u MHz ending in %u ms to allow immediate TX on %u MHz for %u ms",
+		   wpa_s->dpp_listen_freq, remaining, freq, wait_time);
+	wpas_dpp_listen_stop(wpa_s);
+
+	/* TODO: Restart listen in some cases after TX? */
+}
+
+
 static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
 						void *timeout_ctx)
 {
@@ -435,6 +468,10 @@
 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
 				     NULL);
+#ifdef CONFIG_DPP2
+		eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+				     wpa_s, NULL);
+#endif /* CONFIG_DPP2 */
 		offchannel_send_action_done(wpa_s);
 		dpp_auth_deinit(wpa_s->dpp_auth);
 		wpa_s->dpp_auth = NULL;
@@ -769,6 +806,10 @@
 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
 		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
 				     NULL);
+#ifdef CONFIG_DPP2
+		eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+				     wpa_s, NULL);
+#endif /* CONFIG_DPP2 */
 		offchannel_send_action_done(wpa_s);
 		dpp_auth_deinit(wpa_s->dpp_auth);
 		wpa_s->dpp_auth = NULL;
@@ -941,6 +982,24 @@
 }
 
 
+void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				   unsigned int freq, unsigned int duration)
+{
+	if (wpa_s->dpp_listen_freq != freq)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Remain-on-channel started for listen on %u MHz for %u ms",
+		   freq, duration);
+	os_get_reltime(&wpa_s->dpp_listen_end);
+	wpa_s->dpp_listen_end.usec += duration * 1000;
+	while (wpa_s->dpp_listen_end.usec >= 1000000) {
+		wpa_s->dpp_listen_end.sec++;
+		wpa_s->dpp_listen_end.usec -= 1000000;
+	}
+}
+
+
 void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 					  unsigned int freq)
 {
@@ -1080,7 +1139,8 @@
 
 		res = wpa_drv_get_capa(wpa_s, &capa);
 		if (res == 0 &&
-		    !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+		    !(capa.key_mgmt_iftype[WPA_IF_STATION] &
+		      WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
 		    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
 			wpa_printf(MSG_DEBUG,
 				   "DPP: SAE not supported by the driver");
@@ -1204,6 +1264,20 @@
 static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
 					 struct dpp_authentication *auth)
 {
+#ifdef CONFIG_DPP2
+	if (auth->reconfig && wpa_s->dpp_reconfig_ssid &&
+	    wpa_config_get_network(wpa_s->conf, wpa_s->dpp_reconfig_ssid_id) ==
+	    wpa_s->dpp_reconfig_ssid) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Remove reconfigured network profile");
+		wpas_notify_network_removed(wpa_s, wpa_s->dpp_reconfig_ssid);
+		wpa_config_remove_network(wpa_s->conf,
+					  wpa_s->dpp_reconfig_ssid_id);
+		wpa_s->dpp_reconfig_ssid = NULL;
+		wpa_s->dpp_reconfig_ssid_id = -1;
+	}
+#endif /* CONFIG_DPP2 */
+
 	if (wpa_s->conf->dpp_config_processing < 2)
 		return;
 
@@ -1321,7 +1395,8 @@
 
 	wpa_s->dpp_gas_dialog_token = -1;
 
-	if (!auth || !auth->auth_success) {
+	if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
+	    os_memcmp(addr, auth->peer_mac_addr, ETH_ALEN) != 0) {
 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
 		return;
 	}
@@ -1781,6 +1856,222 @@
 	}
 }
 
+
+static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+						 void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+	if (!auth)
+		return;
+
+	wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
+	offchannel_send_action_done(wpa_s);
+	wpas_dpp_listen_stop(wpa_s);
+	dpp_auth_deinit(auth);
+	wpa_s->dpp_auth = NULL;
+}
+
+
+static void
+wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+				  const u8 *hdr, const u8 *buf, size_t len,
+				  unsigned int freq)
+{
+	const u8 *csign_hash;
+	u16 csign_hash_len;
+	struct dpp_configurator *conf;
+	struct dpp_authentication *auth;
+	unsigned int wait_time, max_wait_time;
+
+	if (!wpa_s->dpp)
+		return;
+
+	if (wpa_s->dpp_auth) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Ignore Reconfig Announcement during ongoing Authentication");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
+		   MAC2STR(src));
+
+	csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
+				  &csign_hash_len);
+	if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Configurator C-sign key Hash attribute");
+		return;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
+		    csign_hash, csign_hash_len);
+	conf = dpp_configurator_find_kid(wpa_s->dpp, csign_hash);
+	if (!conf) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No matching Configurator information found");
+		return;
+	}
+
+	auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq);
+	if (!auth)
+		return;
+	wpas_dpp_set_testing_options(wpa_s, auth);
+	if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
+		dpp_auth_deinit(auth);
+		return;
+	}
+
+	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+	wpa_s->dpp_auth = auth;
+
+	wpa_s->dpp_in_response_listen = 0;
+	wpa_s->dpp_auth_ok_on_ack = 0;
+	wait_time = wpa_s->max_remain_on_chan;
+	max_wait_time = wpa_s->dpp_resp_wait_time ?
+		wpa_s->dpp_resp_wait_time : 2000;
+	if (wait_time > max_wait_time)
+		wait_time = max_wait_time;
+	wait_time += 10; /* give the driver some extra time to complete */
+	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+			       wpas_dpp_reconfig_reply_wait_timeout,
+			       wpa_s, NULL);
+	wait_time -= 10;
+
+	wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time);
+
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
+	if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+				   wpabuf_head(auth->reconfig_req_msg),
+				   wpabuf_len(auth->reconfig_req_msg),
+				   wait_time, wpas_dpp_tx_status, 0) < 0) {
+		dpp_auth_deinit(wpa_s->dpp_auth);
+		wpa_s->dpp_auth = NULL;
+	}
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
+			      const u8 *hdr, const u8 *buf, size_t len,
+			      unsigned int freq)
+{
+	struct wpa_ssid *ssid;
+	struct dpp_authentication *auth;
+
+	wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
+		   MACSTR, MAC2STR(src));
+
+	if (!wpa_s->dpp || wpa_s->dpp_auth ||
+	    !wpa_s->dpp_reconfig_announcement || !wpa_s->dpp_reconfig_ssid)
+		return;
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid == wpa_s->dpp_reconfig_ssid &&
+		    ssid->id == wpa_s->dpp_reconfig_ssid_id)
+			break;
+	}
+	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+	    !ssid->dpp_csign)
+		return;
+
+	auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
+					ssid->dpp_netaccesskey,
+					ssid->dpp_netaccesskey_len,
+					ssid->dpp_csign, ssid->dpp_csign_len,
+					freq, hdr, buf, len);
+	if (!auth)
+		return;
+	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+	wpa_s->dpp_auth = auth;
+
+	wpas_dpp_chirp_stop(wpa_s);
+
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_RESP);
+	if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+				   wpabuf_head(auth->reconfig_resp_msg),
+				   wpabuf_len(auth->reconfig_resp_msg),
+				   500, wpas_dpp_tx_status, 0) < 0) {
+		dpp_auth_deinit(wpa_s->dpp_auth);
+		wpa_s->dpp_auth = NULL;
+	}
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
+			       const u8 *hdr, const u8 *buf, size_t len,
+			       unsigned int freq)
+{
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+	struct wpabuf *conf;
+
+	wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
+		   MACSTR, MAC2STR(src));
+
+	if (!auth || !auth->reconfig || !auth->configurator) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No DPP Reconfig Authentication in progress - drop");
+		return;
+	}
+
+	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+		return;
+	}
+
+	conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
+	if (!conf)
+		return;
+
+	eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, wpa_s, NULL);
+
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
+	if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+				   wpabuf_head(conf), wpabuf_len(conf),
+				   500, wpas_dpp_tx_status, 0) < 0) {
+		wpabuf_free(conf);
+		dpp_auth_deinit(wpa_s->dpp_auth);
+		wpa_s->dpp_auth = NULL;
+		return;
+	}
+	wpabuf_free(conf);
+
+	wpas_dpp_start_gas_server(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
+			       const u8 *hdr, const u8 *buf, size_t len,
+			       unsigned int freq)
+{
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+	wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Confirm from "
+		   MACSTR, MAC2STR(src));
+
+	if (!auth || !auth->reconfig || auth->configurator) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No DPP Reconfig Authentication in progress - drop");
+		return;
+	}
+
+	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+		return;
+	}
+
+	if (dpp_reconfig_auth_conf_rx(auth, hdr, buf, len) < 0)
+		return;
+
+	wpas_dpp_start_gas_client(wpa_s);
+}
+
 #endif /* CONFIG_DPP2 */
 
 
@@ -1791,6 +2082,11 @@
 	struct wpa_ssid *ssid;
 	const u8 *connector, *trans_id, *status;
 	u16 connector_len, trans_id_len, status_len;
+#ifdef CONFIG_DPP2
+	const u8 *version;
+	u16 version_len;
+#endif /* CONFIG_DPP2 */
+	u8 peer_version = 1;
 	struct dpp_introduction intro;
 	struct rsn_pmksa_cache_entry *entry;
 	struct os_time now;
@@ -1891,6 +2187,13 @@
 	os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
 	entry->pmk_len = intro.pmk_len;
 	entry->akmp = WPA_KEY_MGMT_DPP;
+#ifdef CONFIG_DPP2
+	version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+			       &version_len);
+	if (version && version_len >= 1)
+		peer_version = version[0];
+	entry->dpp_pfs = peer_version >= 2;
+#endif /* CONFIG_DPP2 */
 	if (expiry) {
 		os_get_time(&now);
 		seconds = expiry - now.sec;
@@ -1904,7 +2207,7 @@
 	wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
 
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
-		" status=%u", MAC2STR(src), status[0]);
+		" status=%u version=%u", MAC2STR(src), status[0], peer_version);
 
 	wpa_printf(MSG_DEBUG,
 		   "DPP: Try connection again after successful network introduction");
@@ -2330,6 +2633,19 @@
 		wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
 						  freq);
 		break;
+	case DPP_PA_RECONFIG_ANNOUNCEMENT:
+		wpas_dpp_rx_reconfig_announcement(wpa_s, src, hdr, buf, len,
+						  freq);
+		break;
+	case DPP_PA_RECONFIG_AUTH_REQ:
+		wpas_dpp_rx_reconfig_auth_req(wpa_s, src, hdr, buf, len, freq);
+		break;
+	case DPP_PA_RECONFIG_AUTH_RESP:
+		wpas_dpp_rx_reconfig_auth_resp(wpa_s, src, hdr, buf, len, freq);
+		break;
+	case DPP_PA_RECONFIG_AUTH_CONF:
+		wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq);
+		break;
 #endif /* CONFIG_DPP2 */
 	default:
 		wpa_printf(MSG_DEBUG,
@@ -2360,7 +2676,7 @@
 
 	wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
 		   MAC2STR(sa));
-	if (!auth || !auth->auth_success ||
+	if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
 	    os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
 		return NULL;
@@ -2501,6 +2817,7 @@
 	unsigned int wait_time;
 	const u8 *rsn;
 	struct wpa_ie_data ied;
+	size_t len;
 
 	if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
 		return 0; /* Not using DPP AKM - continue */
@@ -2534,8 +2851,11 @@
 		   "DPP: Starting network introduction protocol to derive PMKSA for "
 		   MACSTR, MAC2STR(bss->bssid));
 
-	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ,
-			    5 + 4 + os_strlen(ssid->dpp_connector));
+	len = 5 + 4 + os_strlen(ssid->dpp_connector);
+#ifdef CONFIG_DPP2
+	len += 5;
+#endif /* CONFIG_DPP2 */
+	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ, len);
 	if (!msg)
 		return -1;
 
@@ -2590,6 +2910,15 @@
 skip_connector:
 #endif /* CONFIG_TESTING_OPTIONS */
 
+#ifdef CONFIG_DPP2
+	if (DPP_VERSION > 1) {
+		/* Protocol Version */
+		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+		wpabuf_put_le16(msg, 1);
+		wpabuf_put_u8(msg, DPP_VERSION);
+	}
+#endif /* CONFIG_DPP2 */
+
 	/* TODO: Timeout on AP response */
 	wait_time = wpa_s->max_remain_on_chan;
 	if (wait_time > 2000)
@@ -2792,6 +3121,8 @@
 	eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
 			     wpa_s, NULL);
 	eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+			     wpa_s, NULL);
 	dpp_pfs_free(wpa_s->dpp_pfs);
 	wpa_s->dpp_pfs = NULL;
 	wpas_dpp_chirp_stop(wpa_s);
@@ -2814,12 +3145,27 @@
 	const char *pos;
 
 	os_memset(&config, 0, sizeof(config));
+	config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
 	if (cmd) {
 		pos = os_strstr(cmd, " tcp_port=");
 		if (pos) {
 			pos += 10;
 			config.tcp_port = atoi(pos);
 		}
+
+		pos = os_strstr(cmd, " role=");
+		if (pos) {
+			pos += 6;
+			if (os_strncmp(pos, "configurator", 12) == 0)
+				config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
+			else if (os_strncmp(pos, "enrollee", 8) == 0)
+				config.allowed_roles = DPP_CAPAB_ENROLLEE;
+			else if (os_strncmp(pos, "either", 6) == 0)
+				config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
+					DPP_CAPAB_ENROLLEE;
+			else
+				return -1;
+		}
 	}
 	config.configurator_params = wpa_s->dpp_configurator_params;
 	return dpp_controller_start(wpa_s->dpp, &config);
@@ -2862,15 +3208,24 @@
 
 static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
 {
+	struct wpabuf *msg;
+	int type;
+
+	msg = wpa_s->dpp_presence_announcement;
+	type = DPP_PA_PRESENCE_ANNOUNCEMENT;
+	if (!msg) {
+		msg = wpa_s->dpp_reconfig_announcement;
+		if (!msg)
+			return;
+		type = DPP_PA_RECONFIG_ANNOUNCEMENT;
+	}
 	wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
-		MAC2STR(broadcast), wpa_s->dpp_chirp_freq,
-		DPP_PA_PRESENCE_ANNOUNCEMENT);
+		MAC2STR(broadcast), wpa_s->dpp_chirp_freq, type);
 	if (offchannel_send_action(
 		    wpa_s, wpa_s->dpp_chirp_freq, broadcast,
 		    wpa_s->own_addr, broadcast,
-		    wpabuf_head(wpa_s->dpp_presence_announcement),
-		    wpabuf_len(wpa_s->dpp_presence_announcement),
+		    wpabuf_head(msg), wpabuf_len(msg),
 		    2000, wpas_dpp_chirp_tx_status, 0) < 0)
 		wpas_dpp_chirp_stop(wpa_s);
 }
@@ -2885,7 +3240,7 @@
 	int c;
 	struct wpa_bss *bss;
 
-	if (!bi)
+	if (!bi && !wpa_s->dpp_reconfig_announcement)
 		return;
 
 	wpa_s->dpp_chirp_scan_done = 1;
@@ -2894,8 +3249,11 @@
 	wpa_s->dpp_chirp_freqs = NULL;
 
 	/* Channels from own bootstrapping info */
-	for (i = 0; i < bi->num_freq; i++)
-		int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]);
+	if (bi) {
+		for (i = 0; i < bi->num_freq; i++)
+			int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+					     bi->freq[i]);
+	}
 
 	/* Preferred chirping channels */
 	int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
@@ -3047,7 +3405,7 @@
 	pos = os_strstr(cmd, " listen=");
 	if (pos) {
 		listen_freq = atoi(pos + 8);
-		if (iter <= 0)
+		if (listen_freq <= 0)
 			return -1;
 	}
 
@@ -3069,13 +3427,16 @@
 
 void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s->dpp_presence_announcement) {
+	if (wpa_s->dpp_presence_announcement ||
+	    wpa_s->dpp_reconfig_announcement) {
 		offchannel_send_action_done(wpa_s);
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
 	}
 	wpa_s->dpp_chirp_bi = NULL;
 	wpabuf_free(wpa_s->dpp_presence_announcement);
 	wpa_s->dpp_presence_announcement = NULL;
+	wpabuf_free(wpa_s->dpp_reconfig_announcement);
+	wpa_s->dpp_reconfig_announcement = NULL;
 	if (wpa_s->dpp_chirp_listen)
 		wpas_dpp_listen_stop(wpa_s);
 	wpa_s->dpp_chirp_listen = 0;
@@ -3090,4 +3451,29 @@
 	}
 }
 
+
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+	    !ssid->dpp_csign)
+		return -1;
+
+	wpas_dpp_chirp_stop(wpa_s);
+	wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+	wpa_s->dpp_qr_mutual = 0;
+	wpa_s->dpp_reconfig_announcement =
+		dpp_build_reconfig_announcement(ssid->dpp_csign,
+						ssid->dpp_csign_len);
+	if (!wpa_s->dpp_reconfig_announcement)
+		return -1;
+	wpa_s->dpp_reconfig_ssid = ssid;
+	wpa_s->dpp_reconfig_ssid_id = ssid->id;
+	wpa_s->dpp_chirp_iter = 1;
+	wpa_s->dpp_chirp_round = 0;
+	wpa_s->dpp_chirp_scan_done = 0;
+	wpa_s->dpp_chirp_listen = 0;
+
+	return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
 #endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 2ce378d..2dc86e0 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -19,6 +19,8 @@
 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);
+void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				   unsigned int freq, unsigned int duration);
 void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 					  unsigned int freq);
 void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
@@ -37,5 +39,6 @@
 				      enum dpp_status_error result);
 int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
 void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 
 #endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index f531c39..e2cae4b 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2727,7 +2727,8 @@
 
 #ifdef CONFIG_DPP2
 	wpa_sm_set_dpp_z(wpa_s->wpa, NULL);
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->dpp_pfs) {
+	if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP &&
+	    wpa_s->dpp_pfs) {
 		struct ieee802_11_elems elems;
 
 		if (ieee802_11_parse_elems(data->assoc_info.resp_ies,
@@ -4398,7 +4399,7 @@
 	 * the status code defined in the DPP R2 tech spec.
 	 * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an
 	 * interoperability workaround with older hostapd implementation. */
-	if (wpa_s->current_ssid &&
+	if (DPP_VERSION > 1 && wpa_s->current_ssid &&
 	    wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
 	    wpa_s->current_ssid->dpp_pfs == 0 &&
 	    (data->assoc_reject.status_code ==
@@ -5029,6 +5030,11 @@
 		wpas_p2p_remain_on_channel_cb(
 			wpa_s, data->remain_on_channel.freq,
 			data->remain_on_channel.duration);
+#ifdef CONFIG_DPP
+		wpas_dpp_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq,
+			data->remain_on_channel.duration);
+#endif /* CONFIG_DPP */
 		break;
 	case EVENT_CANCEL_REMAIN_ON_CHANNEL:
 #ifdef CONFIG_OFFCHANNEL
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
index f49da34..1883545 100755
--- a/wpa_supplicant/examples/dpp-nfc.py
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -8,6 +8,7 @@
 # See README for more details.
 
 import os
+import struct
 import sys
 import time
 import threading
@@ -18,7 +19,7 @@
 
 import logging
 
-scriptsdir = os.path.dirname(os.path.realpath("dpp-nfc.py"))
+scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
 sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
 import wpaspy
 
@@ -33,12 +34,18 @@
 terminate_now = False
 summary_file = None
 success_file = None
+my_crn_ready = False
+my_crn = None
+peer_crn = None
+hs_sent = False
+mutex = threading.Lock()
 
 def summary(txt):
-    print(txt)
-    if summary_file:
-        with open(summary_file, 'a') as f:
-            f.write(txt + "\n")
+    with mutex:
+        print(txt)
+        if summary_file:
+            with open(summary_file, 'a') as f:
+                f.write(txt + "\n")
 
 def success_report(txt):
     summary(txt)
@@ -52,11 +59,11 @@
         try:
             ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
         except OSError as error:
-            print("Could not find wpa_supplicant: ", error)
+            summary("Could not find wpa_supplicant: %s", str(error))
             return None
 
     if len(ifaces) < 1:
-        print("No wpa_supplicant control interface found")
+        summary("No wpa_supplicant control interface found")
         return None
 
     for ctrl in ifaces:
@@ -64,7 +71,7 @@
             if ifname not in ctrl:
                 continue
         try:
-            print("Trying to use control interface " + ctrl)
+            summary("Trying to use control interface " + ctrl)
             wpas = wpaspy.Ctrl(ctrl)
             return wpas
         except Exception as e:
@@ -77,38 +84,46 @@
         return False
     peer_id = wpas.request("DPP_NFC_URI " + uri)
     if "FAIL" in peer_id:
-        print("Could not parse DPP URI from NFC URI record")
+        summary("Could not parse DPP URI from NFC URI record")
         return False
     peer_id = int(peer_id)
-    print("peer_id=%d" % peer_id)
+    summary("peer_id=%d for URI from NFC Tag: %s" % (peer_id, uri))
     cmd = "DPP_AUTH_INIT peer=%d" % peer_id
+    global enrollee_only, configurator_only, config_params
+    if enrollee_only:
+        cmd += " role=enrollee"
+    elif configurator_only:
+        cmd += " role=configurator"
+    if config_params:
+        cmd += " " + config_params
+    summary("Initiate DPP authentication: " + cmd)
     res = wpas.request(cmd)
     if "OK" not in res:
-        print("Failed to initiate DPP Authentication")
+        summary("Failed to initiate DPP Authentication")
         return False
-    print("DPP Authentication initiated")
+    summary("DPP Authentication initiated")
     return True
 
 def dpp_hs_tag_read(record):
     wpas = wpas_connect()
     if wpas is None:
         return False
-    print(record)
+    summary(record)
     if len(record.data) < 5:
-        print("Too short DPP HS")
+        summary("Too short DPP HS")
         return False
     if record.data[0] != 0:
-        print("Unexpected URI Identifier Code")
+        summary("Unexpected URI Identifier Code")
         return False
     uribuf = record.data[1:]
     try:
         uri = uribuf.decode()
     except:
-        print("Invalid URI payload")
+        summary("Invalid URI payload")
         return False
-    print("URI: " + uri)
+    summary("URI: " + uri)
     if not uri.startswith("DPP:"):
-        print("Not a DPP URI")
+        summary("Not a DPP URI")
         return False
     return dpp_nfc_uri_process(uri)
 
@@ -124,7 +139,7 @@
         try:
             [name, value] = l.split('=', 1)
         except ValueError:
-            logger.info("Ignore unexpected status line: " + l)
+            summary("Ignore unexpected status line: %s" % l)
             continue
         vals[name] = value
     return vals
@@ -136,7 +151,10 @@
     return None
 
 def own_addr(wpas):
-    return get_status_field(wpas, "address")
+    addr = get_status_field(wpas, "address")
+    if addr is None:
+        addr = get_status_field(wpas, "bssid[0]")
+    return addr
 
 def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
                       curve=None, key=None):
@@ -146,7 +164,10 @@
     if mac:
         if mac is True:
             mac = own_addr(wpas)
-        cmd += " mac=" + mac.replace(':', '')
+        if mac is None:
+            summary("Could not determine local MAC address for bootstrap info")
+        else:
+            cmd += " mac=" + mac.replace(':', '')
     if info:
         cmd += " info=" + info
     if curve:
@@ -158,12 +179,23 @@
         raise Exception("Failed to generate bootstrapping info")
     return int(res)
 
-def wpas_get_nfc_uri(start_listen=True):
+def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
     wpas = wpas_connect()
     if wpas is None:
         return None
     global own_id, chanlist
-    own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chanlist, mac=True)
+    chan = chanlist
+    if chan is None and get_status_field(wpas, "bssid[0]"):
+        freq = get_status_field(wpas, "freq")
+        if freq:
+            freq = int(freq)
+            if freq >= 2412 and freq <= 2462:
+                chan = "81/%d" % ((freq - 2407) / 5)
+                summary("Use current AP operating channel (%d MHz) as the URI channel list (%s)" % (freq, chan))
+    if chan is None and pick_channel:
+        chan = "81/6"
+        summary("Use channel 2437 MHz since no other preference provided")
+    own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chan, mac=True)
     res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
     if "FAIL" in res:
         return None
@@ -189,14 +221,22 @@
 
 def dpp_handover_client(llc):
     uri = wpas_get_nfc_uri(start_listen=False)
+    if uri is None:
+        summary("Cannot start handover client - no bootstrap URI available")
+        return
     uri = ndef.UriRecord(uri)
-    print("NFC URI record for DPP: " + str(uri))
+    summary("NFC URI record for DPP: " + str(uri))
     carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
-    hr = ndef.HandoverRequestRecord(version="1.4", crn=os.urandom(2))
+    crn = os.urandom(2)
+    hr = ndef.HandoverRequestRecord(version="1.4", crn=crn)
     hr.add_alternative_carrier('active', carrier.name)
     message = [hr, carrier]
-    print("NFC Handover Request message for DPP: " + str(message))
+    summary("NFC Handover Request message for DPP: " + str(message))
 
+    global peer_crn
+    if peer_crn is not None:
+        summary("NFC handover request from peer was already received - do not send own")
+        return
     client = nfc.handover.HandoverClient(llc)
     try:
         summary("Trying to initiate NFC connection handover")
@@ -211,76 +251,108 @@
         client.close()
         return
 
+    if peer_crn is not None:
+        summary("NFC handover request from peer was already received - do not send own")
+        client.close()
+        return
+
     summary("Sending handover request")
 
+    global my_crn, my_crn_ready, hs_sent
+    my_crn_ready = True
+
     if not client.send_records(message):
+        my_crn_ready = False
         summary("Failed to send handover request")
         client.close()
         return
 
+    my_crn, = struct.unpack('>H', crn)
+
     summary("Receiving handover response")
-    message = client.recv_records(timeout=3.0)
+    try:
+        message = client.recv_records(timeout=3.0)
+    except Exception as e:
+        # This is fine if we are the handover selector
+        if hs_sent:
+            summary("Client receive failed as expected since I'm the handover server: %s" % str(e))
+        else:
+            summary("Client receive failed: %s" % str(e))
+        message = None
     if message is None:
-        summary("No response received")
+        if hs_sent:
+            summary("No response received as expected since I'm the handover server")
+        else:
+            summary("No response received")
         client.close()
         return
-    print("Received message: " + str(message))
+    summary("Received message: " + str(message))
     if len(message) < 1 or \
        not isinstance(message[0], ndef.HandoverSelectRecord):
         summary("Response was not Hs - received: " + message.type)
         client.close()
         return
 
-    print("Received message")
-    print("alternative carriers: " + str(message[0].alternative_carriers))
+    summary("Received handover select message")
+    summary("alternative carriers: " + str(message[0].alternative_carriers))
 
     dpp_found = False
     for carrier in message:
         if isinstance(carrier, ndef.HandoverSelectRecord):
             continue
-        print("Remote carrier type: " + carrier.type)
+        summary("Remote carrier type: " + carrier.type)
         if carrier.type == "application/vnd.wfa.dpp":
             if len(carrier.data) == 0 or carrier.data[0] != 0:
-                print("URI Identifier Code 'None' not seen")
+                summary("URI Identifier Code 'None' not seen")
                 continue
-            print("DPP carrier type match - send to wpa_supplicant")
+            summary("DPP carrier type match - send to wpa_supplicant")
             dpp_found = True
             uri = carrier.data[1:].decode("utf-8")
-            print("DPP URI: " + uri)
+            summary("DPP URI: " + uri)
             res = wpas_report_handover_sel(uri)
             if res is None or "FAIL" in res:
                 summary("DPP handover report rejected")
                 break
 
             success_report("DPP handover reported successfully (initiator)")
-            print("peer_id=" + res)
+            summary("peer_id=" + res)
             peer_id = int(res)
-            # TODO: Single Configurator instance
             wpas = wpas_connect()
             if wpas is None:
                 break
-            res = wpas.request("DPP_CONFIGURATOR_ADD")
-            if "FAIL" in res:
-                print("Failed to initiate Configurator")
-                break
-            conf_id = int(res)
+
+            global enrollee_only
+            global config_params
+            if enrollee_only:
+                extra = " role=enrollee"
+            elif config_params:
+                extra = " role=configurator " + config_params
+            else:
+                # TODO: Single Configurator instance
+                res = wpas.request("DPP_CONFIGURATOR_ADD")
+                if "FAIL" in res:
+                    summary("Failed to initiate Configurator")
+                    break
+                conf_id = int(res)
+                extra = " conf=sta-dpp configurator=%d" % conf_id
             global own_id
-            print("Initiate DPP authentication")
-            cmd = "DPP_AUTH_INIT peer=%d own=%d conf=sta-dpp configurator=%d" % (peer_id, own_id, conf_id)
+            summary("Initiate DPP authentication")
+            cmd = "DPP_AUTH_INIT peer=%d own=%d" % (peer_id, own_id)
+            cmd += extra
             res = wpas.request(cmd)
             if "FAIL" in res:
-                print("Failed to initiate DPP authentication")
+                summary("Failed to initiate DPP authentication")
             break
 
     if not dpp_found:
-        print("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
+        summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
         client.close()
-        print("Returning from dpp_handover_client")
+        summary("Returning from dpp_handover_client")
         return
 
-    print("Remove peer")
+    summary("Remove peer")
     client.close()
-    print("Done with handover")
+    summary("Done with handover")
     global only_one
     if only_one:
         print("only_one -> stop loop")
@@ -293,7 +365,7 @@
         global terminate_now
         terminate_now = True
 
-    print("Returning from dpp_handover_client")
+    summary("Returning from dpp_handover_client")
 
 class HandoverServer(nfc.handover.HandoverServer):
     def __init__(self, llc):
@@ -305,10 +377,45 @@
 
     def process_handover_request_message(self, records):
         self.ho_server_processing = True
+        global in_raw_mode
+        was_in_raw_mode = in_raw_mode
         clear_raw_mode()
-        print("\nHandoverServer - request received: " + str(records))
+        if was_in_raw_mode:
+            print("\n")
+        summary("HandoverServer - request received: " + str(records))
 
-        carrier = None
+        global my_crn, peer_crn, my_crn_ready
+
+        for carrier in records:
+            if not isinstance(carrier, ndef.HandoverRequestRecord):
+                continue
+            if carrier.collision_resolution_number:
+                peer_crn = carrier.collision_resolution_number
+                summary("peer_crn: %d" % peer_crn)
+
+        if my_crn is None and my_crn_ready:
+            summary("Still trying to send own handover request - wait a moment to see if that succeeds before checking crn values")
+            for i in range(10):
+                if my_crn is not None:
+                    break
+                time.sleep(0.01)
+        if my_crn is not None:
+            summary("my_crn: %d" % my_crn)
+
+        if my_crn is not None and peer_crn is not None:
+            if my_crn == peer_crn:
+                summary("Same crn used - automatic collision resolution failed")
+                # TODO: Should generate a new Handover Request message
+                return ''
+            if ((my_crn & 1) == (peer_crn & 1) and my_crn > peer_crn) or \
+               ((my_crn & 1) != (peer_crn & 1) and my_crn < peer_crn):
+                summary("I'm the Handover Selector Device")
+                pass
+            else:
+                summary("Peer is the Handover Selector device")
+                summary("Ignore the received request.")
+                return ''
+
         hs = ndef.HandoverSelectRecord('1.4')
         sel = [hs]
 
@@ -317,25 +424,24 @@
         for carrier in records:
             if isinstance(carrier, ndef.HandoverRequestRecord):
                 continue
-            print("Remote carrier type: " + carrier.type)
+            summary("Remote carrier type: " + carrier.type)
             if carrier.type == "application/vnd.wfa.dpp":
-                print("DPP carrier type match - add DPP carrier record")
+                summary("DPP carrier type match - add DPP carrier record")
                 if len(carrier.data) == 0 or carrier.data[0] != 0:
-                    print("URI Identifier Code 'None' not seen")
+                    summary("URI Identifier Code 'None' not seen")
                     continue
                 uri = carrier.data[1:].decode("utf-8")
-                print("Received DPP URI: " + uri)
+                summary("Received DPP URI: " + uri)
 
-                data = wpas_get_nfc_uri(start_listen=False)
-                print("Own URI (pre-processing): %s" % data)
+                data = wpas_get_nfc_uri(start_listen=False, pick_channel=True)
+                summary("Own URI (pre-processing): %s" % data)
 
                 res = wpas_report_handover_req(uri)
                 if res is None or "FAIL" in res:
-                    print("DPP handover request processing failed")
+                    summary("DPP handover request processing failed")
                     continue
 
                 found = True
-                self.received_carrier = carrier
 
                 wpas = wpas_connect()
                 if wpas is None:
@@ -344,25 +450,42 @@
                 data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
                 if "FAIL" in data:
                     continue
-                print("Own URI (post-processing): %s" % data)
+                summary("Own URI (post-processing): %s" % data)
                 uri = ndef.UriRecord(data)
-                print("Own bootstrapping NFC URI record: " + str(uri))
+                summary("Own bootstrapping NFC URI record: " + str(uri))
 
                 info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
                 freq = None
                 for line in info.splitlines():
                     if line.startswith("use_freq="):
                         freq = int(line.split('=')[1])
-                if freq is None:
-                    print("No channel negotiated over NFC - use channel 1")
-                    freq = 2412
-                res = wpas.request("DPP_LISTEN %d" % freq)
+                if freq is None or freq == 0:
+                    summary("No channel negotiated over NFC - use channel 6")
+                    freq = 2437
+                else:
+                    summary("Negotiated channel: %d MHz" % freq)
+                if get_status_field(wpas, "bssid[0]"):
+                    summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
+                    if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
+                        summary("Enable beaconing to have radio ready for RX")
+                        wpas.request("DISABLE")
+                        wpas.request("SET start_disabled 0")
+                        wpas.request("ENABLE")
+                cmd = "DPP_LISTEN %d" % freq
+                global enrollee_only
+                global configurator_only
+                if enrollee_only:
+                    cmd += " role=enrollee"
+                elif configurator_only:
+                    cmd += " role=configurator"
+                summary(cmd)
+                res = wpas.request(cmd)
                 if "OK" not in res:
-                    print("Failed to start DPP listen")
+                    summary("Failed to start DPP listen")
                     break
 
                 carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
-                print("Own DPP carrier record: " + str(carrier))
+                summary("Own DPP carrier record: " + str(carrier))
                 hs.add_alternative_carrier('active', carrier.name)
                 sel = [hs, carrier]
                 break
@@ -372,6 +495,8 @@
             self.success = True
         else:
             self.try_own = True
+        global hs_sent
+        hs_sent = True
         return sel
 
 def clear_raw_mode():
@@ -403,22 +528,22 @@
 def dpp_tag_read(tag):
     success = False
     for record in tag.ndef.records:
-        print(record)
-        print("record type " + record.type)
+        summary(record)
+        summary("record type " + record.type)
         if record.type == "application/vnd.wfa.dpp":
             summary("DPP HS tag - send to wpa_supplicant")
             success = dpp_hs_tag_read(record)
             break
         if isinstance(record, ndef.UriRecord):
-            print("URI record: uri=" + record.uri)
-            print("URI record: iri=" + record.iri)
+            summary("URI record: uri=" + record.uri)
+            summary("URI record: iri=" + record.iri)
             if record.iri.startswith("DPP:"):
-                print("DPP URI")
+                summary("DPP URI")
                 if not dpp_nfc_uri_process(record.iri):
                     break
                 success = True
             else:
-                print("Ignore unknown URI")
+                summary("Ignore unknown URI")
             break
 
     if success:
@@ -429,15 +554,15 @@
 def rdwr_connected_write_tag(tag):
     summary("Tag found - writing - " + str(tag))
     if not tag.ndef.is_writeable:
-        print("Not a writable tag")
+        summary("Not a writable tag")
         return
     global dpp_tag_data
     if tag.ndef.capacity < len(dpp_tag_data):
-        print("Not enough room for the message")
+        summary("Not enough room for the message")
         return
     tag.ndef.records = dpp_tag_data
     success_report("Tag write succeeded")
-    print("Done - remove tag")
+    summary("Done - remove tag")
     global only_one
     if only_one:
         global continue_loop
@@ -446,7 +571,7 @@
     return dpp_sel_wait_remove
 
 def write_nfc_uri(clf, wait_remove=True):
-    print("Write NFC URI record")
+    summary("Write NFC URI record")
     data = wpas_get_nfc_uri()
     if data is None:
         summary("Could not get NFC URI from wpa_supplicant")
@@ -454,17 +579,17 @@
 
     global dpp_sel_wait_remove
     dpp_sel_wait_remove = wait_remove
-    print("URI: %s" % data)
+    summary("URI: %s" % data)
     uri = ndef.UriRecord(data)
-    print(uri)
+    summary(uri)
 
-    print("Touch an NFC tag")
+    summary("Touch an NFC tag")
     global dpp_tag_data
     dpp_tag_data = [uri]
     clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
 
 def write_nfc_hs(clf, wait_remove=True):
-    print("Write NFC Handover Select record on a tag")
+    summary("Write NFC Handover Select record on a tag")
     data = wpas_get_nfc_uri()
     if data is None:
         summary("Could not get NFC URI from wpa_supplicant")
@@ -472,19 +597,19 @@
 
     global dpp_sel_wait_remove
     dpp_sel_wait_remove = wait_remove
-    print("URI: %s" % data)
+    summary("URI: %s" % data)
     uri = ndef.UriRecord(data)
-    print(uri)
+    summary(uri)
     carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
     hs = ndef.HandoverSelectRecord('1.4')
     hs.add_alternative_carrier('active', carrier.name)
-    print(hs)
-    print(carrier)
+    summary(hs)
+    summary(carrier)
 
-    print("Touch an NFC tag")
+    summary("Touch an NFC tag")
     global dpp_tag_data
     dpp_tag_data = [hs, carrier]
-    print(dpp_tag_data)
+    summary(dpp_tag_data)
     clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
 
 def rdwr_connected(tag):
@@ -492,8 +617,8 @@
     summary("Tag connected: " + str(tag))
 
     if tag.ndef:
-        print("NDEF tag: " + tag.type)
-        print(tag.ndef.records)
+        summary("NDEF tag: " + tag.type)
+        summary(tag.ndef.records)
         success = dpp_tag_read(tag)
         if only_one and success:
             global continue_loop
@@ -507,14 +632,14 @@
 def llcp_worker(llc):
     global init_on_touch
     if init_on_touch:
-        print("Starting handover client")
+        summary("Starting handover client")
         dpp_handover_client(llc)
-        print("Exiting llcp_worker thread (init_in_touch)")
+        summary("Exiting llcp_worker thread (init_in_touch)")
         return
 
     global no_input
     if no_input:
-        print("Wait for handover to complete")
+        summary("Wait for handover to complete")
     else:
         print("Wait for handover to complete - press 'i' to initiate")
     global srv
@@ -522,9 +647,9 @@
     while not wait_connection and srv.sent_carrier is None:
         if srv.try_own:
             srv.try_own = False
-            print("Try to initiate another handover with own parameters")
+            summary("Try to initiate another handover with own parameters")
             dpp_handover_client(llc)
-            print("Exiting llcp_worker thread (retry with own parameters)")
+            summary("Exiting llcp_worker thread (retry with own parameters)")
             return
         if srv.ho_server_processing:
             time.sleep(0.025)
@@ -535,34 +660,40 @@
             if res != 'i':
                 continue
             clear_raw_mode()
-            print("Starting handover client")
+            summary("Starting handover client")
             dpp_handover_client(llc)
-            print("Exiting llcp_worker thread (manual init)")
+            summary("Exiting llcp_worker thread (manual init)")
             return
 
+    global in_raw_mode
+    was_in_raw_mode = in_raw_mode
     clear_raw_mode()
-    print("\rExiting llcp_worker thread")
+    if was_in_raw_mode:
+        print("\r")
+    summary("Exiting llcp_worker thread")
 
 def llcp_startup(llc):
-    print("Start LLCP server")
+    summary("Start LLCP server")
     global srv
     srv = HandoverServer(llc)
     return llc
 
 def llcp_connected(llc):
-    print("P2P LLCP connected")
-    global wait_connection
+    summary("P2P LLCP connected")
+    global wait_connection, my_crn, peer_crn, my_crn_ready, hs_sent
     wait_connection = False
-    global init_on_touch
-    if not init_on_touch:
-        global srv
-        srv.start()
+    my_crn_ready = False
+    my_crn = None
+    peer_crn = None
+    hs_sent = False
+    global srv
+    srv.start()
     if init_on_touch or not no_input:
         threading.Thread(target=llcp_worker, args=(llc,)).start()
     return True
 
 def llcp_release(llc):
-    print("LLCP release")
+    summary("LLCP release")
     return True
 
 def terminate_loop():
@@ -592,17 +723,25 @@
                         help='tag read only (do not allow connection handover)')
     parser.add_argument('--handover-only', action='store_true',
                         help='connection handover only (do not allow tag read)')
+    parser.add_argument('--enrollee', action='store_true',
+                        help='run as Enrollee-only')
+    parser.add_argument('--configurator', action='store_true',
+                        help='run as Configurator-only')
+    parser.add_argument('--config-params', default='',
+                        help='configurator parameters')
+    parser.add_argument('--ctrl', default='/var/run/wpa_supplicant',
+                        help='wpa_supplicant/hostapd control interface')
     parser.add_argument('--summary',
                         help='summary file for writing status updates')
     parser.add_argument('--success',
                         help='success file for writing success update')
     parser.add_argument('--device', default='usb', help='NFC device to open')
-    parser.add_argument('--chan', default='81/1', help='channel list')
+    parser.add_argument('--chan', default=None, help='channel list')
     parser.add_argument('command', choices=['write-nfc-uri',
                                             'write-nfc-hs'],
                         nargs='?')
     args = parser.parse_args()
-    print(args)
+    summary(args)
 
     global only_one
     only_one = args.only_one
@@ -618,10 +757,23 @@
     global init_on_touch
     init_on_touch = args.init_on_touch
 
+    global enrollee_only
+    enrollee_only = args.enrollee
+
+    global configurator_only
+    configurator_only = args.configurator
+
+    global config_params
+    config_params = args.config_params
+
     if args.ifname:
         global ifname
         ifname = args.ifname
-        print("Selected ifname " + ifname)
+        summary("Selected ifname " + ifname)
+
+    if args.ctrl:
+        global wpas_ctrl
+        wpas_ctrl = args.ctrl
 
     if args.summary:
         global summary_file
@@ -640,7 +792,7 @@
 
     try:
         if not clf.open(args.device):
-            print("Could not open connection with an NFC device")
+            summary("Could not open connection with an NFC device")
             raise SystemExit
 
         if args.command == "write-nfc-uri":
@@ -653,8 +805,12 @@
 
         global continue_loop
         while continue_loop:
+            global in_raw_mode
+            was_in_raw_mode = in_raw_mode
             clear_raw_mode()
-            print("\rWaiting for a tag or peer to be touched")
+            if was_in_raw_mode:
+                print("\r")
+            summary("Waiting for a tag or peer to be touched")
             wait_connection = True
             try:
                 if args.tag_read_only:
@@ -674,7 +830,7 @@
                                        terminate=terminate_loop):
                         break
             except Exception as e:
-                print("clf.connect failed: " + str(e))
+                summary("clf.connect failed: " + str(e))
                 break
 
             global srv
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index c16c2a9..b60f80d 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -946,7 +946,8 @@
 	struct wpa_driver_capa capa;
 
 	res = wpa_drv_get_capa(wpa_s, &capa);
-	if (res == 0 && capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+	if (res == 0 && capa.key_mgmt_iftype[WPA_IF_STATION] &
+	    WPA_DRIVER_CAPA_KEY_MGMT_FT) {
 		key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
 			"WPA-EAP WPA-EAP-SHA256 FT-EAP" :
 			"WPA-EAP FT-EAP";
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 4eaece0..d06f6e2 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1646,6 +1646,7 @@
 {
 	struct wpa_driver_associate_params params;
 	struct ieee802_11_elems elems;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
 #ifdef CONFIG_FILS
 	u8 nonces[2 * FILS_NONCE_LEN];
 #endif /* CONFIG_FILS */
@@ -1755,8 +1756,8 @@
 		struct wpabuf *owe_ie;
 		u16 group;
 
-		if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) {
-			group = wpa_s->current_ssid->owe_group;
+		if (ssid && ssid->owe_group) {
+			group = ssid->owe_group;
 		} else if (wpa_s->assoc_status_code ==
 			   WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
 			if (wpa_s->last_owe_group == 19)
@@ -1792,11 +1793,14 @@
 #endif /* CONFIG_OWE */
 
 #ifdef CONFIG_DPP2
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
-	    wpa_s->current_ssid->dpp_netaccesskey &&
-	    wpa_s->current_ssid->dpp_pfs != 2 &&
-	    !wpa_s->current_ssid->dpp_pfs_fallback) {
-		struct wpa_ssid *ssid = wpa_s->current_ssid;
+	if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && ssid &&
+	    ssid->dpp_netaccesskey && ssid->dpp_pfs != 2 &&
+	    !ssid->dpp_pfs_fallback) {
+		struct rsn_pmksa_cache_entry *pmksa;
+
+		pmksa = pmksa_cache_get_current(wpa_s->wpa);
+		if (!pmksa || !pmksa->dpp_pfs)
+			goto pfs_fail;
 
 		dpp_pfs_free(wpa_s->dpp_pfs);
 		wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
@@ -1823,7 +1827,7 @@
 pfs_fail:
 #endif /* CONFIG_DPP2 */
 
-	if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
+	if (ssid && ssid->multi_ap_backhaul_sta) {
 		size_t multi_ap_ie_len;
 
 		multi_ap_ie_len = add_multi_ap_ie(
@@ -1843,8 +1847,7 @@
 	params.ssid = wpa_s->sme.ssid;
 	params.ssid_len = wpa_s->sme.ssid_len;
 	params.freq.freq = wpa_s->sme.freq;
-	params.bg_scan_period = wpa_s->current_ssid ?
-		wpa_s->current_ssid->bg_scan_period : -1;
+	params.bg_scan_period = ssid ? ssid->bg_scan_period : -1;
 	params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
 		wpa_s->sme.assoc_req_ie : NULL;
 	params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
@@ -1860,17 +1863,17 @@
 	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
 	params.htcaps = (u8 *) &htcaps;
 	params.htcaps_mask = (u8 *) &htcaps_mask;
-	wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, &params);
+	wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_HT_OVERRIDES */
 #ifdef CONFIG_VHT_OVERRIDES
 	os_memset(&vhtcaps, 0, sizeof(vhtcaps));
 	os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
 	params.vhtcaps = &vhtcaps;
 	params.vhtcaps_mask = &vhtcaps_mask;
-	wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+	wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_VHT_OVERRIDES */
 #ifdef CONFIG_HE_OVERRIDES
-	wpa_supplicant_apply_he_overrides(wpa_s, wpa_s->current_ssid, &params);
+	wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_HE_OVERRIDES */
 #ifdef CONFIG_IEEE80211R
 	if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
@@ -1992,7 +1995,7 @@
 				       elems.rsnxe_len + 2);
 	else
 		wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
-	if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
+	if (ssid && ssid->p2p_group)
 		params.p2p = 1;
 
 	if (wpa_s->p2pdev->set_sta_uapsd)
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 07d5f31..6a2d2c3 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1706,15 +1706,25 @@
 static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
 				      char *argv[])
 {
-	if (argc < 1 || argc > 2) {
-		printf("Invalid GET_CAPABILITY command: need either one or "
-		       "two arguments\n");
+	if (argc < 1 || argc > 3) {
+		printf("Invalid GET_CAPABILITY command: need at least one argument and max three arguments\n");
 		return -1;
 	}
 
-	if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
-		printf("Invalid GET_CAPABILITY command: second argument, "
-		       "if any, must be 'strict'\n");
+	if (argc > 1 && os_strcmp(argv[0], "key_mgmt") != 0 &&
+	    os_strncmp(argv[1], "iftype=", 7) == 0) {
+		printf("Invalid GET_CAPABILITY command: 'iftype=' param is allowed only for 'key_mgmt'\n");
+		return -1;
+	}
+
+	if (argc == 2 && os_strcmp(argv[1], "strict") != 0 &&
+	    os_strncmp(argv[1], "iftype=", 7) != 0) {
+		printf("Invalid GET_CAPABILITY command: the second argument, if any, must be 'strict' OR 'iftype=<iftype_name>'\n");
+		return -1;
+	}
+
+	if (argc == 3 && os_strcmp(argv[2], "strict") != 0) {
+		printf("Invalid GET_CAPABILITY command: the third argument, if any, must be 'strict'\n");
 		return -1;
 	}
 
@@ -1741,7 +1751,13 @@
 		"acs",
 #endif /* CONFIG_ACS */
 	};
+	const char *iftypes[] = {
+		"iftype=STATION", "iftype=AP", "iftype=P2P_CLIENT",
+		"iftype=P2P_GO", "iftype=AP_VLAN", "iftype=IBSS", "iftype=NAN",
+		"iftype=P2P_DEVICE", "iftype=MESH",
+	};
 	int i, num_fields = ARRAY_SIZE(fields);
+	int num_iftypes = ARRAY_SIZE(iftypes);
 	char **res = NULL;
 
 	if (arg == 1) {
@@ -1755,6 +1771,21 @@
 		}
 	}
 	if (arg == 2) {
+		/* the second argument can be "iftype=<iftype_name>" OR
+		 * "strict" */
+		res = os_calloc(num_iftypes + 2, sizeof(char *));
+		if (!res)
+			return NULL;
+		res[0] = os_strdup("strict");
+		if (!res[0])
+			return res;
+		for (i = 0; i < num_iftypes; i++) {
+			res[i + 1] = os_strdup(iftypes[i]);
+			if (!res[i + 1])
+				return res;
+		}
+	}
+	if (arg == 3) {
 		res = os_calloc(1 + 1, sizeof(char *));
 		if (res == NULL)
 			return NULL;
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/wpa_supplicant/wpa_gui-qt4/icons/Makefile
index 709514c..88efc3c 100644
--- a/wpa_supplicant/wpa_gui-qt4/icons/Makefile
+++ b/wpa_supplicant/wpa_gui-qt4/icons/Makefile
@@ -5,14 +5,28 @@
 ICONS := $(addsuffix .png, $(foreach name, $(NAMES), $(foreach size, $(SIZES), $(size)/$(name))))
 ICONS += $(addsuffix .xpm, $(NAMES))
 
+ifeq (1, $(shell which inkscape; echo $$?))
+$(error "No inkscape in PATH, it is required for exporting icons.")
+else
+ifeq (0, $(shell inkscape --without-gui 2>&1 > /dev/null; echo $$?))
+# Inkscape < 1.0
+INKSCAPE_GUI_FLAG := --without-gui
+INKSCAPE_OUTPUT_FLAG := --export-png
+else
+# Inkscape >= 1.0
+INKSCAPE_GUI_FLAG :=
+INKSCAPE_OUTPUT_FLAG := --export-filename
+endif
+endif
+
 all: $(ICONS)
 
 %.png:
 	mkdir -p hicolor/$(word 1, $(subst /, ,$(@)))/apps/
-	inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) --without-gui \
+	inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) $(INKSCAPE_GUI_FLAG) \
 		--export-width=$(word 1, $(subst x, , $(@)))  \
 	        --export-height=$(word 2, $(subst x, , $(subst /, , $(@)))) \
-		--export-png=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@))
+		$(INKSCAPE_OUTPUT_FLAG)=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@))
 
 %.xpm:
 	mkdir -p pixmaps/
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index ea62e59..6f44613 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1686,6 +1686,9 @@
 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
 		/* Use PMK from DPP network introduction (PMKSA entry) */
 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+#ifdef CONFIG_DPP2
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DPP_PFS, ssid->dpp_pfs);
+#endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
 	} else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
 		int psk_set = 0;
@@ -3085,9 +3088,16 @@
 #endif /* CONFIG_OWE */
 
 #ifdef CONFIG_DPP2
-	if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
+	if (DPP_VERSION > 1 &&
+	    wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
 	    ssid->dpp_netaccesskey &&
 	    ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
+		struct rsn_pmksa_cache_entry *pmksa;
+
+		pmksa = pmksa_cache_get_current(wpa_s->wpa);
+		if (!pmksa || !pmksa->dpp_pfs)
+			goto pfs_fail;
+
 		dpp_pfs_free(wpa_s->dpp_pfs);
 		wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
 					      ssid->dpp_netaccesskey_len);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 2f95eeb..9a9ed8d 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1258,6 +1258,7 @@
 	struct wpa_radio_work *dpp_listen_work;
 	unsigned int dpp_pending_listen_freq;
 	unsigned int dpp_listen_freq;
+	struct os_reltime dpp_listen_end;
 	u8 dpp_allowed_roles;
 	int dpp_qr_mutual;
 	int dpp_netrole;
@@ -1285,6 +1286,7 @@
 #ifdef CONFIG_DPP2
 	struct dpp_pfs *dpp_pfs;
 	int dpp_pfs_fallback;
+	struct wpabuf *dpp_reconfig_announcement;
 	struct wpabuf *dpp_presence_announcement;
 	struct dpp_bootstrap_info *dpp_chirp_bi;
 	int dpp_chirp_freq;
@@ -1293,6 +1295,8 @@
 	int dpp_chirp_round;
 	int dpp_chirp_scan_done;
 	int dpp_chirp_listen;
+	struct wpa_ssid *dpp_reconfig_ssid;
+	int dpp_reconfig_ssid_id;
 #endif /* CONFIG_DPP2 */
 #ifdef CONFIG_TESTING_OPTIONS
 	char *dpp_config_obj_override;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 130c278..9f68b22 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -188,6 +188,7 @@
 	const u8 *ie;
 	struct wpa_ie_data adv;
 	int wpa2 = 0, ccmp = 0;
+	enum wpa_driver_if_type iftype;
 
 	/*
 	 * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
@@ -239,9 +240,12 @@
 		return;
 	}
 
+	iftype = ssid->p2p_group ? WPA_IF_P2P_CLIENT : WPA_IF_STATION;
+
 	if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
 	    (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
-	    (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+	    (capa.key_mgmt_iftype[iftype] &
+	     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
 		wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
 			   "based on scan results");
 		if (wpa_s->conf->ap_scan == 1)