git: f3ba7fe0d220 - stable/13 - wpa: Import wpa_supplicant/hostapd commit b26f5c0fe

From: Cy Schubert <cy_at_FreeBSD.org>
Date: Tue, 08 Feb 2022 01:09:22 UTC
The branch stable/13 has been updated by cy:

URL: https://cgit.FreeBSD.org/src/commit/?id=f3ba7fe0d2202c9a17513982ed5ac767618afbdc

commit f3ba7fe0d2202c9a17513982ed5ac767618afbdc
Author:     Cy Schubert <cy@FreeBSD.org>
AuthorDate: 2022-01-06 18:28:57 +0000
Commit:     Cy Schubert <cy@FreeBSD.org>
CommitDate: 2022-02-08 01:08:29 +0000

    wpa: Import wpa_supplicant/hostapd commit b26f5c0fe
    
    This is the December/January update to vendor/wpa committed upstream
    2021-12-13.
    
    (cherry picked from commit 32a95656b51ebefcdf3e0b02c110825f59abd26f)
---
 contrib/wpa/hostapd/Android.mk                     |   3 +
 contrib/wpa/hostapd/Makefile                       |   3 +
 contrib/wpa/hostapd/config_file.c                  |  10 +
 contrib/wpa/hostapd/ctrl_iface.c                   |  10 +-
 contrib/wpa/hostapd/defconfig                      |   8 +
 contrib/wpa/hostapd/hostapd.conf                   |   4 +
 contrib/wpa/src/ap/acs.c                           |   9 +
 contrib/wpa/src/ap/ap_config.h                     |   3 +
 contrib/wpa/src/ap/ap_drv_ops.c                    |   3 +-
 contrib/wpa/src/ap/beacon.c                        |   8 +-
 contrib/wpa/src/ap/dfs.c                           |   3 +
 contrib/wpa/src/ap/dpp_hostapd.c                   |  69 ++++-
 contrib/wpa/src/ap/drv_callbacks.c                 |   6 +
 contrib/wpa/src/ap/hostapd.c                       |  15 ++
 contrib/wpa/src/common/dpp.c                       |  41 ++-
 contrib/wpa/src/common/dpp.h                       |  19 +-
 contrib/wpa/src/common/dpp_crypto.c                |  55 ++--
 contrib/wpa/src/common/dpp_i.h                     |   1 +
 contrib/wpa/src/common/dpp_pkex.c                  | 237 ++++++++++++-----
 contrib/wpa/src/common/hw_features_common.c        | 141 +++++-----
 contrib/wpa/src/common/hw_features_common.h        |   1 -
 contrib/wpa/src/common/qca-vendor.h                |  41 ++-
 contrib/wpa/src/drivers/driver.h                   |   2 +
 contrib/wpa/src/drivers/driver_nl80211.c           |   3 +
 contrib/wpa/tests/hwsim/test_dpp3.py               |  49 ++++
 contrib/wpa/wpa_supplicant/Android.mk              |   3 +
 contrib/wpa/wpa_supplicant/Makefile                |   3 +
 contrib/wpa/wpa_supplicant/README-HS20             |   6 +
 contrib/wpa/wpa_supplicant/config.c                |  37 +++
 contrib/wpa/wpa_supplicant/config.h                |  34 +++
 contrib/wpa/wpa_supplicant/config_file.c           |  15 ++
 contrib/wpa/wpa_supplicant/config_ssid.h           |   5 +
 contrib/wpa/wpa_supplicant/ctrl_iface.c            |  63 +----
 contrib/wpa/wpa_supplicant/dbus/dbus_new.c         | 133 ++++++++++
 contrib/wpa/wpa_supplicant/dbus/dbus_new.h         |  27 ++
 .../wpa/wpa_supplicant/dbus/dbus_new_handlers.c    | 287 +++++++++++++++++++++
 .../wpa/wpa_supplicant/dbus/dbus_new_handlers.h    |  13 +
 .../wpa_supplicant/dbus/dbus_new_handlers_p2p.c    |   5 +-
 contrib/wpa/wpa_supplicant/defconfig               |   7 +-
 contrib/wpa/wpa_supplicant/dpp_supplicant.c        |  62 ++++-
 contrib/wpa/wpa_supplicant/events.c                |   2 +-
 contrib/wpa/wpa_supplicant/interworking.c          |  41 ++-
 contrib/wpa/wpa_supplicant/mesh.c                  |   6 +
 contrib/wpa/wpa_supplicant/mesh_mpm.c              |   5 +-
 contrib/wpa/wpa_supplicant/notify.c                |  30 +++
 contrib/wpa/wpa_supplicant/notify.h                |   7 +
 contrib/wpa/wpa_supplicant/sme.c                   |  54 ++--
 contrib/wpa/wpa_supplicant/sme.h                   |   6 +-
 contrib/wpa/wpa_supplicant/wpa_cli.c               |   1 +
 contrib/wpa/wpa_supplicant/wpa_supplicant.c        |  76 ++++++
 contrib/wpa/wpa_supplicant/wpa_supplicant.conf     |   3 +
 contrib/wpa/wpa_supplicant/wpa_supplicant_i.h      |   3 +
 52 files changed, 1380 insertions(+), 298 deletions(-)

diff --git a/contrib/wpa/hostapd/Android.mk b/contrib/wpa/hostapd/Android.mk
index dd8aa2450d7e..bf26e41c6b23 100644
--- a/contrib/wpa/hostapd/Android.mk
+++ b/contrib/wpa/hostapd/Android.mk
@@ -567,6 +567,9 @@ NEED_ASN1=y
 ifdef CONFIG_DPP2
 L_CFLAGS += -DCONFIG_DPP2
 endif
+ifdef CONFIG_DPP3
+L_CFLAGS += -DCONFIG_DPP3
+endif
 endif
 
 ifdef CONFIG_PASN
diff --git a/contrib/wpa/hostapd/Makefile b/contrib/wpa/hostapd/Makefile
index ac085fd10520..e37c13b27a6e 100644
--- a/contrib/wpa/hostapd/Makefile
+++ b/contrib/wpa/hostapd/Makefile
@@ -593,6 +593,9 @@ NEED_ASN1=y
 ifdef CONFIG_DPP2
 CFLAGS += -DCONFIG_DPP2
 endif
+ifdef CONFIG_DPP3
+CFLAGS += -DCONFIG_DPP3
+endif
 endif
 
 ifdef CONFIG_PASN
diff --git a/contrib/wpa/hostapd/config_file.c b/contrib/wpa/hostapd/config_file.c
index daf3f37ad99e..b14728d1b507 100644
--- a/contrib/wpa/hostapd/config_file.c
+++ b/contrib/wpa/hostapd/config_file.c
@@ -3193,6 +3193,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 		conf->acs_freq_list_present = 1;
 	} else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) {
 		conf->acs_exclude_6ghz_non_psc = atoi(pos);
+	} else if (os_strcmp(buf, "min_tx_power") == 0) {
+		int val = atoi(pos);
+
+		if (val < 0 || val > 255) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid min_tx_power %d (expected 0..255)",
+				   line, val);
+			return 1;
+		}
+		conf->min_tx_power = val;
 	} else if (os_strcmp(buf, "beacon_int") == 0) {
 		int val = atoi(pos);
 		/* MIB defines range as 1..65535, but very small values
diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c
index 6c99a3105f49..86adf18e5fe3 100644
--- a/contrib/wpa/hostapd/ctrl_iface.c
+++ b/contrib/wpa/hostapd/ctrl_iface.c
@@ -1504,7 +1504,7 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
 			return -1;
 
 		val = atoi(value);
-		if (val < 0 || val > 1)
+		if (val < 0 || val > MBO_ASSOC_DISALLOW_REASON_LOW_RSSI)
 			return -1;
 
 		hapd->mbo_assoc_disallow = val;
@@ -3463,7 +3463,9 @@ static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
 	if (os_strcmp(field, "dpp") == 0) {
 		int res;
 
-#ifdef CONFIG_DPP2
+#ifdef CONFIG_DPP3
+		res = os_snprintf(buf, buflen, "DPP=3");
+#elif defined(CONFIG_DPP2)
 		res = os_snprintf(buf, buflen, "DPP=2");
 #else /* CONFIG_DPP2 */
 		res = os_snprintf(buf, buflen, "DPP=1");
@@ -4492,7 +4494,9 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
 #ifdef CONFIG_TESTING_OPTIONS
 #ifdef CONFIG_DPP
 	dpp_test = DPP_TEST_DISABLED;
-#ifdef CONFIG_DPP2
+#ifdef CONFIG_DPP3
+	dpp_version_override = 3;
+#elif defined(CONFIG_DPP2)
 	dpp_version_override = 2;
 #else /* CONFIG_DPP2 */
 	dpp_version_override = 1;
diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig
index 666447e4ab40..6b50b6c59b46 100644
--- a/contrib/wpa/hostapd/defconfig
+++ b/contrib/wpa/hostapd/defconfig
@@ -402,3 +402,11 @@ CONFIG_IPV6=y
 # production use.
 # This requires CONFIG_IEEE80211W=y to be enabled, too.
 #CONFIG_PASN=y
+
+# Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect)
+CONFIG_DPP=y
+# DPP version 2 support
+CONFIG_DPP2=y
+# DPP version 3 support (experimental and still changing; do not enable for
+# production use)
+#CONFIG_DPP3=y
diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf
index 67d4cefb920b..3c2019f73048 100644
--- a/contrib/wpa/hostapd/hostapd.conf
+++ b/contrib/wpa/hostapd/hostapd.conf
@@ -225,6 +225,10 @@ channel=1
 # Default behavior is to include all PSC and non-PSC channels.
 #acs_exclude_6ghz_non_psc=1
 
+# Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection.
+# (default 0, i.e., not constraint)
+#min_tx_power=20
+
 # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
 beacon_int=100
 
diff --git a/contrib/wpa/src/ap/acs.c b/contrib/wpa/src/ap/acs.c
index 46429f265433..0030edc2a90f 100644
--- a/contrib/wpa/src/ap/acs.c
+++ b/contrib/wpa/src/ap/acs.c
@@ -546,6 +546,9 @@ static void acs_survey_mode_interference_factor(
 		if (!is_in_freqlist(iface, chan))
 			continue;
 
+		if (chan->max_tx_power < iface->conf->min_tx_power)
+			continue;
+
 		wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
 			   chan->chan, chan->freq);
 
@@ -673,6 +676,9 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
 		if (!is_in_freqlist(iface, chan))
 			continue;
 
+		if (chan->max_tx_power < iface->conf->min_tx_power)
+			continue;
+
 		if (!chan_bw_allowed(chan, bw, 1, 1)) {
 			wpa_printf(MSG_DEBUG,
 				   "ACS: Channel %d: BW %u is not supported",
@@ -1047,6 +1053,9 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
 		if (!is_in_freqlist(iface, chan))
 			continue;
 
+		if (chan->max_tx_power < iface->conf->min_tx_power)
+			continue;
+
 		*freq++ = chan->freq;
 	}
 
diff --git a/contrib/wpa/src/ap/ap_config.h b/contrib/wpa/src/ap/ap_config.h
index b8f791e56307..49cd3168a2fa 100644
--- a/contrib/wpa/src/ap/ap_config.h
+++ b/contrib/wpa/src/ap/ap_config.h
@@ -51,6 +51,7 @@ struct mesh_conf {
 	int dot11MeshRetryTimeout; /* msec */
 	int dot11MeshConfirmTimeout; /* msec */
 	int dot11MeshHoldingTimeout; /* msec */
+	int mesh_fwding;
 };
 
 #define MAX_STA_COUNT 2007
@@ -696,6 +697,7 @@ struct hostapd_bss_config {
 
 #define MESH_ENABLED BIT(0)
 	int mesh;
+	int mesh_fwding;
 
 	u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
 
@@ -953,6 +955,7 @@ struct hostapd_config {
 	struct wpa_freq_range_list acs_freq_list;
 	u8 acs_freq_list_present;
 	int acs_exclude_dfs;
+	u8 min_tx_power;
 	enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
 	int acs_exclude_6ghz_non_psc;
 	enum {
diff --git a/contrib/wpa/src/ap/ap_drv_ops.c b/contrib/wpa/src/ap/ap_drv_ops.c
index d1642d7dff15..e917736664bd 100644
--- a/contrib/wpa/src/ap/ap_drv_ops.c
+++ b/contrib/wpa/src/ap/ap_drv_ops.c
@@ -888,7 +888,8 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
 			continue;
 		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
 		    !(hapd->iface->conf->acs_exclude_dfs &&
-		      (chan->flag & HOSTAPD_CHAN_RADAR)))
+		      (chan->flag & HOSTAPD_CHAN_RADAR)) &&
+		    !(chan->max_tx_power < hapd->iface->conf->min_tx_power))
 			int_array_add_unique(freq_list, chan->freq);
 	}
 }
diff --git a/contrib/wpa/src/ap/beacon.c b/contrib/wpa/src/ap/beacon.c
index 22782f54e480..8cd1c417043e 100644
--- a/contrib/wpa/src/ap/beacon.c
+++ b/contrib/wpa/src/ap/beacon.c
@@ -570,9 +570,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 		pos = hostapd_eid_txpower_envelope(hapd, pos);
 #endif /* CONFIG_IEEE80211AX */
 
-	if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
-	    (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
-		pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
+	pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
 
 	pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP);
 	pos = hostapd_eid_fils_indic(hapd, pos, 0);
@@ -1594,9 +1592,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 		tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AX */
 
-	if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
-	    (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
-		tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
+	tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
 
 	tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON);
 	tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
diff --git a/contrib/wpa/src/ap/dfs.c b/contrib/wpa/src/ap/dfs.c
index 03c99b175215..5c99ecfd017e 100644
--- a/contrib/wpa/src/ap/dfs.c
+++ b/contrib/wpa/src/ap/dfs.c
@@ -246,6 +246,9 @@ static int dfs_find_channel(struct hostapd_iface *iface,
 			continue;
 		}
 
+		if (chan->max_tx_power < iface->conf->min_tx_power)
+			continue;
+
 		if (ret_chan && idx == channel_idx) {
 			wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
 				   chan->freq, chan->chan);
diff --git a/contrib/wpa/src/ap/dpp_hostapd.c b/contrib/wpa/src/ap/dpp_hostapd.c
index 41769f475544..13e1fc5bdd96 100644
--- a/contrib/wpa/src/ap/dpp_hostapd.c
+++ b/contrib/wpa/src/ap/dpp_hostapd.c
@@ -1554,17 +1554,38 @@ skip_status:
 
 #ifdef CONFIG_TESTING_OPTIONS
 skip_connector:
+	if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
+		goto skip_proto_ver;
+	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_DPP2
 	if (DPP_VERSION > 1) {
+		u8 ver = DPP_VERSION;
+#ifdef CONFIG_DPP3
+		int conn_ver;
+
+		conn_ver = dpp_get_connector_version(hapd->conf->dpp_connector);
+		if (conn_ver > 0 && ver != conn_ver) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Use Connector version %d instead of current protocol version %d",
+				   conn_ver, ver);
+			ver = conn_ver;
+		}
+#endif /* CONFIG_DPP3 */
+
 		/* Protocol Version */
 		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
 		wpabuf_put_le16(msg, 1);
-		wpabuf_put_u8(msg, DPP_VERSION);
+		wpabuf_put_u8(msg, ver);
 	}
 #endif /* CONFIG_DPP2 */
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_proto_ver:
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
 		   " status=%d", MAC2STR(src), status);
 	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
@@ -1648,6 +1669,28 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 		return;
 	}
 
+#ifdef CONFIG_DPP3
+	if (intro.peer_version && intro.peer_version >= 2) {
+		const u8 *version;
+		u16 version_len;
+		u8 attr_version = 1;
+
+		version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+				       &version_len);
+		if (version && version_len >= 1)
+			attr_version = version[0];
+		if (attr_version != intro.peer_version) {
+			wpa_printf(MSG_INFO,
+				   "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
+				   intro.peer_version, attr_version);
+			hostapd_dpp_send_peer_disc_resp(hapd, src, freq,
+							trans_id[0],
+							DPP_STATUS_NO_MATCH);
+			return;
+		}
+	}
+#endif /* CONFIG_DPP3 */
+
 	if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
 		expire = hapd->conf->dpp_netaccesskey_expiry;
 	if (expire)
@@ -1670,7 +1713,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 static void
 hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
 				 const u8 *buf, size_t len,
-				 unsigned int freq)
+				 unsigned int freq, bool v2)
 {
 	struct wpabuf *msg;
 
@@ -1698,7 +1741,7 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
 						  hapd->own_addr, src,
 						  hapd->dpp_pkex_identifier,
 						  hapd->dpp_pkex_code,
-						  buf, len);
+						  buf, len, v2);
 	if (!hapd->dpp_pkex) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Failed to process the request - ignore it");
@@ -1910,8 +1953,18 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
 	case DPP_PA_PEER_DISCOVERY_REQ:
 		hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq);
 		break;
+#ifdef CONFIG_DPP3
 	case DPP_PA_PKEX_EXCHANGE_REQ:
-		hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq);
+		/* This is for PKEXv2, but for now, process only with
+		 * CONFIG_DPP3 to avoid issues with a capability that has not
+		 * been tested with other implementations. */
+		hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
+						 true);
+		break;
+#endif /* CONFIG_DPP3 */
+	case DPP_PA_PKEX_V1_EXCHANGE_REQ:
+		hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
+						 false);
 		break;
 	case DPP_PA_PKEX_EXCHANGE_RESP:
 		hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq);
@@ -2118,15 +2171,16 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
 	if (!hapd->dpp_pkex_code)
 		return -1;
 
-	if (os_strstr(cmd, " init=1")) {
+	if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
 		struct wpabuf *msg;
+		bool v2 = os_strstr(cmd, " init=2") != NULL;
 
 		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
 		dpp_pkex_free(hapd->dpp_pkex);
 		hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
 					       hapd->own_addr,
 					       hapd->dpp_pkex_identifier,
-					       hapd->dpp_pkex_code);
+					       hapd->dpp_pkex_code, v2);
 		if (!hapd->dpp_pkex)
 			return -1;
 
@@ -2134,7 +2188,8 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
 		/* TODO: Which channel to use? */
 		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
 			" freq=%u type=%d", MAC2STR(broadcast), 2437,
-			DPP_PA_PKEX_EXCHANGE_REQ);
+			v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+			DPP_PA_PKEX_V1_EXCHANGE_REQ);
 		hostapd_drv_send_action(hapd, 2437, 0, broadcast,
 					wpabuf_head(msg), wpabuf_len(msg));
 	}
diff --git a/contrib/wpa/src/ap/drv_callbacks.c b/contrib/wpa/src/ap/drv_callbacks.c
index ec5abf166b23..a50e6f2afa77 100644
--- a/contrib/wpa/src/ap/drv_callbacks.c
+++ b/contrib/wpa/src/ap/drv_callbacks.c
@@ -957,6 +957,12 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 	hapd->iconf->ch_switch_vht_config = 0;
 	hapd->iconf->ch_switch_he_config = 0;
 
+	if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 ||
+	    width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160)
+		hapd->iconf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+	else if (width == CHAN_WIDTH_20 || width == CHAN_WIDTH_20_NOHT)
+		hapd->iconf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+
 	hapd->iconf->secondary_channel = offset;
 	hostapd_set_oper_chwidth(hapd->iconf, chwidth);
 	hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
diff --git a/contrib/wpa/src/ap/hostapd.c b/contrib/wpa/src/ap/hostapd.c
index 913a8e29e16d..4b88641a2dde 100644
--- a/contrib/wpa/src/ap/hostapd.c
+++ b/contrib/wpa/src/ap/hostapd.c
@@ -3461,6 +3461,20 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 				    NULL))
 		return -1;
 
+	switch (params->bandwidth) {
+	case 0:
+	case 20:
+		conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+		break;
+	case 40:
+	case 80:
+	case 160:
+		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+		break;
+	default:
+		return -1;
+	}
+
 	switch (params->bandwidth) {
 	case 0:
 	case 20:
@@ -3482,6 +3496,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 
 	conf->channel = channel;
 	conf->ieee80211n = params->ht_enabled;
+	conf->ieee80211ac = params->vht_enabled;
 	conf->secondary_channel = params->sec_channel_offset;
 	ieee80211_freq_to_chan(params->center_freq1,
 			       &seg0);
diff --git a/contrib/wpa/src/common/dpp.c b/contrib/wpa/src/common/dpp.c
index 1fd074f05627..ac6eae4c893e 100644
--- a/contrib/wpa/src/common/dpp.c
+++ b/contrib/wpa/src/common/dpp.c
@@ -28,7 +28,9 @@
 static const char * dpp_netrole_str(enum dpp_netrole netrole);
 
 #ifdef CONFIG_TESTING_OPTIONS
-#ifdef CONFIG_DPP2
+#ifdef CONFIG_DPP3
+int dpp_version_override = 3;
+#elif defined(CONFIG_DPP2)
 int dpp_version_override = 2;
 #else
 int dpp_version_override = 1;
@@ -306,6 +308,8 @@ int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
 		bi->version = 1;
 	else if (*version == '2')
 		bi->version = 2;
+	else if (*version == '3')
+		bi->version = 3;
 	else
 		wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
 
@@ -628,7 +632,8 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi)
 		    macstr,
 		    bi->info ? "I:" : "", bi->info ? bi->info : "",
 		    bi->info ? ";" : "",
-		    DPP_VERSION == 2 ? "V:2;" : "",
+		    DPP_VERSION == 3 ? "V:3;" :
+		    (DPP_VERSION == 2 ? "V:2;" : ""),
 		    bi->pk);
 	return 0;
 }
@@ -1499,6 +1504,10 @@ skip_groups:
 		json_value_sep(dppcon);
 		json_add_string(dppcon, "expiry", expiry);
 	}
+#ifdef CONFIG_DPP3
+	json_value_sep(dppcon);
+	json_add_int(dppcon, "version", auth->peer_version);
+#endif /* CONFIG_DPP3 */
 	json_end_object(dppcon);
 	wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
 		   (const char *) wpabuf_head(dppcon));
@@ -3694,6 +3703,14 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
 		}
 	}
 
+#ifdef CONFIG_DPP3
+	token = json_get_member(root, "version");
+	if (token && token->type == JSON_NUMBER) {
+		wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
+		intro->peer_version = token->number;
+	}
+#endif /* CONFIG_DPP3 */
+
 	netkey = json_get_member(root, "netAccessKey");
 	if (!netkey || netkey->type != JSON_OBJECT) {
 		wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
@@ -3751,6 +3768,26 @@ fail:
 }
 
 
+#ifdef CONFIG_DPP3
+int dpp_get_connector_version(const char *connector)
+{
+	struct json_token *root, *token;
+	int ver = -1;
+
+	root = dpp_parse_own_connector(connector);
+	if (!root)
+		return -1;
+
+	token = json_get_member(root, "version");
+	if (token && token->type == JSON_NUMBER)
+		ver = token->number;
+
+	json_free(root);
+	return ver;
+}
+#endif /* CONFIG_DPP3 */
+
+
 unsigned int dpp_next_id(struct dpp_global *dpp)
 {
 	struct dpp_bootstrap_info *bi;
diff --git a/contrib/wpa/src/common/dpp.h b/contrib/wpa/src/common/dpp.h
index a47c685f64b9..8d62a0e2ac3b 100644
--- a/contrib/wpa/src/common/dpp.h
+++ b/contrib/wpa/src/common/dpp.h
@@ -25,7 +25,9 @@ struct dpp_reconfig_id;
 #define DPP_VERSION (dpp_version_override)
 extern int dpp_version_override;
 #else /* CONFIG_TESTING_OPTIONS */
-#ifdef CONFIG_DPP2
+#ifdef CONFIG_DPP3
+#define DPP_VERSION 3
+#elif defined(CONFIG_DPP2)
 #define DPP_VERSION 2
 #else
 #define DPP_VERSION 1
@@ -41,7 +43,7 @@ enum dpp_public_action_frame_type {
 	DPP_PA_AUTHENTICATION_CONF = 2,
 	DPP_PA_PEER_DISCOVERY_REQ = 5,
 	DPP_PA_PEER_DISCOVERY_RESP = 6,
-	DPP_PA_PKEX_EXCHANGE_REQ = 7,
+	DPP_PA_PKEX_V1_EXCHANGE_REQ = 7,
 	DPP_PA_PKEX_EXCHANGE_RESP = 8,
 	DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
 	DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
@@ -52,6 +54,7 @@ enum dpp_public_action_frame_type {
 	DPP_PA_RECONFIG_AUTH_REQ = 15,
 	DPP_PA_RECONFIG_AUTH_RESP = 16,
 	DPP_PA_RECONFIG_AUTH_CONF = 17,
+	DPP_PA_PKEX_EXCHANGE_REQ = 18,
 };
 
 enum dpp_attribute_id {
@@ -173,6 +176,7 @@ struct dpp_pkex {
 	unsigned int initiator:1;
 	unsigned int exchange_done:1;
 	unsigned int failed:1;
+	unsigned int v2:1;
 	struct dpp_bootstrap_info *own_bi;
 	u8 own_mac[ETH_ALEN];
 	u8 peer_mac[ETH_ALEN];
@@ -190,6 +194,7 @@ struct dpp_pkex {
 	unsigned int exch_req_wait_time;
 	unsigned int exch_req_tries;
 	unsigned int freq;
+	u8 peer_version;
 };
 
 enum dpp_akm {
@@ -372,6 +377,7 @@ struct dpp_introduction {
 	u8 pmkid[PMKID_LEN];
 	u8 pmk[PMK_LEN_MAX];
 	size_t pmk_len;
+	int peer_version;
 };
 
 struct dpp_relay_config {
@@ -491,6 +497,8 @@ enum dpp_test_behavior {
 	DPP_TEST_STOP_AT_AUTH_CONF = 89,
 	DPP_TEST_STOP_AT_CONF_REQ = 90,
 	DPP_TEST_REJECT_CONFIG = 91,
+	DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ = 92,
+	DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP = 93,
 };
 
 extern enum dpp_test_behavior dpp_test;
@@ -593,17 +601,18 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
 	       const u8 *csign_key, size_t csign_key_len,
 	       const u8 *peer_connector, size_t peer_connector_len,
 	       os_time_t *expiry);
+int dpp_get_connector_version(const char *connector);
 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 				const u8 *own_mac,
-				const char *identifier,
-				const char *code);
+				const char *identifier, const char *code,
+				bool v2);
 struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 					   struct dpp_bootstrap_info *bi,
 					   const u8 *own_mac,
 					   const u8 *peer_mac,
 					   const char *identifier,
 					   const char *code,
-					   const u8 *buf, size_t len);
+					   const u8 *buf, size_t len, bool v2);
 struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
 					  const u8 *peer_mac,
 					  const u8 *buf, size_t len);
diff --git a/contrib/wpa/src/common/dpp_crypto.c b/contrib/wpa/src/common/dpp_crypto.c
index da59730eb7b7..300416fb12ec 100644
--- a/contrib/wpa/src/common/dpp_crypto.c
+++ b/contrib/wpa/src/common/dpp_crypto.c
@@ -1447,12 +1447,15 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
 	struct crypto_bignum *hash_bn = NULL;
 	struct crypto_ec *ec = NULL;
 
-	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+	/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
 
-	wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
-	addr[num_elem] = mac_init;
-	len[num_elem] = ETH_ALEN;
-	num_elem++;
+	if (mac_init) {
+		wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR,
+			   MAC2STR(mac_init));
+		addr[num_elem] = mac_init;
+		len[num_elem] = ETH_ALEN;
+		num_elem++;
+	}
 	if (identifier) {
 		wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
 			   identifier);
@@ -1467,7 +1470,7 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
 	if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
 		goto fail;
 	wpa_hexdump_key(MSG_DEBUG,
-			"DPP: H(MAC-Initiator | [identifier |] code)",
+			"DPP: H([MAC-Initiator |] [identifier |] code)",
 			hash, curve->hash_len);
 	Pi_key = dpp_pkex_get_role_elem(curve, 1);
 	if (!Pi_key)
@@ -1519,12 +1522,15 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
 	struct crypto_bignum *hash_bn = NULL;
 	struct crypto_ec *ec = NULL;
 
-	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+	/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
 
-	wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
-	addr[num_elem] = mac_resp;
-	len[num_elem] = ETH_ALEN;
-	num_elem++;
+	if (mac_resp) {
+		wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR,
+			   MAC2STR(mac_resp));
+		addr[num_elem] = mac_resp;
+		len[num_elem] = ETH_ALEN;
+		num_elem++;
+	}
 	if (identifier) {
 		wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
 			   identifier);
@@ -1539,7 +1545,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
 	if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
 		goto fail;
 	wpa_hexdump_key(MSG_DEBUG,
-			"DPP: H(MAC-Responder | [identifier |] code)",
+			"DPP: H([MAC-Responder |] [identifier |] code)",
 			hash, curve->hash_len);
 	Pr_key = dpp_pkex_get_role_elem(curve, 0);
 	if (!Pr_key)
@@ -1578,6 +1584,7 @@ fail:
 
 
 int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
+		      u8 ver_init, u8 ver_resp,
 		      const u8 *Mx, size_t Mx_len,
 		      const u8 *Nx, size_t Nx_len,
 		      const char *code,
@@ -1589,7 +1596,10 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
 	u8 *info, *pos;
 	size_t info_len;
 
-	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+	/*
+	 * v1: info = MAC-Initiator | MAC-Responder
+	 * v2: info = Protocol Version-Initiator | Protocol Version-Responder
+	 * z = HKDF(<>, info | M.x | N.x | code, K.x)
 	 */
 
 	/* HKDF-Extract(<>, IKM=K.x) */
@@ -1598,15 +1608,24 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
 		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
 			prk, hash_len);
-	info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
+	if (mac_init && mac_resp)
+		info_len = 2 * ETH_ALEN;
+	else
+		info_len = 2;
+	info_len += Mx_len + Nx_len + os_strlen(code);
 	info = os_malloc(info_len);
 	if (!info)
 		return -1;
 	pos = info;
-	os_memcpy(pos, mac_init, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, mac_resp, ETH_ALEN);
-	pos += ETH_ALEN;
+	if (mac_init && mac_resp) {
+		os_memcpy(pos, mac_init, ETH_ALEN);
+		pos += ETH_ALEN;
+		os_memcpy(pos, mac_resp, ETH_ALEN);
+		pos += ETH_ALEN;
+	} else {
+		*pos++ = ver_init;
+		*pos++ = ver_resp;
+	}
 	os_memcpy(pos, Mx, Mx_len);
 	pos += Mx_len;
 	os_memcpy(pos, Nx, Nx_len);
diff --git a/contrib/wpa/src/common/dpp_i.h b/contrib/wpa/src/common/dpp_i.h
index 087878a508cb..c00b1ee41240 100644
--- a/contrib/wpa/src/common/dpp_i.h
+++ b/contrib/wpa/src/common/dpp_i.h
@@ -118,6 +118,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
 		   const char *code, const char *identifier,
 		   struct crypto_ec **ret_ec);
 int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
+		      u8 ver_init, u8 ver_resp,
 		      const u8 *Mx, size_t Mx_len,
 		      const u8 *Nx, size_t Nx_len,
 		      const char *code,
diff --git a/contrib/wpa/src/common/dpp_pkex.c b/contrib/wpa/src/common/dpp_pkex.c
index 06532b5457bd..38349fa3f540 100644
--- a/contrib/wpa/src/common/dpp_pkex.c
+++ b/contrib/wpa/src/common/dpp_pkex.c
@@ -26,7 +26,8 @@ size_t dpp_pkex_ephemeral_key_override_len = 0;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
-static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
+static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
+						   bool v2)
 {
 	struct crypto_ec *ec = NULL;
 	const struct crypto_ec_point *X;
@@ -36,10 +37,11 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
 	size_t attr_len;
 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
 
-	wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
+	wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request",
+		   v2 ? "" : "Version 1 ");
 
-	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
-	Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
+	/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
+	Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
 				pkex->identifier, &ec);
 	if (!Qi)
 		goto fail;
@@ -76,13 +78,27 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
 
 	/* Initiator -> Responder: group, [identifier,] M */
 	attr_len = 4 + 2;
+#ifdef CONFIG_DPP2
+	if (v2)
+		attr_len += 4 + 1;
+#endif /* CONFIG_DPP2 */
 	if (pkex->identifier)
 		attr_len += 4 + os_strlen(pkex->identifier);
 	attr_len += 4 + 2 * curve->prime_len;
-	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
+	msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+			    DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len);
 	if (!msg)
 		goto fail;
 
+#ifdef CONFIG_DPP2
+	if (v2) {
+		/* Protocol Version */
+		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+		wpabuf_put_le16(msg, 1);
+		wpabuf_put_u8(msg, DPP_VERSION);
+	}
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
 		wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
@@ -154,8 +170,8 @@ static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
 
 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 				const u8 *own_mac,
-				const char *identifier,
-				const char *code)
+				const char *identifier, const char *code,
+				bool v2)
 {
 	struct dpp_pkex *pkex;
 
@@ -172,6 +188,7 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 		return NULL;
 	pkex->msg_ctx = msg_ctx;
 	pkex->initiator = 1;
+	pkex->v2 = v2;
 	pkex->own_bi = bi;
 	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
 	if (identifier) {
@@ -182,7 +199,7 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 	pkex->code = os_strdup(code);
 	if (!pkex->code)
 		goto fail;
-	pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
+	pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
 	if (!pkex->exchange_req)
 		goto fail;
 	return pkex;
@@ -201,8 +218,13 @@ dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
 	size_t attr_len;
 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
 
-	/* Initiator -> Responder: DPP Status, [identifier,] N */
+	/* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,]
+	 * N */
 	attr_len = 4 + 1;
+#ifdef CONFIG_DPP2
+	if (pkex->v2)
+		attr_len += 4 + 1;
+#endif /* CONFIG_DPP2 */
 	if (pkex->identifier)
 		attr_len += 4 + os_strlen(pkex->identifier);
 	attr_len += 4 + 2 * curve->prime_len;
@@ -229,6 +251,15 @@ dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
 skip_status:
 #endif /* CONFIG_TESTING_OPTIONS */
 
+#ifdef CONFIG_DPP2
+	if (pkex->v2) {
+		/* Protocol Version */
+		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+		wpabuf_put_le16(msg, 1);
+		wpabuf_put_u8(msg, DPP_VERSION);
+	}
+#endif /* CONFIG_DPP2 */
+
 	/* Code Identifier attribute */
 	if (pkex->identifier) {
 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
@@ -310,7 +341,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 					   const u8 *peer_mac,
 					   const char *identifier,
 					   const char *code,
-					   const u8 *buf, size_t len)
+					   const u8 *buf, size_t len, bool v2)
 {
 	const u8 *attr_group, *attr_id, *attr_key;
 	u16 attr_group_len, attr_id_len, attr_key_len;
@@ -325,6 +356,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
 	size_t Kx_len;
 	int res;
+	u8 peer_version = 0;
 
 	if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
@@ -332,6 +364,24 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 		return NULL;
 	}
 
+#ifdef CONFIG_DPP2
+	if (v2) {
+		const u8 *version;
+		u16 version_len;
+
+		version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+				       &version_len);
+		if (!version || version_len < 1 || version[0] == 0) {
+			wpa_msg(msg_ctx, MSG_INFO,
+				"Missing or invalid Protocol Version attribute");
+			return NULL;
+		}
+		peer_version = version[0];
+		wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+			   peer_version);
+	}
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
 		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
@@ -366,6 +416,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 		pkex = os_zalloc(sizeof(*pkex));
 		if (!pkex)
 			goto fail;
+		pkex->v2 = v2;
+		pkex->peer_version = peer_version;
 		pkex->own_bi = bi;
 		pkex->failed = 1;
 		pkex->exchange_resp = dpp_pkex_build_exchange_resp(
@@ -385,8 +437,9 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 		return NULL;
 	}
 
-	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
-	Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, &ec);
+	/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
+	Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier,
+				&ec);
 	if (!Qi)
 		goto fail;
 
@@ -411,6 +464,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 	pkex = os_zalloc(sizeof(*pkex));
 	if (!pkex)
 		goto fail;
+	pkex->v2 = v2;
+	pkex->peer_version = peer_version;
 	pkex->t = bi->pkex_t;
 	pkex->msg_ctx = msg_ctx;
 	pkex->own_bi = bi;
@@ -438,8 +493,9 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
 	if (!pkex->x)
 		goto fail;
 
-	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
-	Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, NULL);
*** 2189 LINES SKIPPED ***