[wpa_supplicant] Cumulative patch from commit 09a281e52

Bug: 237446599
Test: connect/disconnect to WPA2, WPA3 networks
Test: SoftAp & p2p connection
Test: Regression test(b/237480760)

BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from Open source

09a281e52 Add QCA vendor interface for PASN offload to userspace
809fb96fa Add a vendor attribute to configure concurrency policy for AP interface
a5754f531 Rename QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY
085a3fc76 EHT: Add 320 channel width support
bafe35df0 Move CHANWIDTH_* definitions from ieee80211_defs.h to defs.h
3c2ba98ad Add QCA vendor event to indicate driver recovery after internal failures
6b461f68c Set current_ssid before changing state to ASSOCIATING
8dd826741 QCA vendor attribute to configure direct data path for audio traffic
504be2f9d QCA vendor command support to get WLAN radio combinations
d5905dbc8 OCV: Check the Frequency Segment 1 Channel Number only on 80+80 MHz
4383528e0 P2P: Use weighted preferred channel list for channel selection
f2c5c8d38 QCA vendor attribute to configure RX link speed threshold for roaming
94bc94b20 Add QCA vendor attribute for DO_ACS to allow using existing scan entries
b9e2826b9 P2P: Filter 6 GHz channels if peer doesn't support them
d5a9944b8 Reserve QCA vendor sub command id 206..212
ed63c286f Remove space before tab in QCA vendor commands
e4015440a ProxyARP: Clear bridge parameters on deinit only if hostapd set them
02047e9c8 hs20-osu-client: Explicit checks for snprintf() result
cd92f7f98 FIPS PRF: Avoid duplicate SHA1Init() functionality
5c87fcc15 OpenSSL: Use internal FIPS 186-2 PRF with OpenSSL 3.0
9e305878c SAE-PK: Fix build without AES-SIV
c41004d86 OpenSSL: Convert more crypto_ec_key routines to new EVP API
667a2959c OpenSSL: crypto_ec_key_get_public_key() using new EVP_PKEY API
5b97395b3 OpenSSL: crypto_ec_key_get_private_key() using new EVP_PKEY API
177ebfe10 crypto: Convert crypto_ec_key_get_public_key() to return new ec_point
26780d92f crypto: Convert crypto_ec_key_get_private_key() to return new bignum
c9c2c2d9c OpenSSL: Fix a memory leak on crypto_hash_init() error path
6d19dccf9 OpenSSL: Free OSSL_DECODER_CTX in tls_global_dh()
4f4479ef9 OpenSSL: crypto_ec_key_parse_{priv,pub}() without EC_KEY API
563699174 EAP-SIM/AKA peer: IMSI privacy attribute
1004fb7ee tests: Testing functionality to discard DPP Public Action frames
99165cc4b Rename wpa_supplicant imsi_privacy_key configuration parameter
35eda6e70 EAP-SIM peer: Free imsi_privacy_key on an error path
1328cdeb1 Do not try to use network profile with invalid imsi_privacy_key
d1652dc7c OpenSSL: Refuse to accept expired RSA certificate
866e7b745 OpenSSL: Include rsa.h for OpenSSL 3.0
bc99366f9 OpenSSL: Drop security level to 0 with OpenSSL 3.0 when using TLS 1.0/1.1
ed325ff0f DPP: Allow TCP destination (address/port) to be used from peer URI
37bb4178b DPP: Host information in bootstrapping URI
1142b6e41 EHT: Do not check HE PHY capability info reserved fields
bc3699179 Use Secure=1 in PTK rekeying EAPOL-Key msg 1/4 and 2/4
b859b9bce Simplify wpa_bss_get_vendor_ie_multi_beacon() bounds checking
fc9648a6a DPP: Debug print if not relay is available for PKEX exchange
1739d50c2 FST: More robust bounds checking of local data in fst_dump_mb_ies()
63eb98a8e SAE: Make Anti-Clogging token element parsing simpler
a6e04a067 Simplify DSCP policy parsing
77bb12a60 P2P: Maintain ip_pool bitfield index separately
3f3ce0571 Check sscanf() return value in TWT_SETUP parsing
2982e50c1 EAP-SAKA: Simplify attribute parser for static analyzers
6e8518749 GAS: Limit maximum comeback delay value
fe1dc9ba7 WNM: Try to make bounds checking easier for static analyzers
f8615990e Simplify wpa_parse_kde_ies()
61d37f44b Simplify wpa_parse_generic()
469528a6e BSS coloring: Fix bitmap check
8392c86df Check he_cap pointer in hostapd_set_freq_params() consistently
2227c85a9 DPP: Verify that crypto_ec_point_to_bin() succeeds
a8c319952 nl80211: Verify that nla_put_flag() succeeds for background radar
993eb1240 FST: Make sure get_hw_modes() callback is set for hostapd
4537fe124 P2P: Explicit nul termination of the generated passphrase
79dc7f619 scan: Add option to disable 6 GHz collocated scanning
3b8d9da9b nl80211: Set NL80211_SCAN_FLAG_COLOCATED_6GHZ in scan
96a7f3832 hostapd: Add the destination address of unsolicited Probe Response frame
16e755754 Add -q flag to hostapd in order to control log level
869037443 Discard unencrypted EAPOL/EAP when TK is set and PMF is enabled (AP)
3c2fbe9f5 Discard unencrypted EAPOL-EAP when TK is set and PMF is enabled
872a57500 Discard unencrypted EAPOL-Key msg 1/4 when TK is set and PMF is enabled
e6c0e1215 Do not prevent Michael MIC error report based on disallowed PTK0 rekey
18c0ac890 Provide information about the encryption status of received EAPOL frames
7ee814201 FILS: Set pairwise_set when configuring TK after association
98278c0de Fix no_encrypt flag in control port TX for rekeying
b1172c19e WPA: Discard EAPOL-Key msg 1/4 with corrupted information elements
7a7a4ea57 Check need for SA Query/assoc comeback before updating RSNE parameters

Change-Id: Ifbfe69676b38499a221aeb242cdb3eac3deee375
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index adb4c08..14a7464 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -272,6 +272,7 @@
 OBJS += src/common/sae.c
 ifdef CONFIG_SAE_PK
 L_CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
 OBJS += src/common/sae_pk.c
 endif
 NEED_ECC=y
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 5f06378..88a2e18 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -295,6 +295,7 @@
 OBJS += ../src/common/sae.o
 ifdef CONFIG_SAE_PK
 CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
 OBJS += ../src/common/sae_pk.o
 endif
 NEED_ECC=y
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index 11d1290..5af8978 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -670,27 +670,27 @@
 		   iconf->vht_oper_chwidth, iconf->ieee80211n,
 		   iconf->secondary_channel);
 	switch (iconf->vht_oper_chwidth) {
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		return ChannelBandwidth::BANDWIDTH_80;
-	case CHANWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		return ChannelBandwidth::BANDWIDTH_80P80;
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		return ChannelBandwidth::BANDWIDTH_160;
 		break;
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		if (iconf->ieee80211n) {
 			return iconf->secondary_channel != 0 ?
 				ChannelBandwidth::BANDWIDTH_40 : ChannelBandwidth::BANDWIDTH_20;
 		}
 		return ChannelBandwidth::BANDWIDTH_20_NOHT;
-	case CHANWIDTH_2160MHZ:
+	case CONF_OPER_CHWIDTH_2160MHZ:
 		return ChannelBandwidth::BANDWIDTH_2160;
-	case CHANWIDTH_4320MHZ:
+	case CONF_OPER_CHWIDTH_4320MHZ:
 		return ChannelBandwidth::BANDWIDTH_4320;
-	case CHANWIDTH_6480MHZ:
+	case CONF_OPER_CHWIDTH_6480MHZ:
 		return ChannelBandwidth::BANDWIDTH_6480;
-	case CHANWIDTH_8640MHZ:
+	case CONF_OPER_CHWIDTH_8640MHZ:
 		return ChannelBandwidth::BANDWIDTH_8640;
 	default:
 		return ChannelBandwidth::BANDWIDTH_INVALID;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index ad994d4..6bebcbf 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1686,7 +1686,7 @@
 		return -1;
 	}
 
-	ieee802_1x_receive(hapd, src, buf, len);
+	ieee802_1x_receive(hapd, src, buf, len, FRAME_ENCRYPTION_UNKNOWN);
 	os_free(buf);
 
 	return 0;
@@ -2531,6 +2531,9 @@
 	case 160:
 		bandwidth = CHAN_WIDTH_160;
 		break;
+	case 320:
+		bandwidth = CHAN_WIDTH_320;
+		break;
 	default:
 		bandwidth = CHAN_WIDTH_20;
 		break;
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index f37d563..6b4223f 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -871,7 +871,7 @@
 # he_oper_chwidth is ignored, and the channel width is derived from the
 # configured operating class or center frequency indexes (see
 # IEEE P802.11ax/D6.1 Annex E, Table E-4).
-#he_oper_chwidth
+#he_oper_chwidth (see vht_oper_chwidth)
 #he_oper_centr_freq_seg0_idx
 #he_oper_centr_freq_seg1_idx
 
@@ -1021,7 +1021,7 @@
 # In the 6 GHz band, eht_oper_chwidth is ignored and the channel width is
 # derived from the configured operating class (IEEE P802.11be/D1.5,
 # Annex E.1 - Country information and operating classes).
-#eht_oper_chwidth
+#eht_oper_chwidth (see vht_oper_chwidth)
 #eht_oper_centr_freq_seg0_idx
 
 ##### IEEE 802.1X-2004 related configuration ##################################
diff --git a/hostapd/main.c b/hostapd/main.c
index eab57b6..74c7904 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -468,7 +468,7 @@
 	show_version();
 	fprintf(stderr,
 		"\n"
-		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
+		"usage: hostapd [-hdBKtvq] [-P <PID file>] [-e <entropy file>] "
 		"\\\n"
 		"         [-g <global ctrl_iface>] [-G <group>]\\\n"
 		"         [-i <comma-separated list of interface names>]\\\n"
@@ -687,7 +687,7 @@
 #endif /* CONFIG_DPP */
 
 	for (;;) {
-		c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
+		c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -760,6 +760,9 @@
 							&if_names_size, optarg))
 				goto out;
 			break;
+		case 'q':
+			wpa_debug_level++;
+			break;
 		default:
 			usage();
 			break;
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 7b274da..01e7b75 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2018,6 +2018,7 @@
 	struct osu_data *osu = NULL, *last = NULL;
 	size_t osu_count = 0;
 	char *pos, *end;
+	int res;
 
 	f = fopen(fname, "r");
 	if (f == NULL) {
@@ -2037,15 +2038,20 @@
 			osu = last;
 			last = &osu[osu_count++];
 			memset(last, 0, sizeof(*last));
-			snprintf(last->bssid, sizeof(last->bssid), "%s",
-				 buf + 13);
+			res = os_snprintf(last->bssid, sizeof(last->bssid),
+					  "%s", buf + 13);
+			if (os_snprintf_error(sizeof(last->bssid), res))
+				break;
 			continue;
 		}
 		if (!last)
 			continue;
 
 		if (strncmp(buf, "uri=", 4) == 0) {
-			snprintf(last->url, sizeof(last->url), "%s", buf + 4);
+			res = os_snprintf(last->url, sizeof(last->url),
+					  "%s", buf + 4);
+			if (os_snprintf_error(sizeof(last->url), res))
+				break;
 			continue;
 		}
 
@@ -2055,26 +2061,37 @@
 		}
 
 		if (strncmp(buf, "osu_ssid=", 9) == 0) {
-			snprintf(last->osu_ssid, sizeof(last->osu_ssid),
-				 "%s", buf + 9);
+			res = os_snprintf(last->osu_ssid,
+					  sizeof(last->osu_ssid),
+					  "%s", buf + 9);
+			if (os_snprintf_error(sizeof(last->osu_ssid), res))
+				break;
 			continue;
 		}
 
 		if (strncmp(buf, "osu_ssid2=", 10) == 0) {
-			snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
-				 "%s", buf + 10);
+			res = os_snprintf(last->osu_ssid2,
+					  sizeof(last->osu_ssid2),
+					  "%s", buf + 10);
+			if (os_snprintf_error(sizeof(last->osu_ssid2), res))
+				break;
 			continue;
 		}
 
 		if (os_strncmp(buf, "osu_nai=", 8) == 0) {
-			os_snprintf(last->osu_nai, sizeof(last->osu_nai),
-				    "%s", buf + 8);
+			res = os_snprintf(last->osu_nai, sizeof(last->osu_nai),
+					  "%s", buf + 8);
+			if (os_snprintf_error(sizeof(last->osu_nai), res))
+				break;
 			continue;
 		}
 
 		if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
-			os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
-				    "%s", buf + 9);
+			res = os_snprintf(last->osu_nai2,
+					  sizeof(last->osu_nai2),
+					  "%s", buf + 9);
+			if (os_snprintf_error(sizeof(last->osu_nai2), res))
+				break;
 			continue;
 		}
 
@@ -2087,8 +2104,14 @@
 				continue;
 			*pos++ = '\0';
 			txt = &last->friendly_name[last->friendly_name_count++];
-			snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14);
-			snprintf(txt->text, sizeof(txt->text), "%s", pos);
+			res = os_snprintf(txt->lang, sizeof(txt->lang),
+					  "%s", buf + 14);
+			if (os_snprintf_error(sizeof(txt->lang), res))
+				break;
+			res = os_snprintf(txt->text, sizeof(txt->text),
+					  "%s", pos);
+			if (os_snprintf_error(sizeof(txt->text), res))
+				break;
 		}
 
 		if (strncmp(buf, "desc=", 5) == 0) {
@@ -2100,8 +2123,14 @@
 				continue;
 			*pos++ = '\0';
 			txt = &last->serv_desc[last->serv_desc_count++];
-			snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5);
-			snprintf(txt->text, sizeof(txt->text), "%s", pos);
+			res = os_snprintf(txt->lang, sizeof(txt->lang),
+					  "%s", buf + 5);
+			if (os_snprintf_error(sizeof(txt->lang), res))
+				break;
+			res = os_snprintf(txt->text, sizeof(txt->text),
+					  "%s", pos);
+			if (os_snprintf_error(sizeof(txt->text), res))
+				break;
 		}
 
 		if (strncmp(buf, "icon=", 5) == 0) {
@@ -2124,23 +2153,30 @@
 			if (!end)
 				continue;
 			*end = '\0';
-			snprintf(icon->lang, sizeof(icon->lang), "%s", pos);
+			res = os_snprintf(icon->lang, sizeof(icon->lang),
+					  "%s", pos);
+			if (os_snprintf_error(sizeof(icon->lang), res))
+				break;
 			pos = end + 1;
 
 			end = strchr(pos, ':');
 			if (end)
 				*end = '\0';
-			snprintf(icon->mime_type, sizeof(icon->mime_type),
-				 "%s", pos);
-			if (!pos)
+			res = os_snprintf(icon->mime_type,
+					  sizeof(icon->mime_type), "%s", pos);
+			if (os_snprintf_error(sizeof(icon->mime_type), res))
+				break;
+			if (!end)
 				continue;
 			pos = end + 1;
 
 			end = strchr(pos, ':');
 			if (end)
 				*end = '\0';
-			snprintf(icon->filename, sizeof(icon->filename),
-				 "%s", pos);
+			res = os_snprintf(icon->filename,
+					  sizeof(icon->filename), "%s", pos);
+			if (os_snprintf_error(sizeof(icon->filename), res))
+				break;
 			continue;
 		}
 	}
diff --git a/src/ap/acs.c b/src/ap/acs.c
index faaedbf..7708bc2 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -710,7 +710,7 @@
 		if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
 		    (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
 			if (hostapd_get_oper_chwidth(iface->conf) ==
-			    CHANWIDTH_80MHZ &&
+			    CONF_OPER_CHWIDTH_80MHZ &&
 			    !acs_usable_bw80_chan(chan)) {
 				wpa_printf(MSG_DEBUG,
 					   "ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
@@ -719,7 +719,7 @@
 			}
 
 			if (hostapd_get_oper_chwidth(iface->conf) ==
-			    CHANWIDTH_160MHZ &&
+			    CONF_OPER_CHWIDTH_160MHZ &&
 			    !acs_usable_bw160_chan(chan)) {
 				wpa_printf(MSG_DEBUG,
 					   "ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
@@ -873,12 +873,14 @@
 
 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
 		switch (hostapd_get_oper_chwidth(iface->conf)) {
-		case CHANWIDTH_80MHZ:
+		case CONF_OPER_CHWIDTH_80MHZ:
 			n_chans = 4;
 			break;
-		case CHANWIDTH_160MHZ:
+		case CONF_OPER_CHWIDTH_160MHZ:
 			n_chans = 8;
 			break;
+		default:
+			break;
 		}
 	}
 
@@ -915,13 +917,13 @@
 	wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
 
 	switch (hostapd_get_oper_chwidth(iface->conf)) {
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		offset = 2 * iface->conf->secondary_channel;
 		break;
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		offset = 6;
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		offset = 14;
 		break;
 	default:
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b97d49c..05a1b05 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1048,7 +1048,7 @@
 	u32 vht_capab;
 	int ieee80211ac;
 	int require_vht;
-	u8 vht_oper_chwidth;
+	enum oper_chan_width vht_oper_chwidth;
 	u8 vht_oper_centr_freq_seg0_idx;
 	u8 vht_oper_centr_freq_seg1_idx;
 	u8 ht40_plus_minus_allowed;
@@ -1094,7 +1094,7 @@
 	struct he_operation he_op;
 	struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
 	struct spatial_reuse spr;
-	u8 he_oper_chwidth;
+	enum oper_chan_width he_oper_chwidth;
 	u8 he_oper_centr_freq_seg0_idx;
 	u8 he_oper_centr_freq_seg1_idx;
 	u8 he_6ghz_max_mpdu;
@@ -1132,7 +1132,7 @@
 
 	int ieee80211be;
 #ifdef CONFIG_IEEE80211BE
-	u8 eht_oper_chwidth;
+	enum oper_chan_width eht_oper_chwidth;
 	u8 eht_oper_centr_freq_seg0_idx;
 	struct eht_phy_capabilities_info eht_phy_capab;
 #endif /* CONFIG_IEEE80211BE */
@@ -1144,7 +1144,8 @@
 };
 
 
-static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
+static inline enum oper_chan_width
+hostapd_get_oper_chwidth(struct hostapd_config *conf)
 {
 #ifdef CONFIG_IEEE80211BE
 	if (conf->ieee80211be)
@@ -1158,11 +1159,14 @@
 }
 
 static inline void
-hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
+hostapd_set_oper_chwidth(struct hostapd_config *conf,
+			 enum oper_chan_width oper_chwidth)
 {
 #ifdef CONFIG_IEEE80211BE
 	if (conf->ieee80211be)
 		conf->eht_oper_chwidth = oper_chwidth;
+	if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
+		oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
 #endif /* CONFIG_IEEE80211BE */
 #ifdef CONFIG_IEEE80211AX
 	if (conf->ieee80211ax)
@@ -1192,6 +1196,9 @@
 #ifdef CONFIG_IEEE80211BE
 	if (conf->ieee80211be)
 		conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+	if (center_idx_to_bw_6ghz(oper_centr_freq_seg0_idx) == 4)
+		oper_centr_freq_seg0_idx +=
+			conf->channel > oper_centr_freq_seg0_idx ? 16 : -16;
 #endif /* CONFIG_IEEE80211BE */
 #ifdef CONFIG_IEEE80211AX
 	if (conf->ieee80211ax)
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 8af7a0e..87c3b90 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -978,13 +978,16 @@
 	     hapd->iface->conf->ieee80211ax ||
 	     hapd->iface->conf->ieee80211ac) &&
 	    params.ht40_enabled) {
-		u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
+		enum oper_chan_width oper_chwidth;
 
-		if (oper_chwidth == CHANWIDTH_80MHZ)
+		oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
+		if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
 			params.ch_width = 80;
-		else if (oper_chwidth == CHANWIDTH_160MHZ ||
-			 oper_chwidth == CHANWIDTH_80P80MHZ)
+		else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
+			 oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
 			params.ch_width = 160;
+		else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
+			params.ch_width = 320;
 	}
 
 	if (hapd->iface->conf->op_class)
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index eaa4033..8676570 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -464,7 +464,8 @@
 
 static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 				   const struct ieee80211_mgmt *req,
-				   int is_p2p, size_t *resp_len)
+				   int is_p2p, size_t *resp_len,
+				   bool bcast_probe_resp)
 {
 	struct ieee80211_mgmt *resp;
 	u8 *pos, *epos, *csa_pos;
@@ -531,6 +532,9 @@
 					   WLAN_FC_STYPE_PROBE_RESP);
 	if (req)
 		os_memcpy(resp->da, req->sa, ETH_ALEN);
+	else if (bcast_probe_resp)
+		os_memset(resp->da, 0xff, ETH_ALEN);
+
 	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
 
 	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
@@ -1141,7 +1145,7 @@
 		     " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
 
 	resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
-				      &resp_len);
+				      &resp_len, false);
 	if (resp == NULL)
 		return;
 
@@ -1210,7 +1214,7 @@
 			   "this");
 
 	/* Generate a Probe Response template for the non-P2P case */
-	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
+	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false);
 }
 
 #endif /* NEED_AP_MLME */
@@ -1228,7 +1232,8 @@
 		hapd->conf->unsol_bcast_probe_resp_interval;
 
 	return hostapd_gen_probe_resp(hapd, NULL, 0,
-				      &params->unsol_bcast_probe_resp_tmpl_len);
+				      &params->unsol_bcast_probe_resp_tmpl_len,
+				      true);
 }
 #endif /* CONFIG_IEEE80211AX */
 
@@ -1275,22 +1280,24 @@
 		}
 	} else {
 		switch (hostapd_get_oper_chwidth(hapd->iconf)) {
-		case CHANWIDTH_80P80MHZ:
+		case CONF_OPER_CHWIDTH_80P80MHZ:
 			mcs_nss_size += 4;
 			/* fallthrough */
-		case CHANWIDTH_160MHZ:
+		case CONF_OPER_CHWIDTH_160MHZ:
 			mcs_nss_size += 4;
 			chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
 			break;
-		case CHANWIDTH_80MHZ:
+		case CONF_OPER_CHWIDTH_80MHZ:
 			chwidth = FD_CAP_BSS_CHWIDTH_80;
 			break;
-		case CHANWIDTH_USE_HT:
+		case CONF_OPER_CHWIDTH_USE_HT:
 			if (hapd->iconf->secondary_channel)
 				chwidth = FD_CAP_BSS_CHWIDTH_40;
 			else
 				chwidth = FD_CAP_BSS_CHWIDTH_20;
 			break;
+		default:
+			break;
 		}
 
 #ifdef CONFIG_IEEE80211AX
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index e46dd7e..146dd1a 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -50,15 +50,15 @@
 
 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
 		switch (hostapd_get_oper_chwidth(iface->conf)) {
-		case CHANWIDTH_USE_HT:
+		case CONF_OPER_CHWIDTH_USE_HT:
 			break;
-		case CHANWIDTH_80MHZ:
+		case CONF_OPER_CHWIDTH_80MHZ:
 			n_chans = 4;
 			break;
-		case CHANWIDTH_160MHZ:
+		case CONF_OPER_CHWIDTH_160MHZ:
 			n_chans = 8;
 			break;
-		case CHANWIDTH_80P80MHZ:
+		case CONF_OPER_CHWIDTH_80P80MHZ:
 			n_chans = 4;
 			*seg1 = 4;
 			break;
@@ -311,7 +311,7 @@
 	*oper_centr_freq_seg1_idx = 0;
 
 	switch (hostapd_get_oper_chwidth(iface->conf)) {
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		if (secondary_channel == 1)
 			*oper_centr_freq_seg0_idx = chan->chan + 2;
 		else if (secondary_channel == -1)
@@ -319,13 +319,13 @@
 		else
 			*oper_centr_freq_seg0_idx = chan->chan;
 		break;
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		*oper_centr_freq_seg0_idx = chan->chan + 6;
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		*oper_centr_freq_seg0_idx = chan->chan + 14;
 		break;
-	case CHANWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		*oper_centr_freq_seg0_idx = chan->chan + 6;
 		*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
 		break;
@@ -361,17 +361,17 @@
 	/* VHT/HE */
 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
 		switch (hostapd_get_oper_chwidth(iface->conf)) {
-		case CHANWIDTH_USE_HT:
+		case CONF_OPER_CHWIDTH_USE_HT:
 			break;
-		case CHANWIDTH_80MHZ:
+		case CONF_OPER_CHWIDTH_80MHZ:
 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
 				iface->conf) - 6;
 			break;
-		case CHANWIDTH_160MHZ:
+		case CONF_OPER_CHWIDTH_160MHZ:
 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
 				iface->conf) - 14;
 			break;
-		case CHANWIDTH_80P80MHZ:
+		case CONF_OPER_CHWIDTH_80P80MHZ:
 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
 				iface->conf) - 6;
 			chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
@@ -555,7 +555,8 @@
 		*secondary_channel = 0;
 
 	/* Get secondary channel for HT80P80 */
-	if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
+	if (hostapd_get_oper_chwidth(iface->conf) ==
+	    CONF_OPER_CHWIDTH_80P80MHZ) {
 		if (num_available_chandefs <= 1) {
 			wpa_printf(MSG_ERROR,
 				   "only 1 valid chan, can't support 80+80");
@@ -1220,7 +1221,7 @@
 			int oper_chwidth;
 
 			oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
-			if (oper_chwidth == CHANWIDTH_USE_HT)
+			if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
 				break;
 			*channel_type = DFS_AVAILABLE;
 			hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index d4cbed8..2613c0c 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -832,7 +832,17 @@
 	}
 
 	addr = get_param(cmd, " tcp_addr=");
-	if (addr) {
+	if (addr && os_strcmp(addr, "from-uri") == 0) {
+		os_free(addr);
+		if (!peer_bi->host) {
+			wpa_printf(MSG_INFO,
+				   "DPP: TCP address not available in peer URI");
+			return -1;
+		}
+		tcp = 1;
+		os_memcpy(&ipaddr, peer_bi->host, sizeof(ipaddr));
+		tcp_port = peer_bi->port;
+	} else if (addr) {
 		int res;
 
 		res = hostapd_parse_ip_addr(addr, &ipaddr);
@@ -2064,9 +2074,11 @@
 
 try_relay:
 #ifdef CONFIG_DPP2
-	if (v2)
-		dpp_relay_rx_action(hapd->iface->interfaces->dpp,
-				    src, hdr, buf, len, freq, NULL, NULL, hapd);
+	if (v2 && dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+				      src, hdr, buf, len, freq, NULL, NULL,
+				      hapd) != 0)
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No Relay available for the message");
 #else /* CONFIG_DPP2 */
 	wpa_printf(MSG_DEBUG, "DPP: No relay functionality included - skip");
 #endif /* CONFIG_DPP2 */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 643a273..b1cb31e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -340,6 +340,16 @@
 		}
 #endif /* CONFIG_WPS */
 
+		if (check_sa_query_need(hapd, sta)) {
+			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+
+			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+					  p - buf);
+			return 0;
+		}
+
 		if (sta->wpa_sm == NULL)
 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
 							sta->addr,
@@ -420,16 +430,6 @@
 			goto fail;
 		}
 
-		if (check_sa_query_need(hapd, sta)) {
-			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
-
-			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-
-			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
-					  p - buf);
-			return 0;
-		}
-
 		if (wpa_auth_uses_mfp(sta->wpa_sm))
 			sta->flags |= WLAN_STA_MFP;
 		else
@@ -838,6 +838,9 @@
 	case CHAN_WIDTH_160:
 		txt = "160";
 		break;
+	case CHAN_WIDTH_320:
+		txt = "320";
+		break;
 	default:
 		txt = NULL;
 		break;
@@ -891,19 +894,22 @@
 
 	switch (width) {
 	case CHAN_WIDTH_80:
-		chwidth = CHANWIDTH_80MHZ;
+		chwidth = CONF_OPER_CHWIDTH_80MHZ;
 		break;
 	case CHAN_WIDTH_80P80:
-		chwidth = CHANWIDTH_80P80MHZ;
+		chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
 		break;
 	case CHAN_WIDTH_160:
-		chwidth = CHANWIDTH_160MHZ;
+		chwidth = CONF_OPER_CHWIDTH_160MHZ;
+		break;
+	case CHAN_WIDTH_320:
+		chwidth = CONF_OPER_CHWIDTH_320MHZ;
 		break;
 	case CHAN_WIDTH_20_NOHT:
 	case CHAN_WIDTH_20:
 	case CHAN_WIDTH_40:
 	default:
-		chwidth = CHANWIDTH_USE_HT;
+		chwidth = CONF_OPER_CHWIDTH_USE_HT;
 		break;
 	}
 
@@ -979,10 +985,10 @@
 	hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
 	if (hapd->iconf->ieee80211ac) {
 		hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
-		if (chwidth == CHANWIDTH_160MHZ)
+		if (chwidth == CONF_OPER_CHWIDTH_160MHZ)
 			hapd->iconf->vht_capab |=
 				VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
-		else if (chwidth == CHANWIDTH_80P80MHZ)
+		else if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
 			hapd->iconf->vht_capab |=
 				VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
 	}
@@ -1145,7 +1151,7 @@
 		/* set defaults for backwards compatibility */
 		hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
 		hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
-		hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
+		hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_USE_HT);
 		if (acs_res->ch_width == 40) {
 			if (is_6ghz_freq(acs_res->pri_freq))
 				hostapd_set_oper_centr_freq_seg0_idx(
@@ -1155,22 +1161,33 @@
 			hostapd_set_oper_centr_freq_seg0_idx(
 				hapd->iconf, acs_res->vht_seg0_center_ch);
 			if (acs_res->vht_seg1_center_ch == 0) {
-				hostapd_set_oper_chwidth(hapd->iconf,
-							 CHANWIDTH_80MHZ);
+				hostapd_set_oper_chwidth(
+					hapd->iconf, CONF_OPER_CHWIDTH_80MHZ);
 			} else {
-				hostapd_set_oper_chwidth(hapd->iconf,
-							 CHANWIDTH_80P80MHZ);
+				hostapd_set_oper_chwidth(
+					hapd->iconf,
+					CONF_OPER_CHWIDTH_80P80MHZ);
 				hostapd_set_oper_centr_freq_seg1_idx(
 					hapd->iconf,
 					acs_res->vht_seg1_center_ch);
 			}
 		} else if (acs_res->ch_width == 160) {
-			hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
+			hostapd_set_oper_chwidth(hapd->iconf,
+						 CONF_OPER_CHWIDTH_160MHZ);
 			hostapd_set_oper_centr_freq_seg0_idx(
 				hapd->iconf, acs_res->vht_seg1_center_ch);
 		}
 	}
 
+#ifdef CONFIG_IEEE80211BE
+	if (hapd->iface->conf->ieee80211be && acs_res->ch_width == 320) {
+		hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_320MHZ);
+		hostapd_set_oper_centr_freq_seg0_idx(
+			hapd->iconf, acs_res->vht_seg1_center_ch);
+		hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
+	}
+#endif /* CONFIG_IEEE80211BE */
+
 out:
 	ret = hostapd_acs_completed(hapd->iface, err);
 	if (ret) {
@@ -1543,7 +1560,8 @@
 
 
 static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
-				   const u8 *data, size_t data_len)
+				   const u8 *data, size_t data_len,
+				   enum frame_encryption encrypted)
 {
 	struct hostapd_iface *iface = hapd->iface;
 	struct sta_info *sta;
@@ -1557,7 +1575,7 @@
 		}
 	}
 
-	ieee802_1x_receive(hapd, src, data, data_len);
+	ieee802_1x_receive(hapd, src, data, data_len, encrypted);
 }
 
 #endif /* HOSTAPD */
@@ -1952,7 +1970,8 @@
 	case EVENT_EAPOL_RX:
 		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
 				       data->eapol_rx.data,
-				       data->eapol_rx.data_len);
+				       data->eapol_rx.data_len,
+				       data->eapol_rx.encrypted);
 		break;
 	case EVENT_ASSOC:
 		if (!data)
diff --git a/src/ap/gas_query_ap.c b/src/ap/gas_query_ap.c
index fdb3cad..3d94407 100644
--- a/src/ap/gas_query_ap.c
+++ b/src/ap/gas_query_ap.c
@@ -29,6 +29,8 @@
 #define GAS_QUERY_WAIT_TIME_INITIAL 1000
 #define GAS_QUERY_WAIT_TIME_COMEBACK 150
 
+#define GAS_QUERY_MAX_COMEBACK_DELAY 60000
+
 /**
  * struct gas_query_pending - Pending GAS query
  */
@@ -545,6 +547,8 @@
 	if (pos + 2 > data + len)
 		return 0;
 	comeback_delay = WPA_GET_LE16(pos);
+	if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY)
+		comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY;
 	pos += 2;
 
 	/* Advertisement Protocol element */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ef53c41..05faa0f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1718,7 +1718,7 @@
 			goto fail;
 
 		if (iface->conf->op_class) {
-			int ch_width;
+			enum oper_chan_width ch_width;
 
 			ch_width = op_class_to_ch_width(iface->conf->op_class);
 			hostapd_set_oper_chwidth(iface->conf, ch_width);
@@ -1784,6 +1784,16 @@
 }
 
 
+static int fst_hostapd_get_hw_modes_cb(void *ctx,
+				       struct hostapd_hw_modes **modes)
+{
+	struct hostapd_data *hapd = ctx;
+
+	*modes = hapd->iface->hw_features;
+	return hapd->iface->num_hw_features;
+}
+
+
 static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
 {
 	struct hostapd_data *hapd = ctx;
@@ -1876,9 +1886,11 @@
 void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
 				struct fst_wpa_obj *iface_obj)
 {
+	os_memset(iface_obj, 0, sizeof(*iface_obj));
 	iface_obj->ctx = hapd;
 	iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
 	iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
+	iface_obj->get_hw_modes = fst_hostapd_get_hw_modes_cb;
 	iface_obj->set_ies = fst_hostapd_set_ies_cb;
 	iface_obj->send_action = fst_hostapd_send_action_cb;
 	iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
@@ -3491,16 +3503,21 @@
 	case 0:
 	case 20:
 	case 40:
-		hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+		hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_USE_HT);
 		break;
 	case 80:
 		if (params->center_freq2)
-			hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ);
+			hostapd_set_oper_chwidth(conf,
+						 CONF_OPER_CHWIDTH_80P80MHZ);
 		else
-			hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
+			hostapd_set_oper_chwidth(conf,
+						 CONF_OPER_CHWIDTH_80MHZ);
 		break;
 	case 160:
-		hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
+		hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ);
+		break;
+	case 320:
+		hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_320MHZ);
 		break;
 	default:
 		return -1;
@@ -3538,15 +3555,15 @@
 	switch (settings->freq_params.bandwidth) {
 	case 80:
 		if (settings->freq_params.center_freq2)
-			bandwidth = CHANWIDTH_80P80MHZ;
+			bandwidth = CONF_OPER_CHWIDTH_80P80MHZ;
 		else
-			bandwidth = CHANWIDTH_80MHZ;
+			bandwidth = CONF_OPER_CHWIDTH_80MHZ;
 		break;
 	case 160:
-		bandwidth = CHANWIDTH_160MHZ;
+		bandwidth = CONF_OPER_CHWIDTH_160MHZ;
 		break;
 	default:
-		bandwidth = CHANWIDTH_USE_HT;
+		bandwidth = CONF_OPER_CHWIDTH_USE_HT;
 		break;
 	}
 
@@ -3676,7 +3693,8 @@
 hostapd_switch_channel_fallback(struct hostapd_iface *iface,
 				const struct hostapd_freq_params *freq_params)
 {
-	int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT;
+	int seg0_idx = 0, seg1_idx = 0;
+	enum oper_chan_width bw = CONF_OPER_CHWIDTH_USE_HT;
 
 	wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
 
@@ -3689,16 +3707,19 @@
 	case 0:
 	case 20:
 	case 40:
-		bw = CHANWIDTH_USE_HT;
+		bw = CONF_OPER_CHWIDTH_USE_HT;
 		break;
 	case 80:
 		if (freq_params->center_freq2)
-			bw = CHANWIDTH_80P80MHZ;
+			bw = CONF_OPER_CHWIDTH_80P80MHZ;
 		else
-			bw = CHANWIDTH_80MHZ;
+			bw = CONF_OPER_CHWIDTH_80MHZ;
 		break;
 	case 160:
-		bw = CHANWIDTH_160MHZ;
+		bw = CONF_OPER_CHWIDTH_160MHZ;
+		break;
+	case 320:
+		bw = CONF_OPER_CHWIDTH_320MHZ;
 		break;
 	default:
 		wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
@@ -3792,7 +3813,7 @@
 
 	r = os_random() % HE_OPERATION_BSS_COLOR_MAX;
 	for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) {
-		if (r && !(hapd->color_collision_bitmap & BIT(r)))
+		if (r && !(hapd->color_collision_bitmap & (1ULL << r)))
 			break;
 
 		r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 6b9b65f..15d59dc 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -324,6 +324,7 @@
 #ifdef CONFIG_PROXYARP
 	struct l2_packet_data *sock_dhcp;
 	struct l2_packet_data *sock_ndisc;
+	bool x_snoop_initialized;
 #endif /* CONFIG_PROXYARP */
 #ifdef CONFIG_MESH
 	int num_plinks;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 4b66b02..ed5ff41 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -371,7 +371,7 @@
 		iface->conf->secondary_channel = 0;
 		hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
 		hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
-		hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
+		hostapd_set_oper_chwidth(iface->conf, CONF_OPER_CHWIDTH_USE_HT);
 		res = 1;
 		wpa_printf(MSG_INFO, "Fallback to 20 MHz");
 	}
@@ -1087,13 +1087,14 @@
 
 	if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
 	     iface->conf->ieee80211n || iface->conf->ieee80211ac ||
-	     iface->conf->ieee80211ax) &&
+	     iface->conf->ieee80211ax || iface->conf->ieee80211be) &&
 	    iface->conf->channel == 14) {
-		wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
+		wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14");
 		iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
 		iface->conf->ieee80211n = 0;
 		iface->conf->ieee80211ac = 0;
 		iface->conf->ieee80211ax = 0;
+		iface->conf->ieee80211be = 0;
 	}
 
 	iface->current_mode = NULL;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 394e292..8806a58 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -4629,6 +4629,9 @@
 	if (hapd->conf->wpa && wpa_ie) {
 		enum wpa_validate_result res;
 
+		if (check_sa_query(hapd, sta, reassoc))
+			return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
 		wpa_ie -= 2;
 		wpa_ie_len += 2;
 		if (sta->wpa_sm == NULL)
@@ -4652,9 +4655,6 @@
 		if (resp != WLAN_STATUS_SUCCESS)
 			return resp;
 
-		if (check_sa_query(hapd, sta, reassoc))
-			return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
-
 		if (wpa_auth_uses_mfp(sta->wpa_sm))
 			sta->flags |= WLAN_STA_MFP;
 		else
@@ -6589,7 +6589,8 @@
 			ieee802_1x_receive(
 				hapd, mgmt->da,
 				wpabuf_head(sta->pending_eapol_rx->buf),
-				wpabuf_len(sta->pending_eapol_rx->buf));
+				wpabuf_len(sta->pending_eapol_rx->buf),
+				sta->pending_eapol_rx->encrypted);
 		}
 		wpabuf_free(sta->pending_eapol_rx->buf);
 		os_free(sta->pending_eapol_rx);
@@ -7032,7 +7033,7 @@
 #endif /* CONFIG_IEEE80211AX */
 
 	switch (hostapd_get_oper_chwidth(iconf)) {
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		if (iconf->secondary_channel == 0) {
 			/* Max Transmit Power count = 0 (20 MHz) */
 			tx_pwr_count = 0;
@@ -7041,12 +7042,12 @@
 			tx_pwr_count = 1;
 		}
 		break;
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
 		tx_pwr_count = 2;
 		break;
-	case CHANWIDTH_80P80MHZ:
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
 		tx_pwr_count = 3;
 		break;
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index dbbf9a6..ec36a9e 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -41,25 +41,41 @@
 }
 
 
-static u8 ieee80211_eht_mcs_set_size(const u8 *he_phy_cap,
+static u8 ieee80211_eht_mcs_set_size(enum hostapd_hw_mode mode, u8 opclass,
+				     const u8 *he_phy_cap,
 				     const u8 *eht_phy_cap)
 {
 	u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+	bool band24, band5, band6;
 
-	if ((he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
-	    (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
-	     HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
-	     HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
-	     HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0)
+	band24 = mode == HOSTAPD_MODE_IEEE80211B ||
+		mode == HOSTAPD_MODE_IEEE80211G ||
+		mode == NUM_HOSTAPD_MODES;
+	band5 = mode == HOSTAPD_MODE_IEEE80211A ||
+		mode == NUM_HOSTAPD_MODES;
+	band6 = is_6ghz_op_class(opclass);
+
+	if (band24 &&
+	    (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+	     HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0)
 		return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
 
-	if (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
-	    (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
-	     HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))
-		sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+	if (band5 &&
+	    (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+	     (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+	      HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+	      HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0)
+		return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
 
-	if (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
-	    EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
+	if (band5 &&
+	    (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+	     (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+	      HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)))
+	    sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+	if (band6 &&
+	    (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+	     EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK))
 		sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
 
 	return sz;
@@ -81,7 +97,8 @@
 	if (!eht_cap->eht_supported)
 		return 0;
 
-	len += ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+	len += ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class,
+					  mode->he_capab[opmode].phy_cap,
 					  eht_cap->phy_cap);
 	len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]),
 				       eht_cap->phy_cap);
@@ -133,7 +150,9 @@
 
 	pos = cap->optional;
 
-	mcs_nss_len = ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+	mcs_nss_len = ieee80211_eht_mcs_set_size(mode->mode,
+						 hapd->iconf->op_class,
+						 mode->he_capab[opmode].phy_cap,
 						 eht_cap->phy_cap);
 	if (mcs_nss_len) {
 		os_memcpy(pos, eht_cap->mcs, mcs_nss_len);
@@ -157,7 +176,8 @@
 {
 	struct hostapd_config *conf = hapd->iconf;
 	struct ieee80211_eht_operation *oper;
-	u8 *pos = eid, chwidth, seg0 = 0, seg1 = 0;
+	u8 *pos = eid, seg0 = 0, seg1 = 0;
+	enum oper_chan_width chwidth;
 
 	if (!hapd->iface->current_mode)
 		return eid;
@@ -177,9 +197,7 @@
 	seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf);
 
 	switch (chwidth) {
-#if 0 /* FIX: Need to clean up CHANWIDTH_* use for protocol vs. internal
-       * needs to be able to define this. */
-	case CHANWIDTH_320MHZ:
+	case CONF_OPER_CHWIDTH_320MHZ:
 		oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ;
 		seg1 = seg0;
 		if (hapd->iconf->channel < seg0)
@@ -187,8 +205,7 @@
 		else
 			seg0 += 16;
 		break;
-#endif
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ;
 		seg1 = seg0;
 		if (hapd->iconf->channel < seg0)
@@ -196,10 +213,10 @@
 		else
 			seg0 += 8;
 		break;
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ;
 		break;
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		if (seg0)
 			oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_40MHZ;
 		break;
@@ -257,7 +274,8 @@
 	capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab;
 	sta_mcs = capab->optional;
 
-	if (ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+	if (ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class,
+				       mode->he_capab[opmode].phy_cap,
 				       mode->eht_capab[opmode].phy_cap) ==
 	    EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY)
 		return check_valid_eht_mcs_nss(
@@ -265,10 +283,14 @@
 			EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY);
 
 	switch (hapd->iface->conf->eht_oper_chwidth) {
-	/* TODO: CHANWIDTH_320MHZ */
-	case CHANWIDTH_80P80MHZ:
-	case CHANWIDTH_160MHZ:
-		mcs_count = 2;
+	case CONF_OPER_CHWIDTH_320MHZ:
+		mcs_count++;
+		/* fall through */
+	case CONF_OPER_CHWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
+		mcs_count++;
+		break;
+	default:
 		break;
 	}
 
@@ -277,7 +299,9 @@
 }
 
 
-static bool ieee80211_invalid_eht_cap_size(const u8 *he_cap, const u8 *eht_cap,
+static bool ieee80211_invalid_eht_cap_size(enum hostapd_hw_mode mode,
+					   u8 opclass,
+					   const u8 *he_cap, const u8 *eht_cap,
 					   size_t len)
 {
 	const struct ieee80211_he_capabilities *he_capab;
@@ -293,7 +317,8 @@
 	if (len < cap_len)
 		return true;
 
-	cap_len += ieee80211_eht_mcs_set_size(he_phy_cap, cap->phy_cap);
+	cap_len += ieee80211_eht_mcs_set_size(mode, opclass, he_phy_cap,
+					      cap->phy_cap);
 	if (len < cap_len)
 		return true;
 
@@ -310,10 +335,14 @@
 		       const u8 *he_capab, size_t he_capab_len,
 		       const u8 *eht_capab, size_t eht_capab_len)
 {
+	struct hostapd_hw_modes *c_mode = hapd->iface->current_mode;
+	enum hostapd_hw_mode mode = c_mode ? c_mode->mode : NUM_HOSTAPD_MODES;
+
 	if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be ||
 	    !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN ||
 	    !eht_capab ||
-	    ieee80211_invalid_eht_cap_size(he_capab, eht_capab,
+	    ieee80211_invalid_eht_cap_size(mode, hapd->iconf->op_class,
+					   he_capab, eht_capab,
 					   eht_capab_len) ||
 	    !check_valid_eht_mcs(hapd, eht_capab, opmode)) {
 		sta->flags &= ~WLAN_STA_EHT;
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 1e74c58..b5b7e5d 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -102,20 +102,22 @@
 					   mode->he_capab[opmode].phy_cap);
 
 	switch (hapd->iface->conf->he_oper_chwidth) {
-	case CHANWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		he_oper_chwidth |=
 			HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
 		mcs_nss_size += 4;
 		/* fall through */
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
 		mcs_nss_size += 4;
 		/* fall through */
-	case CHANWIDTH_80MHZ:
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
 			HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
 		break;
+	default:
+		break;
 	}
 
 	ie_size += mcs_nss_size + ppet_size;
@@ -217,7 +219,7 @@
 	pos += 6; /* skip the fixed part */
 
 	if (is_6ghz_op_class(hapd->iconf->op_class)) {
-		u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+		u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx;
 		u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
 		u8 control;
 
@@ -430,10 +432,10 @@
 	 * band/stream cases.
 	 */
 	switch (hapd->iface->conf->he_oper_chwidth) {
-	case CHANWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		mcs_count = 3;
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		mcs_count = 2;
 		break;
 	default:
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 6154895..4e7c33e 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -998,7 +998,7 @@
 		 * If a VHT Operation element was present, use it to determine
 		 * the supported channel bandwidth.
 		 */
-		if (oper->vht_op_info_chwidth == 0) {
+		if (oper->vht_op_info_chwidth == CHANWIDTH_USE_HT) {
 			requested_bw = ht_40mhz ? 40 : 20;
 		} else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
 			requested_bw = 80;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 828f0ab..681b6d7 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -96,12 +96,12 @@
 		hapd->iconf->vht_oper_centr_freq_seg1_idx;
 
 	oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
-	if (hapd->iconf->vht_oper_chwidth == 2) {
+	if (hapd->iconf->vht_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
 		/*
 		 * Convert 160 MHz channel width to new style as interop
 		 * workaround.
 		 */
-		oper->vht_op_info_chwidth = 1;
+		oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
 		oper->vht_op_info_chan_center_freq_seg1_idx =
 			oper->vht_op_info_chan_center_freq_seg0_idx;
 		if (hapd->iconf->channel <
@@ -109,12 +109,13 @@
 			oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
 		else
 			oper->vht_op_info_chan_center_freq_seg0_idx += 8;
-	} else if (hapd->iconf->vht_oper_chwidth == 3) {
+	} else if (hapd->iconf->vht_oper_chwidth ==
+		   CONF_OPER_CHWIDTH_80P80MHZ) {
 		/*
 		 * Convert 80+80 MHz channel width to new style as interop
 		 * workaround.
 		 */
-		oper->vht_op_info_chwidth = 1;
+		oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
 	}
 
 	/* VHT Basic MCS set comes from hw */
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index fb5e920..d90792c 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -998,7 +998,7 @@
 
 
 static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
-				  size_t len)
+				  size_t len, enum frame_encryption encrypted)
 {
 	if (sta->pending_eapol_rx) {
 		wpabuf_free(sta->pending_eapol_rx->buf);
@@ -1016,21 +1016,39 @@
 		return;
 	}
 
+	sta->pending_eapol_rx->encrypted = encrypted;
 	os_get_reltime(&sta->pending_eapol_rx->rx_time);
 }
 
 
+static bool ieee802_1x_check_encryption(struct sta_info *sta,
+					enum frame_encryption encrypted,
+					u8 type)
+{
+	if (encrypted != FRAME_NOT_ENCRYPTED)
+		return true;
+	if (type != IEEE802_1X_TYPE_EAP_PACKET &&
+	    type != IEEE802_1X_TYPE_EAPOL_START &&
+	    type != IEEE802_1X_TYPE_EAPOL_LOGOFF)
+		return true;
+	if (!(sta->flags & WLAN_STA_MFP))
+		return true;
+	return !wpa_auth_pairwise_set(sta->wpa_sm);
+}
+
+
 /**
  * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
  * @hapd: hostapd BSS data
  * @sa: Source address (sender of the EAPOL frame)
  * @buf: EAPOL frame
  * @len: Length of buf in octets
+ * @encrypted: Whether the frame was encrypted
  *
  * This function is called for each incoming EAPOL frame from the interface
  */
 void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
-			size_t len)
+			size_t len, enum frame_encryption encrypted)
 {
 	struct sta_info *sta;
 	struct ieee802_1x_hdr *hdr;
@@ -1043,8 +1061,9 @@
 	    !hapd->conf->wps_state)
 		return;
 
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
-		   (unsigned long) len, MAC2STR(sa));
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR
+		   " (encrypted=%d)",
+		   (unsigned long) len, MAC2STR(sa), encrypted);
 	sta = ap_get_sta(hapd, sa);
 	if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
 		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
@@ -1054,7 +1073,7 @@
 		if (sta && (sta->flags & WLAN_STA_AUTH)) {
 			wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
 				   " for later use", MAC2STR(sta->addr));
-			ieee802_1x_save_eapol(sta, buf, len);
+			ieee802_1x_save_eapol(sta, buf, len, encrypted);
 		}
 
 		return;
@@ -1114,6 +1133,12 @@
 		return;
 	}
 
+	if (!ieee802_1x_check_encryption(sta, encrypted, hdr->type)) {
+		wpa_printf(MSG_DEBUG,
+			   "IEEE 802.1X: Discard unencrypted EAPOL message - encryption was expected");
+		return;
+	}
+
 	if (!sta->eapol_sm) {
 		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
 		if (!sta->eapol_sm)
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 70dc11a..1469351 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -19,7 +19,7 @@
 
 
 void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
-			size_t len);
+			size_t len, enum frame_encryption encrypted);
 void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
 void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta);
 
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index e37324f..52f25eb 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -199,19 +199,21 @@
 static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
 						    int ht, int vht, int he)
 {
-	u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
+	enum oper_chan_width oper_chwidth;
+
+	oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
 
 	if (!ht && !vht && !he)
 		return NR_CHAN_WIDTH_20;
 	if (!hapd->iconf->secondary_channel)
 		return NR_CHAN_WIDTH_20;
-	if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
+	if ((!vht && !he) || oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
 		return NR_CHAN_WIDTH_40;
-	if (oper_chwidth == CHANWIDTH_80MHZ)
+	if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
 		return NR_CHAN_WIDTH_80;
-	if (oper_chwidth == CHANWIDTH_160MHZ)
+	if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ)
 		return NR_CHAN_WIDTH_160;
-	if (oper_chwidth == CHANWIDTH_80P80MHZ)
+	if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
 		return NR_CHAN_WIDTH_80P80;
 	return NR_CHAN_WIDTH_20;
 }
diff --git a/src/ap/preauth_auth.c b/src/ap/preauth_auth.c
index 2ff1861..3284a10 100644
--- a/src/ap/preauth_auth.c
+++ b/src/ap/preauth_auth.c
@@ -90,7 +90,7 @@
 		return;
 	sta->preauth_iface = piface;
 	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
-			   len - sizeof(*ethhdr));
+			   len - sizeof(*ethhdr), FRAME_ENCRYPTION_UNKNOWN);
 }
 
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index af8f171..5c92e01 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -65,6 +65,7 @@
 struct pending_eapol_rx {
 	struct wpabuf *buf;
 	struct os_reltime rx_time;
+	enum frame_encryption encrypted;
 };
 
 enum pasn_fils_state {
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index ad91883..2954af6 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -735,16 +735,13 @@
 {
 #ifdef CONFIG_P2P
 	if (WPA_GET_BE32(sm->ip_addr)) {
-		u32 start;
 		wpa_printf(MSG_DEBUG,
 			   "P2P: Free assigned IP address %u.%u.%u.%u from "
-			   MACSTR,
+			   MACSTR " (bit %u)",
 			   sm->ip_addr[0], sm->ip_addr[1],
 			   sm->ip_addr[2], sm->ip_addr[3],
-			   MAC2STR(sm->addr));
-		start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start);
-		bitfield_clear(sm->wpa_auth->ip_pool,
-			       WPA_GET_BE32(sm->ip_addr) - start);
+			   MAC2STR(sm->addr), sm->ip_addr_bit);
+		bitfield_clear(sm->wpa_auth->ip_pool, sm->ip_addr_bit);
 	}
 #endif /* CONFIG_P2P */
 	if (sm->GUpdateStationKeys) {
@@ -2204,6 +2201,7 @@
 {
 	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
 	size_t pmkid_len = 0;
+	u16 key_info;
 
 	SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
 	sm->PTKRequest = false;
@@ -2307,8 +2305,10 @@
 	}
 	if (!pmkid)
 		pmkid_len = 0;
-	wpa_send_eapol(sm->wpa_auth, sm,
-		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+	key_info = WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE;
+	if (sm->pairwise_set && sm->wpa != WPA_VERSION_WPA)
+		key_info |= WPA_KEY_INFO_SECURE;
+	wpa_send_eapol(sm->wpa_auth, sm, key_info, NULL,
 		       sm->ANonce, pmkid, pmkid_len, 0, 0);
 }
 
@@ -2892,6 +2892,7 @@
 		wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
 		return -1;
 	}
+	sm->pairwise_set = true;
 	sm->tk_already_set = true;
 
 	wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
@@ -3178,12 +3179,14 @@
 		if (idx >= 0) {
 			u32 start = WPA_GET_BE32(wpa_auth->conf.ip_addr_start);
 			bitfield_set(wpa_auth->ip_pool, idx);
+			sm->ip_addr_bit = idx;
 			WPA_PUT_BE32(sm->ip_addr, start + idx);
 			wpa_printf(MSG_DEBUG,
 				   "P2P: Assigned IP address %u.%u.%u.%u to "
-				   MACSTR, sm->ip_addr[0], sm->ip_addr[1],
+				   MACSTR " (bit %u)",
+				   sm->ip_addr[0], sm->ip_addr[1],
 				   sm->ip_addr[2], sm->ip_addr[3],
-				   MAC2STR(sm->addr));
+				   MAC2STR(sm->addr), sm->ip_addr_bit);
 		}
 	}
 #endif /* CONFIG_P2P */
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 17cb5a2..5bd699c 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -152,6 +152,7 @@
 
 #ifdef CONFIG_P2P
 	u8 ip_addr[4];
+	unsigned int ip_addr_bit;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_FILS
diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c
index aef9a53..029f4de 100644
--- a/src/ap/x_snoop.c
+++ b/src/ap/x_snoop.c
@@ -31,6 +31,8 @@
 		return -1;
 	}
 
+	hapd->x_snoop_initialized = true;
+
 	if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
 					 1)) {
 		wpa_printf(MSG_DEBUG,
@@ -125,7 +127,10 @@
 
 void x_snoop_deinit(struct hostapd_data *hapd)
 {
+	if (!hapd->x_snoop_initialized)
+		return;
 	hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
 	hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
 	hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
+	hapd->x_snoop_initialized = false;
 }
diff --git a/src/common/defs.h b/src/common/defs.h
index f43bdb5..4e63053 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -429,9 +429,26 @@
 	CHAN_WIDTH_4320,
 	CHAN_WIDTH_6480,
 	CHAN_WIDTH_8640,
+	CHAN_WIDTH_320,
 	CHAN_WIDTH_UNKNOWN
 };
 
+/* VHT/EDMG/etc. channel widths
+ * Note: The first four values are used in hostapd.conf and as such, must
+ * maintain their defined values. Other values are used internally. */
+enum oper_chan_width {
+	CONF_OPER_CHWIDTH_USE_HT = 0,
+	CONF_OPER_CHWIDTH_80MHZ = 1,
+	CONF_OPER_CHWIDTH_160MHZ = 2,
+	CONF_OPER_CHWIDTH_80P80MHZ = 3,
+	CONF_OPER_CHWIDTH_2160MHZ,
+	CONF_OPER_CHWIDTH_4320MHZ,
+	CONF_OPER_CHWIDTH_6480MHZ,
+	CONF_OPER_CHWIDTH_8640MHZ,
+	CONF_OPER_CHWIDTH_40MHZ_6GHZ,
+	CONF_OPER_CHWIDTH_320MHZ,
+};
+
 enum key_flag {
 	KEY_FLAG_MODIFY			= BIT(0),
 	KEY_FLAG_DEFAULT		= BIT(1),
@@ -475,4 +492,10 @@
 	PTK0_REKEY_ALLOW_NEVER
 };
 
+enum frame_encryption {
+	FRAME_ENCRYPTION_UNKNOWN = -1,
+	FRAME_NOT_ENCRYPTED = 0,
+	FRAME_ENCRYPTED = 1
+};
+
 #endif /* DEFS_H */
diff --git a/src/common/dpp.c b/src/common/dpp.c
index cc26b80..fcc5241 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -13,6 +13,7 @@
 #include "utils/common.h"
 #include "utils/base64.h"
 #include "utils/json.h"
+#include "utils/ip_addr.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
 #include "common/gas.h"
@@ -162,6 +163,7 @@
 	os_free(info->uri);
 	os_free(info->info);
 	os_free(info->chan);
+	os_free(info->host);
 	os_free(info->pk);
 	crypto_ec_key_deinit(info->pubkey);
 	str_clear_free(info->configurator_params);
@@ -369,12 +371,70 @@
 }
 
 
+static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt)
+{
+	const char *end;
+	char *port;
+	struct hostapd_ip_addr addr;
+	char buf[100], *pos;
+
+	if (!txt)
+		return 0;
+
+	end = os_strchr(txt, ';');
+	if (!end)
+		end = txt + os_strlen(txt);
+	if (end - txt > (int) sizeof(buf) - 1)
+		return -1;
+	os_memcpy(buf, txt, end - txt);
+	buf[end - txt] = '\0';
+
+	bi->port = DPP_TCP_PORT;
+
+	pos = buf;
+	if (*pos == '[') {
+		pos = &buf[1];
+		port = os_strchr(pos, ']');
+		if (!port)
+			return -1;
+		*port++ = '\0';
+		if (*port == ':')
+			bi->port = atoi(port + 1);
+	}
+
+	if (hostapd_parse_ip_addr(pos, &addr) < 0) {
+		if (buf[0] != '[') {
+			port = os_strrchr(pos, ':');
+			if (port) {
+				*port++ = '\0';
+				bi->port = atoi(port);
+			}
+		}
+		if (hostapd_parse_ip_addr(pos, &addr) < 0) {
+			wpa_printf(MSG_INFO,
+				   "DPP: Invalid IP address in URI host entry: %s",
+				   pos);
+			return -1;
+		}
+	}
+	os_free(bi->host);
+	bi->host = os_memdup(&addr, sizeof(addr));
+	if (!bi->host)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u",
+		   hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port);
+
+	return 0;
+}
+
+
 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
 {
 	const char *pos = uri;
 	const char *end;
 	const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
-	const char *version = NULL, *supported_curves = NULL;
+	const char *version = NULL, *supported_curves = NULL, *host = NULL;
 	struct dpp_bootstrap_info *bi;
 
 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
@@ -409,6 +469,8 @@
 			version = pos + 2;
 		else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
 			supported_curves = pos + 2;
+		else if (pos[0] == 'H' && pos[1] == ':' && !host)
+			host = pos + 2;
 		else
 			wpa_hexdump_ascii(MSG_DEBUG,
 					  "DPP: Ignore unrecognized URI parameter",
@@ -431,6 +493,7 @@
 	    dpp_parse_uri_info(bi, info) < 0 ||
 	    dpp_parse_uri_version(bi, version) < 0 ||
 	    dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
+	    dpp_parse_uri_host(bi, host) < 0 ||
 	    dpp_parse_uri_pk(bi, pk) < 0) {
 		dpp_bootstrap_info_free(bi);
 		bi = NULL;
@@ -632,6 +695,7 @@
 	char macstr[ETH_ALEN * 2 + 10];
 	size_t len;
 	char supp_curves[10];
+	char host[100];
 
 	len = 4; /* "DPP:" */
 	if (bi->chan)
@@ -664,11 +728,29 @@
 		supp_curves[0] = '\0';
 	}
 
+	host[0] = '\0';
+	if (bi->host) {
+		char buf[100];
+		const char *addr;
+
+		addr = hostapd_ip_txt(bi->host, buf, sizeof(buf));
+		if (!addr)
+			return -1;
+		if (bi->port == DPP_TCP_PORT)
+			len += os_snprintf(host, sizeof(host), "H:%s;", addr);
+		else if (bi->host->af == AF_INET)
+			len += os_snprintf(host, sizeof(host), "H:%s:%u;",
+					   addr, bi->port);
+		else
+			len += os_snprintf(host, sizeof(host), "H:[%s]:%u;",
+					   addr, bi->port);
+	}
+
 	os_free(bi->uri);
 	bi->uri = os_malloc(len + 1);
 	if (!bi->uri)
 		return -1;
-	os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
+	os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%s%sK:%s;;",
 		    bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
 		    bi->chan ? ";" : "",
 		    macstr,
@@ -677,6 +759,7 @@
 		    DPP_VERSION == 3 ? "V:3;" :
 		    (DPP_VERSION == 2 ? "V:2;" : ""),
 		    supp_curves,
+		    host,
 		    bi->pk);
 	return 0;
 }
@@ -4233,7 +4316,7 @@
 int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
 {
 	char *mac = NULL, *info = NULL, *curve = NULL;
-	char *key = NULL, *supported_curves = NULL;
+	char *key = NULL, *supported_curves = NULL, *host = NULL;
 	u8 *privkey = NULL;
 	size_t privkey_len = 0;
 	int ret = -1;
@@ -4261,6 +4344,7 @@
 	curve = get_param(cmd, " curve=");
 	key = get_param(cmd, " key=");
 	supported_curves = get_param(cmd, " supported_curves=");
+	host = get_param(cmd, " host=");
 
 	if (key) {
 		privkey_len = os_strlen(key) / 2;
@@ -4275,6 +4359,7 @@
 	    dpp_parse_uri_mac(bi, mac) < 0 ||
 	    dpp_parse_uri_info(bi, info) < 0 ||
 	    dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
+	    dpp_parse_uri_host(bi, host) < 0 ||
 	    dpp_gen_uri(bi) < 0)
 		goto fail;
 
@@ -4288,6 +4373,7 @@
 	os_free(info);
 	str_clear_free(key);
 	os_free(supported_curves);
+	os_free(host);
 	bin_clear_free(privkey, privkey_len);
 	dpp_bootstrap_info_free(bi);
 	return ret;
@@ -4343,6 +4429,8 @@
 	struct dpp_bootstrap_info *bi;
 	char pkhash[2 * SHA256_MAC_LEN + 1];
 	char supp_curves[100];
+	char host[100];
+	int ret;
 
 	bi = dpp_bootstrap_get_id(dpp, id);
 	if (!bi)
@@ -4352,7 +4440,6 @@
 
 	supp_curves[0] = '\0';
 	if (bi->supported_curves) {
-		int ret;
 		size_t i;
 		char *pos = supp_curves;
 		char *end = &supp_curves[sizeof(supp_curves)];
@@ -4379,6 +4466,17 @@
 			supp_curves[0] = '\0';
 	}
 
+	host[0] = '\0';
+	if (bi->host) {
+		char buf[100];
+
+		ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
+				  hostapd_ip_txt(bi->host, buf, sizeof(buf)),
+				  bi->port);
+		if (os_snprintf_error(sizeof(host), ret))
+			return -1;
+	}
+
 	return os_snprintf(reply, reply_size, "type=%s\n"
 			   "mac_addr=" MACSTR "\n"
 			   "info=%s\n"
@@ -4386,7 +4484,7 @@
 			   "use_freq=%u\n"
 			   "curve=%s\n"
 			   "pkhash=%s\n"
-			   "version=%d\n%s",
+			   "version=%d\n%s%s",
 			   dpp_bootstrap_type_txt(bi->type),
 			   MAC2STR(bi->mac_addr),
 			   bi->info ? bi->info : "",
@@ -4395,7 +4493,8 @@
 			   bi->curve->name,
 			   pkhash,
 			   bi->version,
-			   supp_curves);
+			   supp_curves,
+			   host);
 }
 
 
diff --git a/src/common/dpp.h b/src/common/dpp.h
index fba4119..1241668 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -163,6 +163,8 @@
 	u8 mac_addr[ETH_ALEN];
 	char *chan;
 	char *info;
+	struct hostapd_ip_addr *host;
+	unsigned int port;
 	char *pk;
 	unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
 	unsigned int num_freq;
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 47f56c2..fb239f7 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -1035,10 +1035,9 @@
 int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
 {
 	struct crypto_ec *ec;
-	struct crypto_ec_point *L = NULL;
-	const struct crypto_ec_point *BI;
-	const struct crypto_bignum *bR, *pR, *q;
-	struct crypto_bignum *sum = NULL, *lx = NULL;
+	struct crypto_ec_point *L = NULL, *BI = NULL;
+	const struct crypto_bignum *q;
+	struct crypto_bignum *sum = NULL, *lx = NULL, *bR = NULL, *pR = NULL;
 	int ret = -1;
 
 	/* L = ((bR + pR) modulo q) * BI */
@@ -1068,7 +1067,10 @@
 fail:
 	crypto_bignum_deinit(lx, 1);
 	crypto_bignum_deinit(sum, 1);
+	crypto_bignum_deinit(bR, 1);
+	crypto_bignum_deinit(pR, 1);
 	crypto_ec_point_deinit(L, 1);
+	crypto_ec_point_deinit(BI, 1);
 	crypto_ec_deinit(ec);
 	return ret;
 }
@@ -1077,10 +1079,8 @@
 int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
 {
 	struct crypto_ec *ec;
-	struct crypto_ec_point *L = NULL, *sum = NULL;
-	const struct crypto_ec_point *BR, *PR;
-	const struct crypto_bignum *bI;
-	struct crypto_bignum *lx = NULL;
+	struct crypto_ec_point *L = NULL, *sum = NULL, *BR = NULL, *PR = NULL;
+	struct crypto_bignum *lx = NULL, *bI = NULL;
 	int ret = -1;
 
 	/* L = bI * (BR + PR) */
@@ -1108,8 +1108,11 @@
 	ret = 0;
 fail:
 	crypto_bignum_deinit(lx, 1);
+	crypto_bignum_deinit(bI, 1);
 	crypto_ec_point_deinit(sum, 1);
 	crypto_ec_point_deinit(L, 1);
+	crypto_ec_point_deinit(BR, 1);
+	crypto_ec_point_deinit(PR, 1);
 	crypto_ec_deinit(ec);
 	return ret;
 }
@@ -1441,9 +1444,8 @@
 	const u8 *addr[3];
 	size_t len[3];
 	unsigned int num_elem = 0;
-	struct crypto_ec_point *Qi = NULL;
+	struct crypto_ec_point *Qi = NULL, *Pi = NULL;
 	struct crypto_ec_key *Pi_key = NULL;
-	const struct crypto_ec_point *Pi = NULL;
 	struct crypto_bignum *hash_bn = NULL;
 	struct crypto_ec *ec = NULL;
 
@@ -1494,6 +1496,7 @@
 	crypto_ec_point_debug_print(ec, Qi, "DPP: Qi");
 out:
 	crypto_ec_key_deinit(Pi_key);
+	crypto_ec_point_deinit(Pi, 1);
 	crypto_bignum_deinit(hash_bn, 1);
 	if (ret_ec && Qi)
 		*ret_ec = ec;
@@ -1516,9 +1519,8 @@
 	const u8 *addr[3];
 	size_t len[3];
 	unsigned int num_elem = 0;
-	struct crypto_ec_point *Qr = NULL;
+	struct crypto_ec_point *Qr = NULL, *Pr = NULL;
 	struct crypto_ec_key *Pr_key = NULL;
-	const struct crypto_ec_point *Pr = NULL;
 	struct crypto_bignum *hash_bn = NULL;
 	struct crypto_ec *ec = NULL;
 
@@ -1570,6 +1572,7 @@
 
 out:
 	crypto_ec_key_deinit(Pr_key);
+	crypto_ec_point_deinit(Pr, 1);
 	crypto_bignum_deinit(hash_bn, 1);
 	if (ret_ec && Qr)
 		*ret_ec = ec;
@@ -1661,11 +1664,10 @@
 				     struct json_token *peer_net_access_key)
 {
 	struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
-	struct crypto_bignum *sum = NULL;
-	const struct crypto_bignum *q, *cR, *pR;
+	struct crypto_bignum *sum = NULL, *cR = NULL, *pR = NULL;
+	const struct crypto_bignum *q;
 	struct crypto_ec *ec = NULL;
-	struct crypto_ec_point *M = NULL;
-	const struct crypto_ec_point *CI;
+	struct crypto_ec_point *M = NULL, *CI = NULL;
 	u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
 	u8 prk[DPP_MAX_HASH_LEN];
 	const struct dpp_curve_params *curve;
@@ -1748,7 +1750,10 @@
 	forced_memzero(prk, sizeof(prk));
 	forced_memzero(Mx, sizeof(Mx));
 	crypto_ec_point_deinit(M, 1);
+	crypto_ec_point_deinit(CI, 1);
 	crypto_bignum_deinit(sum, 1);
+	crypto_bignum_deinit(cR, 1);
+	crypto_bignum_deinit(pR, 1);
 	crypto_ec_key_deinit(own_key);
 	crypto_ec_key_deinit(peer_key);
 	crypto_ec_deinit(ec);
@@ -1761,10 +1766,9 @@
 				     struct json_token *net_access_key)
 {
 	struct crypto_ec_key *pr = NULL, *peer_key = NULL;
-	const struct crypto_ec_point *CR, *PR;
-	const struct crypto_bignum *cI;
+	struct crypto_bignum *cI = NULL;
 	struct crypto_ec *ec = NULL;
-	struct crypto_ec_point *sum = NULL, *M = NULL;
+	struct crypto_ec_point *sum = NULL, *M = NULL, *CR = NULL, *PR = NULL;
 	u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
 	u8 prk[DPP_MAX_HASH_LEN];
 	int res = -1;
@@ -1835,10 +1839,13 @@
 fail:
 	forced_memzero(prk, sizeof(prk));
 	forced_memzero(Mx, sizeof(Mx));
+	crypto_bignum_deinit(cI, 1);
 	crypto_ec_key_deinit(pr);
 	crypto_ec_key_deinit(peer_key);
 	crypto_ec_point_deinit(sum, 1);
 	crypto_ec_point_deinit(M, 1);
+	crypto_ec_point_deinit(CR, 1);
+	crypto_ec_point_deinit(PR, 1);
 	crypto_ec_deinit(ec);
 	return res;
 }
@@ -2259,8 +2266,8 @@
 {
 	const struct crypto_bignum *q;
 	struct crypto_bignum *bn;
-	const struct crypto_ec_point *pp, *generator;
-	struct crypto_ec_point *e_prime_id, *a_nonce;
+	const struct crypto_ec_point *generator;
+	struct crypto_ec_point *e_prime_id, *a_nonce, *pp;
 	int ret = -1;
 
 	pp = crypto_ec_key_get_public_key(id->pp_key);
@@ -2297,6 +2304,7 @@
 fail:
 	crypto_ec_point_deinit(e_prime_id, 1);
 	crypto_ec_point_deinit(a_nonce, 1);
+	crypto_ec_point_deinit(pp, 1);
 	crypto_bignum_deinit(bn, 1);
 	return ret;
 }
@@ -2321,9 +2329,9 @@
 					  struct crypto_ec_key *e_prime_id)
 {
 	struct crypto_ec *ec;
-	const struct crypto_bignum *pp;
+	struct crypto_bignum *pp = NULL;
 	struct crypto_ec_point *e_id = NULL;
-	const struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
+	struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
 
 	if (!ppkey)
 		return NULL;
@@ -2348,6 +2356,9 @@
 	crypto_ec_point_debug_print(ec, e_id, "DPP: Decrypted E-id");
 
 fail:
+	crypto_ec_point_deinit(a_nonce_point, 1);
+	crypto_ec_point_deinit(e_prime_id_point, 1);
+	crypto_bignum_deinit(pp, 1);
 	crypto_ec_deinit(ec);
 	return e_id;
 }
@@ -2453,8 +2464,7 @@
 {
 	struct crypto_ec *ec;
 	struct crypto_ec_key *key = NULL;
-	const struct crypto_ec_point *pub_key;
-	struct crypto_ec_point *p = NULL;
+	struct crypto_ec_point *p = NULL, *pub_key = NULL;
 	u8 *x, *y;
 	int ret = -1;
 
@@ -2472,11 +2482,9 @@
 
 	/* Retrieve public key coordinates */
 	pub_key = crypto_ec_key_get_public_key(key);
-	if (!pub_key)
+	if (!pub_key || crypto_ec_point_to_bin(ec, pub_key, x, y))
 		goto fail;
 
-	crypto_ec_point_to_bin(ec, pub_key, x, y);
-
 	/* And corrupt them */
 	y[curve->prime_len - 1] ^= 0x01;
 	p = crypto_ec_point_from_bin(ec, x);
@@ -2489,6 +2497,7 @@
 	ret = 0;
 fail:
 	crypto_ec_point_deinit(p, 0);
+	crypto_ec_point_deinit(pub_key, 0);
 	crypto_ec_key_deinit(key);
 	crypto_ec_deinit(ec);
 	return ret;
diff --git a/src/common/dpp_pkex.c b/src/common/dpp_pkex.c
index 72084d9..cf4fb6b 100644
--- a/src/common/dpp_pkex.c
+++ b/src/common/dpp_pkex.c
@@ -30,8 +30,7 @@
 						   bool v2)
 {
 	struct crypto_ec *ec = NULL;
-	const struct crypto_ec_point *X;
-	struct crypto_ec_point *Qi = NULL, *M = NULL;
+	struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL;
 	u8 *Mx, *My;
 	struct wpabuf *msg = NULL;
 	size_t attr_len;
@@ -150,6 +149,7 @@
 	os_memcpy(pkex->Mx, Mx, curve->prime_len);
 
 out:
+	crypto_ec_point_deinit(X, 1);
 	crypto_ec_point_deinit(M, 1);
 	crypto_ec_point_deinit(Qi, 1);
 	crypto_ec_deinit(ec);
@@ -349,9 +349,8 @@
 	u16 ike_group;
 	struct dpp_pkex *pkex = NULL;
 	struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
-		*N = NULL;
+		*N = NULL, *Y = NULL;
 	struct crypto_ec *ec = NULL;
-	const struct crypto_ec_point *Y;
 	u8 *x_coord = NULL, *y_coord = NULL;
 	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
 	size_t Kx_len;
@@ -566,6 +565,7 @@
 	crypto_ec_point_deinit(M, 1);
 	crypto_ec_point_deinit(N, 1);
 	crypto_ec_point_deinit(X, 1);
+	crypto_ec_point_deinit(Y, 1);
 	crypto_ec_deinit(ec);
 	return pkex;
 fail:
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 732124f..6646301 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -384,13 +384,16 @@
 			    u8 edmg_channel, int ht_enabled,
 			    int vht_enabled, int he_enabled,
 			    bool eht_enabled, int sec_channel_offset,
-			    int oper_chwidth, int center_segment0,
+			    enum oper_chan_width oper_chwidth,
+			    int center_segment0,
 			    int center_segment1, u32 vht_caps,
 			    struct he_capabilities *he_cap,
 			    struct eht_capabilities *eht_cap)
 {
 	if (!he_cap || !he_cap->he_supported)
 		he_enabled = 0;
+	if (!eht_cap || !eht_cap->eht_supported)
+		eht_enabled = 0;
 	os_memset(data, 0, sizeof(*data));
 	data->mode = mode;
 	data->freq = freq;
@@ -402,11 +405,13 @@
 	data->sec_channel_offset = sec_channel_offset;
 	data->center_freq1 = freq + sec_channel_offset * 10;
 	data->center_freq2 = 0;
-	if (oper_chwidth == CHANWIDTH_80MHZ)
+	if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
 		data->bandwidth = 80;
-	else if (oper_chwidth == CHANWIDTH_160MHZ ||
-		 oper_chwidth == CHANWIDTH_80P80MHZ)
+	else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
+		 oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
 		data->bandwidth = 160;
+	else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
+		data->bandwidth = 320;
 	else if (sec_channel_offset)
 		data->bandwidth = 40;
 	else
@@ -482,9 +487,8 @@
 		return 0;
 	}
 
-#if 0 /* FIX: Figure out how to handle CHANWIDTH_320MHZ */
 	if (data->eht_enabled) switch (oper_chwidth) {
-	case CHANWIDTH_320MHZ:
+	case CONF_OPER_CHWIDTH_320MHZ:
 		if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
 		      EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
 			wpa_printf(MSG_ERROR,
@@ -492,16 +496,18 @@
 			return -1;
 		}
 		break;
+	default:
+		break;
 	}
-#endif
 
 	if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) {
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		if (sec_channel_offset == 0)
 			break;
 
 		if (mode == HOSTAPD_MODE_IEEE80211G) {
-			if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+			if (he_cap &&
+			    !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
 			      HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
 				wpa_printf(MSG_ERROR,
 					   "40 MHz channel width is not supported in 2.4 GHz");
@@ -510,9 +516,10 @@
 			break;
 		}
 		/* fall through */
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		if (mode == HOSTAPD_MODE_IEEE80211A) {
-			if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+			if (he_cap &&
+			    !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
 			      HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
 				wpa_printf(MSG_ERROR,
 					   "40/80 MHz channel width is not supported in 5/6 GHz");
@@ -520,35 +527,39 @@
 			}
 		}
 		break;
-	case CHANWIDTH_80P80MHZ:
-		if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+	case CONF_OPER_CHWIDTH_80P80MHZ:
+		if (he_cap &&
+		    !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
 		      HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
 			wpa_printf(MSG_ERROR,
 				   "80+80 MHz channel width is not supported in 5/6 GHz");
 			return -1;
 		}
 		break;
-	case CHANWIDTH_160MHZ:
-		if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+	case CONF_OPER_CHWIDTH_160MHZ:
+		if (he_cap &&
+		    !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
 		      HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
 			wpa_printf(MSG_ERROR,
 				   "160 MHz channel width is not supported in 5 / 6GHz");
 			return -1;
 		}
 		break;
-	} else if (data->vht_enabled) switch (oper_chwidth) {
-	case CHANWIDTH_USE_HT:
+	default:
 		break;
-	case CHANWIDTH_80P80MHZ:
+	} else if (data->vht_enabled) switch (oper_chwidth) {
+	case CONF_OPER_CHWIDTH_USE_HT:
+		break;
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
 			wpa_printf(MSG_ERROR,
 				   "80+80 channel width is not supported!");
 			return -1;
 		}
 		/* fall through */
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
 				  VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
 			wpa_printf(MSG_ERROR,
@@ -556,11 +567,13 @@
 			return -1;
 		}
 		break;
+	default:
+		break;
 	}
 
 	if (data->eht_enabled || data->he_enabled ||
 	    data->vht_enabled) switch (oper_chwidth) {
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		if (center_segment1 ||
 		    (center_segment0 != 0 &&
 		     5000 + center_segment0 * 5 != data->center_freq1 &&
@@ -571,7 +584,7 @@
 			return -1;
 		}
 		break;
-	case CHANWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		if (center_segment1 == center_segment0 + 4 ||
 		    center_segment1 == center_segment0 - 4) {
 			wpa_printf(MSG_ERROR,
@@ -580,19 +593,21 @@
 		}
 		data->center_freq2 = 5000 + center_segment1 * 5;
 		/* fall through */
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		data->bandwidth = 80;
 		if (!sec_channel_offset) {
 			wpa_printf(MSG_ERROR,
 				   "80/80+80 MHz: no second channel offset");
 			return -1;
 		}
-		if (oper_chwidth == CHANWIDTH_80MHZ && center_segment1) {
+		if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ &&
+		    center_segment1) {
 			wpa_printf(MSG_ERROR,
 				   "80 MHz: center segment 1 configured");
 			return -1;
 		}
-		if (oper_chwidth == CHANWIDTH_80P80MHZ && !center_segment1) {
+		if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ &&
+		    !center_segment1) {
 			wpa_printf(MSG_ERROR,
 				   "80+80 MHz: center segment 1 not configured");
 			return -1;
@@ -631,7 +646,7 @@
 			}
 		}
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		data->bandwidth = 160;
 		if (center_segment1) {
 			wpa_printf(MSG_ERROR,
@@ -662,6 +677,43 @@
 			return -1;
 		}
 		break;
+	case CONF_OPER_CHWIDTH_320MHZ:
+		data->bandwidth = 320;
+		if (!data->eht_enabled || !is_6ghz_freq(freq)) {
+			wpa_printf(MSG_ERROR,
+				   "320 MHz: EHT not enabled or not a 6 GHz channel");
+			return -1;
+		}
+		if (center_segment1) {
+			wpa_printf(MSG_ERROR,
+				   "320 MHz: center segment 1 should not be set");
+			return -1;
+		}
+		if (center_segment0 == channel + 30 ||
+		    center_segment0 == channel + 26 ||
+		    center_segment0 == channel + 22 ||
+		    center_segment0 == channel + 18 ||
+		    center_segment0 == channel + 14 ||
+		    center_segment0 == channel + 10 ||
+		    center_segment0 == channel + 6 ||
+		    center_segment0 == channel + 2 ||
+		    center_segment0 == channel - 2 ||
+		    center_segment0 == channel - 6 ||
+		    center_segment0 == channel - 10 ||
+		    center_segment0 == channel - 14 ||
+		    center_segment0 == channel - 18 ||
+		    center_segment0 == channel - 22 ||
+		    center_segment0 == channel - 26 ||
+		    center_segment0 == channel - 30)
+			data->center_freq1 = 5000 + center_segment0 * 5;
+		else {
+			wpa_printf(MSG_ERROR,
+				   "320 MHz: wrong center segment 0");
+			return -1;
+		}
+		break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -772,6 +824,7 @@
 	case 2:
 	case 4:
 	case 8:
+	case 16:
 		return num_chans * 20;
 	default:
 		return 20;
@@ -805,6 +858,9 @@
 	case 160:
 		bw_mask = HOSTAPD_CHAN_WIDTH_160;
 		break;
+	case 320:
+		bw_mask = HOSTAPD_CHAN_WIDTH_320;
+		break;
 	default:
 		bw_mask = 0;
 		break;
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index d87a2ca..d8ca168 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -41,7 +41,8 @@
 			    int ht_enabled,
 			    int vht_enabled, int he_enabled,
 			    bool eht_enabled, int sec_channel_offset,
-			    int oper_chwidth, int center_segment0,
+			    enum oper_chan_width oper_chwidth,
+			    int center_segment0,
 			    int center_segment1, u32 vht_caps,
 			    struct he_capabilities *he_caps,
 			    struct eht_capabilities *eht_cap);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 44335de..b8d3c54 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -886,7 +886,7 @@
 {
 	u8 op_class;
 
-	return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
+	return ieee80211_freq_to_channel_ext(freq, 0, CONF_OPER_CHWIDTH_USE_HT,
 					     &op_class, channel);
 }
 
@@ -896,15 +896,15 @@
  * for HT40, VHT, and HE. DFS channels are not covered.
  * @freq: Frequency (MHz) to convert
  * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
- * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*)
+ * @chanwidth: VHT/EDMG/etc. channel width
  * @op_class: Buffer for returning operating class
  * @channel: Buffer for returning channel number
  * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
  */
-enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
-						   int sec_channel,
-						   int chanwidth,
-						   u8 *op_class, u8 *channel)
+enum hostapd_hw_mode
+ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
+			      enum oper_chan_width chanwidth,
+			      u8 *op_class, u8 *channel)
 {
 	u8 vht_opclass;
 
@@ -952,13 +952,13 @@
 	}
 
 	switch (chanwidth) {
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		vht_opclass = 128;
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		vht_opclass = 129;
 		break;
-	case CHANWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		vht_opclass = 130;
 		break;
 	default:
@@ -1057,15 +1057,18 @@
 			return NUM_HOSTAPD_MODES;
 
 		switch (chanwidth) {
-		case CHANWIDTH_80MHZ:
+		case CONF_OPER_CHWIDTH_80MHZ:
 			*op_class = 133;
 			break;
-		case CHANWIDTH_160MHZ:
+		case CONF_OPER_CHWIDTH_160MHZ:
 			*op_class = 134;
 			break;
-		case CHANWIDTH_80P80MHZ:
+		case CONF_OPER_CHWIDTH_80P80MHZ:
 			*op_class = 135;
 			break;
+		case CONF_OPER_CHWIDTH_320MHZ:
+			*op_class = 137;
+			break;
 		default:
 			if (sec_channel)
 				*op_class = 132;
@@ -1090,12 +1093,12 @@
 			return NUM_HOSTAPD_MODES;
 
 		switch (chanwidth) {
-		case CHANWIDTH_USE_HT:
-		case CHANWIDTH_2160MHZ:
+		case CONF_OPER_CHWIDTH_USE_HT:
+		case CONF_OPER_CHWIDTH_2160MHZ:
 			*channel = (freq - 56160) / 2160;
 			*op_class = 180;
 			break;
-		case CHANWIDTH_4320MHZ:
+		case CONF_OPER_CHWIDTH_4320MHZ:
 			/* EDMG channels 9 - 13 */
 			if (freq > 56160 + 2160 * 5)
 				return NUM_HOSTAPD_MODES;
@@ -1103,7 +1106,7 @@
 			*channel = (freq - 56160) / 2160 + 8;
 			*op_class = 181;
 			break;
-		case CHANWIDTH_6480MHZ:
+		case CONF_OPER_CHWIDTH_6480MHZ:
 			/* EDMG channels 17 - 20 */
 			if (freq > 56160 + 2160 * 4)
 				return NUM_HOSTAPD_MODES;
@@ -1111,7 +1114,7 @@
 			*channel = (freq - 56160) / 2160 + 16;
 			*op_class = 182;
 			break;
-		case CHANWIDTH_8640MHZ:
+		case CONF_OPER_CHWIDTH_8640MHZ:
 			/* EDMG channels 25 - 27 */
 			if (freq > 56160 + 2160 * 3)
 				return NUM_HOSTAPD_MODES;
@@ -1140,28 +1143,31 @@
 	case CHAN_WIDTH_20_NOHT:
 	case CHAN_WIDTH_20:
 	case CHAN_WIDTH_40:
-		cw = CHANWIDTH_USE_HT;
+		cw = CONF_OPER_CHWIDTH_USE_HT;
 		break;
 	case CHAN_WIDTH_80:
-		cw = CHANWIDTH_80MHZ;
+		cw = CONF_OPER_CHWIDTH_80MHZ;
 		break;
 	case CHAN_WIDTH_80P80:
-		cw = CHANWIDTH_80P80MHZ;
+		cw = CONF_OPER_CHWIDTH_80P80MHZ;
 		break;
 	case CHAN_WIDTH_160:
-		cw = CHANWIDTH_160MHZ;
+		cw = CONF_OPER_CHWIDTH_160MHZ;
 		break;
 	case CHAN_WIDTH_2160:
-		cw = CHANWIDTH_2160MHZ;
+		cw = CONF_OPER_CHWIDTH_2160MHZ;
 		break;
 	case CHAN_WIDTH_4320:
-		cw = CHANWIDTH_4320MHZ;
+		cw = CONF_OPER_CHWIDTH_4320MHZ;
 		break;
 	case CHAN_WIDTH_6480:
-		cw = CHANWIDTH_6480MHZ;
+		cw = CONF_OPER_CHWIDTH_6480MHZ;
 		break;
 	case CHAN_WIDTH_8640:
-		cw = CHANWIDTH_8640MHZ;
+		cw = CONF_OPER_CHWIDTH_8640MHZ;
+		break;
+	case CHAN_WIDTH_320:
+		cw = CONF_OPER_CHWIDTH_320MHZ;
 		break;
 	}
 
@@ -1458,6 +1464,7 @@
 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+	case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
 		if (chan < 1 || chan > 233)
 			return -1;
 		return 5950 + chan * 5;
@@ -2272,6 +2279,9 @@
 	/* channels 15, 47, 79...*/
 	if ((idx & 0x1f) == 0xf)
 		return 3; /* 160 MHz */
+	/* channels 31, 63, 95, 127, 159, 191 */
+	if ((idx & 0x1f) == 0x1f && idx < 192)
+		return 4; /* 320 MHz */
 
 	return -1;
 }
@@ -2294,7 +2304,7 @@
 
 bool is_6ghz_op_class(u8 op_class)
 {
-	return op_class >= 131 && op_class <= 136;
+	return op_class >= 131 && op_class <= 137;
 }
 
 
@@ -2600,6 +2610,8 @@
 		return 160;
 	case 136: /* UHB channels, 20 MHz: 2 */
 		return 20;
+	case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
+		return 320;
 	case 180: /* 60 GHz band, channels 1..8 */
 		return 2160;
 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
@@ -2614,64 +2626,66 @@
 }
 
 
-int op_class_to_ch_width(u8 op_class)
+enum oper_chan_width op_class_to_ch_width(u8 op_class)
 {
 	switch (op_class) {
 	case 81:
 	case 82:
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 83: /* channels 1..9; 40 MHz */
 	case 84: /* channels 5..13; 40 MHz */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 115: /* channels 36,40,44,48; indoor only */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 116: /* channels 36,44; 40 MHz; indoor only */
 	case 117: /* channels 40,48; 40 MHz; indoor only */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 118: /* channels 52,56,60,64; dfs */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 119: /* channels 52,60; 40 MHz; dfs */
 	case 120: /* channels 56,64; 40 MHz; dfs */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 121: /* channels 100-140 */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 122: /* channels 100-142; 40 MHz */
 	case 123: /* channels 104-136; 40 MHz */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 124: /* channels 149,153,157,161 */
 	case 125: /* channels 149,153,157,161,165,169,171 */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 126: /* channels 149,157,165, 173; 40 MHz */
 	case 127: /* channels 153,161,169,177; 40 MHz */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
-		return CHANWIDTH_80MHZ;
+		return CONF_OPER_CHWIDTH_80MHZ;
 	case 129: /* center freqs 50, 114, 163; 160 MHz */
-		return CHANWIDTH_160MHZ;
+		return CONF_OPER_CHWIDTH_160MHZ;
 	case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
-		return CHANWIDTH_80P80MHZ;
+		return CONF_OPER_CHWIDTH_80P80MHZ;
 	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
-		return CHANWIDTH_80MHZ;
+		return CONF_OPER_CHWIDTH_80MHZ;
 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
-		return CHANWIDTH_160MHZ;
+		return CONF_OPER_CHWIDTH_160MHZ;
 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
-		return CHANWIDTH_80P80MHZ;
+		return CONF_OPER_CHWIDTH_80P80MHZ;
 	case 136: /* UHB channels, 20 MHz: 2 */
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
+	case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
+		return CONF_OPER_CHWIDTH_320MHZ;
 	case 180: /* 60 GHz band, channels 1..8 */
-		return CHANWIDTH_2160MHZ;
+		return CONF_OPER_CHWIDTH_2160MHZ;
 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
-		return CHANWIDTH_4320MHZ;
+		return CONF_OPER_CHWIDTH_4320MHZ;
 	case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
-		return CHANWIDTH_6480MHZ;
+		return CONF_OPER_CHWIDTH_6480MHZ;
 	case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
-		return CHANWIDTH_8640MHZ;
+		return CONF_OPER_CHWIDTH_8640MHZ;
 	}
-	return CHANWIDTH_USE_HT;
+	return CONF_OPER_CHWIDTH_USE_HT;
 }
 
 struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index e21f7be..13fd10d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -215,9 +215,10 @@
 			    const char *name, const char *val);
 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
 int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
-enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
-						   int sec_channel, int vht,
-						   u8 *op_class, u8 *channel);
+enum hostapd_hw_mode
+ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
+			      enum oper_chan_width chanwidth,
+			      u8 *op_class, u8 *channel);
 int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
 				  int sec_channel, u8 *op_class, u8 *channel);
 int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
@@ -279,7 +280,7 @@
 			       unsigned int capab);
 bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab);
 int op_class_to_bandwidth(u8 op_class);
-int op_class_to_ch_width(u8 op_class);
+enum oper_chan_width op_class_to_ch_width(u8 op_class);
 
 /* element iteration helpers */
 #define for_each_element(_elem, _data, _datalen)			\
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index c341a1d..ae035f5 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1340,16 +1340,11 @@
 
 #define VHT_RX_NSS_MAX_STREAMS			    8
 
-/* VHT/EDMG channel widths */
+/* VHT operation information - channel widths */
 #define CHANWIDTH_USE_HT	0
 #define CHANWIDTH_80MHZ		1
 #define CHANWIDTH_160MHZ	2
 #define CHANWIDTH_80P80MHZ	3
-#define CHANWIDTH_2160MHZ	4
-#define CHANWIDTH_4320MHZ	5
-#define CHANWIDTH_6480MHZ	6
-#define CHANWIDTH_8640MHZ	7
-#define CHANWIDTH_40MHZ_6GHZ	8
 
 #define HE_NSS_MAX_STREAMS			    8
 
diff --git a/src/common/ocv.c b/src/common/ocv.c
index c9dc14f..d77bc4b 100644
--- a/src/common/ocv.c
+++ b/src/common/ocv.c
@@ -159,11 +159,10 @@
 	}
 
 	/*
-	 * When using a 160 or 80+80 MHz channel to transmit, verify that we use
+	 * When using an 80+80 MHz channel to transmit, verify that we use
 	 * the same segments as the receiver by comparing frequency segment 1.
 	 */
-	if ((ci->chanwidth == CHAN_WIDTH_160 ||
-	     ci->chanwidth == CHAN_WIDTH_80P80) &&
+	if (ci->chanwidth == CHAN_WIDTH_80P80 &&
 	    tx_seg1_idx != oci.seg1_idx) {
 		os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
 			    "frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index d04c8d1..c9e4675 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -711,10 +711,10 @@
  *	This event contains Tx VDEV group information, other VDEVs
  *	interface index, and status information.
  *
- * @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY: Vendor command to
- *	configure the concurrent session policies when multiple STA interfaces
+ * @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY: Vendor command to
+ *	configure the concurrent session policies when multiple interfaces
  *	are (getting) active. The attributes used by this command are defined
- *	in enum qca_wlan_vendor_attr_concurrent_sta_policy.
+ *	in enum qca_wlan_vendor_attr_concurrent_policy.
  *
  * @QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS: Userspace can use this command
  *	to query usable channels for different interface types such as STA,
@@ -788,6 +788,37 @@
  *
  *	The attributes used with this command are defined in
  *	enum qca_wlan_vendor_attr_mcc_quota.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX: Vendor command to
+ *	get the WLAN radio combinations matrix supported by the device which
+ *	provides the device simultaneous radio configurations such as
+ *	standalone, dual band simultaneous, and single band simultaneous.
+ *
+ *	The attributes used with this command are defined in
+ *	enum qca_wlan_vendor_attr_radio_combination_matrix.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY: Event indicating to the user space
+ *	that the driver is ready for operations again after recovering from
+ *	internal failures. This occurs following a failure that was indicated by
+ *	@QCA_NL80211_VENDOR_SUBCMD_HANG.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PASN: Subcommand used to offload preassociation
+ *	security negotiation and key generation to user space.
+ *
+ *	When used as an event, the driver requests userspace to trigger the PASN
+ *	authentication or dropping of a PTKSA for the indicated peer devices.
+ *	When used as a command response, userspace indicates a consolidated
+ *	status report for all the peers that were requested for.
+ *
+ *	The attributes used with this command are defined in
+ *	enum qca_wlan_vendor_attr_pasn.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT: Subcommand used to set
+ *	secure ranging context such as TK and LTF keyseed for each peer
+ *	requested by the driver with a @QCA_NL80211_VENDOR_SUBCMD_PASN event.
+ *
+ *	The attributes used with this command are defined in
+ *	enum qca_wlan_vendor_attr_secure_ranging_ctx.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -974,7 +1005,7 @@
 	QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID = 194,
 	QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS = 195,
 	QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS = 196,
-	QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY = 197,
+	QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY = 197,
 	QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS = 198,
 	QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY = 199,
 	QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD = 200,
@@ -983,8 +1014,19 @@
 	QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS = 203,
 	QCA_NL80211_VENDOR_SUBCMD_RATEMASK_CONFIG = 204,
 	QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA = 205,
+	/* 206..212 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX = 213,
+	QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY = 214,
+	QCA_NL80211_VENDOR_SUBCMD_PASN = 215,
+	QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT = 216,
 };
 
+/* Compatibility defines for previously used subcmd names.
+ * These values should not be used in any new implementation.
+ */
+#define QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY \
+	QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY
+
 enum qca_wlan_vendor_attr {
 	QCA_WLAN_VENDOR_ATTR_INVALID = 0,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
@@ -1495,6 +1537,12 @@
  * Used with command to configure ACS operation for EHT mode.
  * Disable (flag attribute not present) - EHT disabled and
  * Enable (flag attribute present) - EHT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME: Optional (u32).
+ * Used with command to configure how older scan can be considered for ACS
+ * scoring. In case scan was performed on a partial set of channels configured
+ * with this command within last QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME
+ * (in ms), scan only the remaining channels.
  */
 enum qca_wlan_vendor_attr_acs_offload {
 	QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
@@ -1517,6 +1565,7 @@
 	QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17,
 	QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP = 18,
 	QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED = 19,
+	QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME = 20,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
@@ -1600,17 +1649,17 @@
  *	operation is specifically mentioned (against its respective
  *	documentation) to support either of these or both modes.
  * @QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI: Flag indicates
- * 	that the driver requires add/del virtual interface path using the
+ *	that the driver requires add/del virtual interface path using the
  *	generic nl80211 commands for NDP interface create/delete and to
  *	register/unregister the netdev instead of creating/deleting the NDP
  *	interface using the vendor commands
  *	QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE and
  *	QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE. With the latest kernel
- * 	(5.12 version onward), interface creation/deletion is not allowed using
- * 	vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK
- * 	during the register/unregister of netdev. Create and delete NDP
- * 	interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE
- * 	commands respectively if the driver advertises this capability set.
+ *	(5.12 version onward), interface creation/deletion is not allowed using
+ *	vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK
+ *	during the register/unregister of netdev. Create and delete NDP
+ *	interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE
+ *	commands respectively if the driver advertises this capability set.
  * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
  */
 enum qca_wlan_vendor_features {
@@ -1622,7 +1671,7 @@
 	QCA_WLAN_VENDOR_FEATURE_OCE_AP                  = 5,
 	QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON            = 6,
 	QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
-	QCA_WLAN_VENDOR_FEATURE_TWT 			= 8,
+	QCA_WLAN_VENDOR_FEATURE_TWT			= 8,
 	QCA_WLAN_VENDOR_FEATURE_11AX			= 9,
 	QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT		= 10,
 	QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG		= 11,
@@ -2643,6 +2692,13 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD = 81,
 
+	/*
+	 * 8-bit unsigned value. This attribute can be used to configure the
+	 * data path mode to be followed for audio traffic. Possible values
+	 * are defined in enum qca_wlan_audio_data_path.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_AUDIO_DATA_PATH = 82,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -4683,7 +4739,7 @@
 
 /**
  * enum qca_vendor_attr_roam_control - Attributes to carry roam configuration
- * 	The following attributes are used to set/get/clear the respective
+ *	The following attributes are used to set/get/clear the respective
  *	configurations to/from the driver.
  *	For the get, the attribute for the configuration to be queried shall
  *	carry any of its acceptable values to the driver. In return, the driver
@@ -4885,6 +4941,12 @@
  *	Optional parameter. Scan dwell time for 6G Non Preferred Scanning
  *	Channels. If this attribute is not configured, the driver shall proceed
  *	with default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_RX_LINKSPEED_THRESHOLD: u16 value in Mbps.
+ *	Optional parameter. RX link speed threshold to disable roaming.
+ *	If the current RX link speed is above the threshold, roaming is not
+ *	needed. If this attribute is not configured, or if it is set to 0, the
+ *	driver will not consider the RX link speed in the roaming decision.
  */
 enum qca_vendor_attr_roam_control {
 	QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
@@ -4910,6 +4972,7 @@
 	QCA_ATTR_ROAM_CONTROL_MAXIMUM_AWAY_TIME = 21,
 	QCA_ATTR_ROAM_CONTROL_SCAN_6G_PSC_DWELL_TIME = 22,
 	QCA_ATTR_ROAM_CONTROL_SCAN_6G_NON_PSC_DWELL_TIME = 23,
+	QCA_ATTR_ROAM_CONTROL_LINKSPEED_THRESHOLD = 24,
 
 	/* keep last */
 	QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
@@ -11573,24 +11636,58 @@
 };
 
 /**
- * enum qca_wlan_vendor_attr_concurrent_sta_policy - Defines attributes
- * used by QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY vendor command.
+ * enum qca_wlan_concurrent_ap_policy_config - Concurrent AP policies
  *
- * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG:
+ * @QCA_WLAN_CONCURRENT_AP_POLICY_UNSPECIFIED: No specific policy for this AP
+ * interface.
+ *
+ * @QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO: Select interface concurrencies
+ * to meet gaming audio latency requirements.
+ *
+ * @QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: Select interface
+ * concurrencies to meet lossless audio streaming requirements.
+ */
+enum qca_wlan_concurrent_ap_policy_config {
+	QCA_WLAN_CONCURRENT_AP_POLICY_UNSPECIFIED = 0,
+	QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO = 1,
+	QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_concurrent_policy - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG:
  * u8 attribute. Configures the concurrent STA policy configuration.
  * Possible values are defined in enum qca_wlan_concurrent_sta_policy_config.
+
+ * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG:
+ * u8 attribute. Configures the concurrent AP policy configuration.
+ * Possible values are defined in enum qca_wlan_concurrent_ap_policy_config.
  */
-enum qca_wlan_vendor_attr_concurrent_sta_policy {
-	QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_INVALID = 0,
-	QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG = 1,
+enum qca_wlan_vendor_attr_concurrent_policy {
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG = 1,
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG = 2,
 
 	/* keep last */
-	QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST,
-	QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_MAX =
-	QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST - 1,
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX =
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AFTER_LAST - 1,
 
 };
 
+/* Compatibility defines for previously used enum
+ * qca_wlan_vendor_attr_concurrent_policy names. These values should not be used
+ * in any new implementation.
+ */
+#define QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG \
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG
+#define QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_MAX \
+	QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX
+#define qca_wlan_vendor_attr_concurrent_sta_policy \
+	qca_wlan_vendor_attr_concurrent_policy
+
 /**
  * enum qca_sta_connect_fail_reason_codes - Defines values carried
  * by QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE vendor
@@ -11821,6 +11918,82 @@
 };
 
 /**
+ * enum qca_wlan_vendor_attr_supported_radio_cfg - Attributes for
+ * radio configurations present in each radio combination.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND: u32 attribute indicates
+ * the band info in the radio configuration. Uses the enum qca_set_band values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA: u8 attribute indicates
+ * the number of antennas info in the radio configuration.
+ */
+enum qca_wlan_vendor_attr_supported_radio_cfg {
+	QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND = 1,
+	QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_LAST,
+	QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_MAX =
+	QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_radio_combination - Attributes for
+ * radio combinations supported by the device.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS: Nested attribute
+ * provides the radio configurations present in the radio combination.
+ * Uses the enum qca_wlan_vendor_attr_supported_radio_cfg attributes.
+ * This attribute provides the values for radio combination matrix.
+ * For standalone config, the number of config values is one and the config
+ * carries the band and antenna information for standalone configuration. For
+ * Dual Band Simultaneous (DBS)/Single Band Simultaneous (SBS) mode
+ * configuration the number of config values is two and the config carries the
+ * band and antenna information for each simultaneous radio.
+ */
+enum qca_wlan_vendor_attr_radio_combination {
+	QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS = 1,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_LAST,
+	QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_MAX =
+	QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_radio_combination_matrix - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX
+ *
+ * @QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS: Nested attribute
+ * provides the radio combinations supported by the device.
+ * Uses the enum qca_wlan_vendor_attr_radio_combination attributes.
+ * For example, in the radio combination matrix for a device which has two
+ * radios, where one radio is capable of 2.4 GHz 2X2 only and another radio is
+ * capable of either 5 GHz or 6 GHz 2X2, the possible number of radio
+ * combinations is 5 and the radio combinations are
+ * {{{2.4 GHz 2X2}}, //Standalone 2.4 GHz
+ * {{5 GHz 2X2}}, //Standalone 5 GHz
+ * {{6 GHz 2X2}}, //Standalone 6 GHz
+ * {{2.4 GHz 2X2}, {5 GHz 2X2}}, //2.4 GHz + 5 GHz DBS
+ * {{2.4 GHz 2X2}, {6 GHz 2X2}}} //2.4 GHz + 6 GHz DBS
+ * The band and antenna info together as nested data provides one radio config.
+ * Standalone configuration has one config with band and antenna nested data.
+ * Dual Band Simultaneous (DBS)/Single Band Simultaneous (SBS) configuration
+ * have two nested band and antenna info data.
+ */
+enum qca_wlan_vendor_attr_radio_combination_matrix {
+	QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS = 1,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_LAST,
+	QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_MAX =
+	QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_LAST - 1,
+};
+
+/**
  * enum qca_wlan_vendor_attr_mdns_offload - Attributes used by
  * %QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD vendor command.
  *
@@ -12198,4 +12371,173 @@
 	QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_audio_data_path - Defines the data path to be used for audio
+ * traffic.
+ *
+ * @QCA_WLAN_AUDIO_DATA_PATH_VIA_HOST_PROCESSOR:
+ * Send audio traffic through the host processor.
+ * @QCA_WLAN_AUDIO_DATA_PATH_VIA_LOW_POWER_DSP:
+ * Send audio traffic using the low power DSP to/from the encoder.
+ */
+enum qca_wlan_audio_data_path {
+	QCA_WLAN_AUDIO_DATA_PATH_VIA_HOST_PROCESSOR = 0,
+	QCA_WLAN_AUDIO_DATA_PATH_VIA_LOW_POWER_DSP = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_pasn_action - Action to authenticate (and generate keys
+ *	for) or drop existing PASN security association for the listed the
+ *	peers. Used by QCA_WLAN_VENDOR_ATTR_PASN_ACTION and sent from the driver
+ *	to userspace.
+ *
+ * @QCA_WLAN_VENDOR_PASN_ACTION_AUTH: Initiate PASN handshake with the peer
+ *	devices indicated with %QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR.
+ * @QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT: Indication from
+ *	the driver to userspace to inform that the existing PASN keys of the
+ *	peer devices specified with %QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR are
+ *	not valid anymore.
+ */
+enum qca_wlan_vendor_pasn_action {
+	QCA_WLAN_VENDOR_PASN_ACTION_AUTH,
+	QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_pasn_peer: Defines the nested attributes used in
+ *	QCA_WLAN_VENDOR_ATTR_PASN_PEERS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR: This attribute is optional in the
+ *	event from the driver to userspace and represents the local MAC address
+ *	to be used for PASN handshake. When this attribute is present, userspace
+ *	shall use the source address specified in this attribute by the driver
+ *	for PASN handshake with peer device.
+ *	This attribute is required in a command response from userspace to the
+ *	driver and represents the MAC address that was used in PASN handshake
+ *	with the peer device.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR: Indicates the MAC address of the
+ *	peer device to which PASN handshake is requested in an event from the
+ *	driver to userspace when QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ *	QCA_WLAN_VENDOR_PASN_ACTION_AUTH.
+ *	Indicates the MAC address of the peer device for which the keys are to
+ *	be invalidated in an event from the driver to userspace when
+ *	QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ *	QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT.
+ *	Indicates the MAC address of the peer device for which the status is
+ *	being sent in a status report from userspace to the driver.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED: NLA_FLAG attribute used
+ *	in the event from the driver to userspace. When set, userspace is
+ *	required to derive LTF key seed from KDK and set it to the driver.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS: NLA_FLAG attribute. This
+ *	attribute is used in the command response from userspace to the driver.
+ *	If present, it indicates the successful PASN handshake with the peer. If
+ *	this flag is not present, it indicates that the PASN handshake with the
+ *	peer device failed.
+ */
+enum qca_wlan_vendor_attr_pasn_peer {
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR = 1,
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR = 2,
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED = 3,
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS = 4,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX =
+	QCA_WLAN_VENDOR_ATTR_PASN_PEER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_pasn: Defines the attributes used in the
+ *	QCA_NL80211_VENDOR_SUBCMD_PASN command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PASN_ACTION: u32 attribute, possible values are
+ *	defined in enum qca_wlan_vendor_pasn_action and used only in an event
+ *	from the driver to userspace.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEERS: Nested attribute, used to pass PASN peer
+ *	details for each peer and used in both an event and a command response.
+ *	The nested attributes used inside QCA_WLAN_VENDOR_ATTR_PASN_PEERS are
+ *	defined in enum qca_wlan_vendor_attr_pasn_peer.
+ */
+enum qca_wlan_vendor_attr_pasn {
+	QCA_WLAN_VENDOR_ATTR_PASN_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_PASN_ACTION = 1,
+	QCA_WLAN_VENDOR_ATTR_PASN_PEERS = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_PASN_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_PASN_MAX =
+	QCA_WLAN_VENDOR_ATTR_PASN_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_secure_ranging_ctx_action - Used to add or delete
+ *	the ranging security context derived from PASN for each peer. Used in
+ *	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION.
+ *
+ * @QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_ADD: Add the secure ranging
+ *	context for the peer.
+ * @QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_DELETE: Delete the secure ranging
+ *	context for the peer.
+ */
+enum qca_wlan_vendor_secure_ranging_ctx_action {
+	QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_ADD,
+	QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_DELETE,
+};
+
+/**
+ * enum qca_wlan_vendor_sha_type - SHA types. Used to configure the SHA type
+ *	used for deriving PASN keys to the driver. Used in
+ *	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE
+ * @QCA_WLAN_VENDOR_SHA_256: SHA-256
+ * @QCA_WLAN_VENDOR_SHA_384: SHA-384
+ */
+enum qca_wlan_vendor_sha_type {
+	QCA_WLAN_VENDOR_SHA_256,
+	QCA_WLAN_VENDOR_SHA_384,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_secure_ranging_ctx: Defines the attributes used
+ *	to set security context for the PASN peer from userspace to the driver.
+ *	Used with QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION: u32 attribute, possible
+ *	values are defined in enum qca_wlan_vendor_secure_ranging_ctx_action
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR: The local MAC address that
+ *	was used during the PASN handshake.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR: The MAC address of
+ *	the peer device for which secure ranging context is being configured.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE: u32 attribute, defines the
+ *	hash algorithm to be used, possible values are defined in enum
+ *	qca_wlan_vendor_sha_type.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK: Variable length attribute, holds
+ *	the temporal key generated from the PASN handshake. The length of this
+ *	attribute is dependent on the value of
+ *	%QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER: cipher suite to use with the
+ *	TK, u32, as defined in IEEE Std 802.11-2020, 9.4.2.24.2 (Cipher suites)
+ *	(e.g., 0x000FAC04).
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED: Variable length
+ *	attribute, holds the LTF keyseed derived from KDK of PASN handshake.
+ *	The length of this attribute is dependent on the value of
+ *	%QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE.
+
+ */
+enum qca_wlan_vendor_attr_secure_ranging_ctx {
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION = 1,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR = 2,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR = 3,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE = 4,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK = 5,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER = 6,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED = 7,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX =
+	QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 27336c9..587cd88 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -3025,120 +3025,116 @@
  */
 static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
 {
-	if (pos[1] == 0)
+	u8 len = pos[1];
+	size_t dlen = 2 + len;
+	u32 selector;
+	const u8 *p;
+	size_t left;
+
+	if (len == 0)
 		return 1;
 
-	if (pos[1] >= 6 &&
-	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
-	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
-	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+	if (len < RSN_SELECTOR_LEN)
+		return 2;
+
+	p = pos + 2;
+	selector = RSN_SELECTOR_GET(p);
+	p += RSN_SELECTOR_LEN;
+	left = len - RSN_SELECTOR_LEN;
+
+	if (left >= 2 && selector == WPA_OUI_TYPE && p[0] == 1 && p[1] == 0) {
 		ie->wpa_ie = pos;
-		ie->wpa_ie_len = pos[1] + 2;
+		ie->wpa_ie_len = dlen;
 		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
 			    ie->wpa_ie, ie->wpa_ie_len);
 		return 0;
 	}
 
-	if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+	if (selector == OSEN_IE_VENDOR_TYPE) {
 		ie->osen = pos;
-		ie->osen_len = pos[1] + 2;
+		ie->osen_len = dlen;
 		return 0;
 	}
 
-	if (pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
-		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
-			    pos, pos[1] + 2);
+	if (left >= PMKID_LEN && selector == RSN_KEY_DATA_PMKID) {
+		ie->pmkid = p;
+		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) {
-		ie->key_id = pos + 2 + RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key",
-			    pos, pos[1] + 2);
+	if (left >= 2 && selector == RSN_KEY_DATA_KEYID) {
+		ie->key_id = p;
+		wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key", pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
-		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
-				pos, pos[1] + 2);
+	if (left > 2 && selector == RSN_KEY_DATA_GROUPKEY) {
+		ie->gtk = p;
+		ie->gtk_len = left;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
-		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
-		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+	if (left > 2 && selector == RSN_KEY_DATA_MAC_ADDR) {
+		ie->mac_addr = p;
+		ie->mac_addr_len = left;
 		wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
-			    pos, pos[1] + 2);
+			    pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
-		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+	if (left > 2 && selector == RSN_KEY_DATA_IGTK) {
+		ie->igtk = p;
+		ie->igtk_len = left;
 		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
-				pos, pos[1] + 2);
+				pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) {
-		ie->bigtk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN;
+	if (left > 2 && selector == RSN_KEY_DATA_BIGTK) {
+		ie->bigtk = p;
+		ie->bigtk_len = left;
 		wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key",
-				pos, pos[1] + 2);
+				pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
-	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
-		ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+	if (left >= 1 && selector == WFA_KEY_DATA_IP_ADDR_REQ) {
+		ie->ip_addr_req = p;
 		wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
-			    ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+			    ie->ip_addr_req, left);
 		return 0;
 	}
 
-	if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
-	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
-		ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+	if (left >= 3 * 4 && selector == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+		ie->ip_addr_alloc = p;
 		wpa_hexdump(MSG_DEBUG,
 			    "WPA: IP Address Allocation in EAPOL-Key",
-			    ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+			    ie->ip_addr_alloc, left);
 		return 0;
 	}
 
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
-		ie->oci = pos + 2 + RSN_SELECTOR_LEN;
-		ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+	if (left > 2 && selector == RSN_KEY_DATA_OCI) {
+		ie->oci = p;
+		ie->oci_len = left;
 		wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
-			    pos, pos[1] + 2);
+			    pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
-	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) {
-		ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN;
-		ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN;
+	if (left >= 1 && selector == WFA_KEY_DATA_TRANSITION_DISABLE) {
+		ie->transition_disable = p;
+		ie->transition_disable_len = left;
 		wpa_hexdump(MSG_DEBUG,
 			    "WPA: Transition Disable KDE in EAPOL-Key",
-			    pos, pos[1] + 2);
+			    pos, dlen);
 		return 0;
 	}
 
-	if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_DPP) {
-		ie->dpp_kde = pos + 2 + RSN_SELECTOR_LEN;
-		ie->dpp_kde_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key",
-			    pos, pos[1] + 2);
+	if (left >= 2 && selector == WFA_KEY_DATA_DPP) {
+		ie->dpp_kde = p;
+		ie->dpp_kde_len = left;
+		wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key", pos, dlen);
 		return 0;
 	}
 
@@ -3157,15 +3153,17 @@
 {
 	const u8 *pos, *end;
 	int ret = 0;
+	size_t dlen = 0;
 
 	os_memset(ie, 0, sizeof(*ie));
-	for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+	for (pos = buf, end = pos + len; end - pos > 1; pos += dlen) {
 		if (pos[0] == 0xdd &&
 		    ((pos == buf + len - 1) || pos[1] == 0)) {
 			/* Ignore padding */
 			break;
 		}
-		if (2 + pos[1] > end - pos) {
+		dlen = 2 + pos[1];
+		if ((int) dlen > end - pos) {
 			wpa_printf(MSG_DEBUG,
 				   "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
 				   pos[0], pos[1], (int) (pos - buf));
@@ -3175,22 +3173,22 @@
 		}
 		if (*pos == WLAN_EID_RSN) {
 			ie->rsn_ie = pos;
-			ie->rsn_ie_len = pos[1] + 2;
+			ie->rsn_ie_len = dlen;
 			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
 				    ie->rsn_ie, ie->rsn_ie_len);
 		} else if (*pos == WLAN_EID_RSNX) {
 			ie->rsnxe = pos;
-			ie->rsnxe_len = pos[1] + 2;
+			ie->rsnxe_len = dlen;
 			wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
 				    ie->rsnxe, ie->rsnxe_len);
 		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
 			ie->mdie = pos;
-			ie->mdie_len = pos[1] + 2;
+			ie->mdie_len = dlen;
 			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
 				    ie->mdie, ie->mdie_len);
 		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
 			ie->ftie = pos;
-			ie->ftie_len = pos[1] + 2;
+			ie->ftie_len = dlen;
 			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
 				    ie->ftie, ie->ftie_len);
 		} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
@@ -3198,31 +3196,31 @@
 				ie->reassoc_deadline = pos;
 				wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
 					    "in EAPOL-Key",
-					    ie->reassoc_deadline, pos[1] + 2);
+					    ie->reassoc_deadline, dlen);
 			} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
 				ie->key_lifetime = pos;
 				wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
 					    "in EAPOL-Key",
-					    ie->key_lifetime, pos[1] + 2);
+					    ie->key_lifetime, dlen);
 			} else {
 				wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
 					    "EAPOL-Key Key Data IE",
-					    pos, 2 + pos[1]);
+					    pos, dlen);
 			}
 		} else if (*pos == WLAN_EID_LINK_ID) {
 			if (pos[1] >= 18) {
 				ie->lnkid = pos;
-				ie->lnkid_len = pos[1] + 2;
+				ie->lnkid_len = dlen;
 			}
 		} else if (*pos == WLAN_EID_EXT_CAPAB) {
 			ie->ext_capab = pos;
-			ie->ext_capab_len = pos[1] + 2;
+			ie->ext_capab_len = dlen;
 		} else if (*pos == WLAN_EID_SUPP_RATES) {
 			ie->supp_rates = pos;
-			ie->supp_rates_len = pos[1] + 2;
+			ie->supp_rates_len = dlen;
 		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
 			ie->ext_supp_rates = pos;
-			ie->ext_supp_rates_len = pos[1] + 2;
+			ie->ext_supp_rates_len = dlen;
 		} else if (*pos == WLAN_EID_HT_CAP &&
 			   pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
 			ie->ht_capabilities = pos + 2;
@@ -3276,7 +3274,7 @@
 		} else {
 			wpa_hexdump(MSG_DEBUG,
 				    "WPA: Unrecognized EAPOL-Key Key Data IE",
-				    pos, 2 + pos[1]);
+				    pos, dlen);
 		}
 	}
 
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index e4f3eb3..67210a0 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1086,16 +1086,20 @@
  * crypto_ec_key_get_public_key - Get EC public key as an EC point
  * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv()
  * Returns: Public key as an EC point or %NULL on failure
+ *
+ * The caller needs to free the returned value with crypto_ec_point_deinit().
  */
-const struct crypto_ec_point *
+struct crypto_ec_point *
 crypto_ec_key_get_public_key(struct crypto_ec_key *key);
 
 /**
  * crypto_ec_key_get_private_key - Get EC private key as a bignum
  * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv()
  * Returns: Private key as a bignum or %NULL on failure
+ *
+ * The caller needs to free the returned value with crypto_bignum_deinit().
  */
-const struct crypto_bignum *
+struct crypto_bignum *
 crypto_ec_key_get_private_key(struct crypto_ec_key *key);
 
 /**
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index c6e065f..08e9f26 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -25,6 +25,9 @@
 #include <openssl/provider.h>
 #include <openssl/core_names.h>
 #include <openssl/param_build.h>
+#include <openssl/rsa.h>
+#include <openssl/encoder.h>
+#include <openssl/decoder.h>
 #else /* OpenSSL version >= 3.0 */
 #include <openssl/cmac.h>
 #endif /* OpenSSL version >= 3.0 */
@@ -117,6 +120,19 @@
 {
 	return ASN1_STRING_data((ASN1_STRING *) x);
 }
+
+
+static const ASN1_TIME * X509_get0_notBefore(const X509 *x)
+{
+	return X509_get_notBefore(x);
+}
+
+
+static const ASN1_TIME * X509_get0_notAfter(const X509 *x)
+{
+	return X509_get_notAfter(x);
+}
+
 #endif /* OpenSSL version < 1.1.0 */
 
 
@@ -1347,21 +1363,22 @@
 
 	ctx = os_zalloc(sizeof(*ctx));
 	if (!ctx)
-		return NULL;
+		goto fail;
 	ctx->ctx = EVP_MAC_CTX_new(mac);
 	if (!ctx->ctx) {
-		EVP_MAC_free(mac);
 		os_free(ctx);
-		return NULL;
+		ctx = NULL;
+		goto fail;
 	}
 
 	if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) {
 		EVP_MAC_CTX_free(ctx->ctx);
 		bin_clear_free(ctx, sizeof(*ctx));
-		EVP_MAC_free(mac);
-		return NULL;
+		ctx = NULL;
+		goto fail;
 	}
 
+fail:
 	EVP_MAC_free(mac);
 	return ctx;
 #else /* OpenSSL version >= 3.0 */
@@ -2216,6 +2233,7 @@
 struct crypto_ec {
 	EC_GROUP *group;
 	int nid;
+	int iana_group;
 	BN_CTX *bnctx;
 	BIGNUM *prime;
 	BIGNUM *order;
@@ -2260,6 +2278,44 @@
 }
 
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static const char * crypto_ec_group_2_name(int group)
+{
+	/* Map from IANA registry for IKE D-H groups to OpenSSL group name */
+	switch (group) {
+	case 19:
+		return "prime256v1";
+	case 20:
+		return "secp384r1";
+	case 21:
+		return "secp521r1";
+	case 25:
+		return "prime192v1";
+	case 26:
+		return "secp224r1";
+#ifdef NID_brainpoolP224r1
+	case 27:
+		return "brainpoolP224r1";
+#endif /* NID_brainpoolP224r1 */
+#ifdef NID_brainpoolP256r1
+	case 28:
+		return "brainpoolP256r1";
+#endif /* NID_brainpoolP256r1 */
+#ifdef NID_brainpoolP384r1
+	case 29:
+		return "brainpoolP384r1";
+#endif /* NID_brainpoolP384r1 */
+#ifdef NID_brainpoolP512r1
+	case 30:
+		return "brainpoolP512r1";
+#endif /* NID_brainpoolP512r1 */
+	default:
+		return NULL;
+	}
+}
+#endif /* OpenSSL version >= 3.0 */
+
+
 struct crypto_ec * crypto_ec_init(int group)
 {
 	struct crypto_ec *e;
@@ -2274,6 +2330,7 @@
 		return NULL;
 
 	e->nid = nid;
+	e->iana_group = group;
 	e->bnctx = BN_CTX_new();
 	e->group = EC_GROUP_new_by_curve_name(nid);
 	e->prime = BN_new();
@@ -2936,6 +2993,27 @@
 
 struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY *pkey = NULL;
+	OSSL_DECODER_CTX *ctx;
+
+	ctx = OSSL_DECODER_CTX_new_for_pkey(
+		&pkey, "DER", NULL, "EC",
+		OSSL_KEYMGMT_SELECT_KEYPAIR |
+		OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS,
+		NULL, NULL);
+	if (!ctx ||
+	    OSSL_DECODER_from_data(ctx, &der, &der_len) != 1) {
+		wpa_printf(MSG_INFO, "OpenSSL: Decoding EC private key (DER) failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto fail;
+	}
+
+	return (struct crypto_ec_key *) pkey;
+fail:
+	crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
+	return NULL;
+#else /* OpenSSL version >= 3.0 */
 	EVP_PKEY *pkey = NULL;
 	EC_KEY *eckey;
 
@@ -2957,6 +3035,7 @@
 fail:
 	crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
 	return NULL;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
@@ -2972,8 +3051,13 @@
 	}
 
 	/* Ensure this is an EC key */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (!EVP_PKEY_is_a(pkey, "EC"))
+		goto fail;
+#else /* OpenSSL version >= 3.0 */
 	if (!EVP_PKEY_get0_EC_KEY(pkey))
 		goto fail;
+#endif /* OpenSSL version >= 3.0 */
 	return (struct crypto_ec_key *) pkey;
 fail:
 	crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
@@ -2984,6 +3068,47 @@
 struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *buf_x,
 					     const u8 *buf_y, size_t len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	const char *group_name;
+	OSSL_PARAM params[3];
+	u8 *pub;
+	EVP_PKEY_CTX *ctx;
+	EVP_PKEY *pkey = NULL;
+
+	group_name = crypto_ec_group_2_name(group);
+	if (!group_name)
+		return NULL;
+
+	pub = os_malloc(1 + len * 2);
+	if (!pub)
+		return NULL;
+	pub[0] = 0x04; /* uncompressed */
+	os_memcpy(pub + 1, buf_x, len);
+	os_memcpy(pub + 1 + len, buf_y, len);
+
+	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+						     (char *) group_name, 0);
+	params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
+						      pub, 1 + len * 2);
+	params[2] = OSSL_PARAM_construct_end();
+
+	ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+	if (!ctx) {
+		os_free(pub);
+		return NULL;
+	}
+	if (EVP_PKEY_fromdata_init(ctx) <= 0 ||
+	    EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
+		os_free(pub);
+		EVP_PKEY_CTX_free(ctx);
+		return NULL;
+	}
+
+	os_free(pub);
+	EVP_PKEY_CTX_free(ctx);
+
+	return (struct crypto_ec_key *) pkey;
+#else /* OpenSSL version >= 3.0 */
 	EC_KEY *eckey = NULL;
 	EVP_PKEY *pkey = NULL;
 	EC_GROUP *ec_group = NULL;
@@ -3058,6 +3183,7 @@
 	EVP_PKEY_free(pkey);
 	pkey = NULL;
 	goto out;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
@@ -3065,9 +3191,28 @@
 crypto_ec_key_set_pub_point(struct crypto_ec *ec,
 			    const struct crypto_ec_point *pub)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	int len = BN_num_bytes(ec->prime);
+	struct crypto_ec_key *key;
+	u8 *buf;
+
+	buf = os_malloc(2 * len);
+	if (!buf)
+		return NULL;
+	if (crypto_ec_point_to_bin(ec, pub, buf, buf + len) < 0) {
+		os_free(buf);
+		return NULL;
+	}
+
+	key = crypto_ec_key_set_pub(ec->iana_group, buf, buf + len, len);
+	os_free(buf);
+
+	return key;
+#else /* OpenSSL version >= 3.0 */
 	EC_KEY *eckey;
 	EVP_PKEY *pkey = NULL;
 
+	wpa_printf(MSG_INFO, "JKM:%s", __func__);
 	eckey = EC_KEY_new();
 	if (!eckey ||
 	    EC_KEY_set_group(eckey, ec->group) != 1 ||
@@ -3093,11 +3238,41 @@
 	EC_KEY_free(eckey);
 	pkey = NULL;
 	goto out;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 struct crypto_ec_key * crypto_ec_key_gen(int group)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY_CTX *ctx;
+	OSSL_PARAM params[2];
+	const char *group_name;
+	EVP_PKEY *pkey = NULL;
+
+	group_name = crypto_ec_group_2_name(group);
+	if (!group_name)
+		return NULL;
+
+	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+						     (char *) group_name, 0);
+	params[1] = OSSL_PARAM_construct_end();
+
+	ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+	if (!ctx ||
+	    EVP_PKEY_keygen_init(ctx) != 1 ||
+	    EVP_PKEY_CTX_set_params(ctx, params) != 1 ||
+	    EVP_PKEY_generate(ctx, &pkey) != 1) {
+		wpa_printf(MSG_INFO,
+			   "OpenSSL: failed to generate EC keypair: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		pkey = NULL;
+	}
+
+	EVP_PKEY_CTX_free(ctx);
+
+	return (struct crypto_ec_key *) pkey;
+#else /* OpenSSL version >= 3.0 */
 	EVP_PKEY_CTX *kctx = NULL;
 	EC_KEY *ec_params = NULL, *eckey;
 	EVP_PKEY *params = NULL, *key = NULL;
@@ -3145,6 +3320,7 @@
 	EVP_PKEY_free(params);
 	EVP_PKEY_CTX_free(kctx);
 	return (struct crypto_ec_key *) key;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
@@ -3183,6 +3359,54 @@
 
 struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
 {
+	EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	OSSL_ENCODER_CTX *ctx;
+	int selection;
+	unsigned char *pdata = NULL;
+	size_t pdata_len = 0;
+	EVP_PKEY *copy = NULL;
+	struct wpabuf *buf = NULL;
+
+	if (EVP_PKEY_get_ec_point_conv_form(pkey) !=
+	    POINT_CONVERSION_COMPRESSED) {
+		copy = EVP_PKEY_dup(pkey);
+		if (!copy)
+			return NULL;
+		if (EVP_PKEY_set_utf8_string_param(
+			    copy, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
+			    OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_COMPRESSED) !=
+		    1) {
+			wpa_printf(MSG_INFO,
+				   "OpenSSL: Failed to set compressed format");
+			EVP_PKEY_free(copy);
+			return NULL;
+		}
+		pkey = copy;
+	}
+
+	selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS |
+		OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+
+	ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER",
+					    "SubjectPublicKeyInfo",
+					    NULL);
+	if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) {
+		wpa_printf(MSG_INFO,
+			   "OpenSSL: Failed to encode SubjectPublicKeyInfo: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		pdata = NULL;
+	}
+	OSSL_ENCODER_CTX_free(ctx);
+	if (pdata) {
+		buf = wpabuf_alloc_copy(pdata, pdata_len);
+		OPENSSL_free(pdata);
+	}
+
+	EVP_PKEY_free(copy);
+
+	return buf;
+#else /* OpenSSL version >= 3.0 */
 #ifdef OPENSSL_IS_BORINGSSL
 	unsigned char *der = NULL;
 	int der_len;
@@ -3196,7 +3420,7 @@
 	int nid;
 
 	ctx = BN_CTX_new();
-	eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+	eckey = EVP_PKEY_get0_EC_KEY(pkey);
 	if (!ctx || !eckey)
 		goto fail;
 
@@ -3249,33 +3473,16 @@
 	int der_len;
 	struct wpabuf *buf;
 	EC_KEY *eckey;
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-	EVP_PKEY *tmp;
-#endif /* OpenSSL version >= 3.0 */
 
-	eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+	eckey = EVP_PKEY_get1_EC_KEY(pkey);
 	if (!eckey)
 		return NULL;
 
 	/* For now, all users expect COMPRESSED form */
 	EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
 
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-	tmp = EVP_PKEY_new();
-	if (!tmp)
-		return NULL;
-	if (EVP_PKEY_set1_EC_KEY(tmp, eckey) != 1) {
-		EVP_PKEY_free(tmp);
-		return NULL;
-	}
-	key = (struct crypto_ec_key *) tmp;
-#endif /* OpenSSL version >= 3.0 */
-
 	der_len = i2d_PUBKEY((EVP_PKEY *) key, &der);
 	EC_KEY_free(eckey);
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-	EVP_PKEY_free(tmp);
-#endif /* OpenSSL version >= 3.0 */
 	if (der_len <= 0) {
 		wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
 			   ERR_error_string(ERR_get_error(), NULL));
@@ -3286,19 +3493,58 @@
 	OPENSSL_free(der);
 	return buf;
 #endif /* OPENSSL_IS_BORINGSSL */
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key,
 						bool include_pub)
 {
+	EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	OSSL_ENCODER_CTX *ctx;
+	int selection;
+	unsigned char *pdata = NULL;
+	size_t pdata_len = 0;
+	struct wpabuf *buf;
+	EVP_PKEY *copy = NULL;
+
+	selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS |
+		OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+	if (include_pub) {
+		selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+	} else {
+		/* Not including OSSL_KEYMGMT_SELECT_PUBLIC_KEY does not seem
+		 * to really be sufficient, so clone the key and explicitly
+		 * mark it not to include the public key. */
+		copy = EVP_PKEY_dup(pkey);
+		if (!copy)
+			return NULL;
+		EVP_PKEY_set_int_param(copy, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC,
+				       0);
+		pkey = copy;
+	}
+
+	ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER",
+					    "type-specific", NULL);
+	if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) {
+		OSSL_ENCODER_CTX_free(ctx);
+		EVP_PKEY_free(copy);
+		return NULL;
+	}
+	OSSL_ENCODER_CTX_free(ctx);
+	buf = wpabuf_alloc_copy(pdata, pdata_len);
+	OPENSSL_free(pdata);
+	EVP_PKEY_free(copy);
+	return buf;
+#else /* OpenSSL version >= 3.0 */
 	EC_KEY *eckey;
 	unsigned char *der = NULL;
 	int der_len;
 	struct wpabuf *buf;
 	unsigned int key_flags;
 
-	eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+	eckey = EVP_PKEY_get1_EC_KEY(pkey);
 	if (!eckey)
 		return NULL;
 
@@ -3319,18 +3565,53 @@
 	OPENSSL_free(der);
 
 	return buf;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
 struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key,
 					       int prefix)
 {
+	EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	struct wpabuf *buf;
+	unsigned char *pos;
+	size_t pub_len = OSSL_PARAM_UNMODIFIED;
+
+	buf = NULL;
+	if (!EVP_PKEY_is_a(pkey, "EC") ||
+	    EVP_PKEY_get_octet_string_param(pkey,
+					    OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+					    NULL, 0, &pub_len) < 0 ||
+	    pub_len == OSSL_PARAM_UNMODIFIED ||
+	    !(buf = wpabuf_alloc(pub_len)) ||
+	    EVP_PKEY_get_octet_string_param(pkey,
+					    OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+					    wpabuf_put(buf, pub_len),
+					    pub_len, NULL) != 1 ||
+	    wpabuf_head_u8(buf)[0] != 0x04) {
+		wpa_printf(MSG_INFO,
+			   "OpenSSL: Failed to get encoded public key: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		wpabuf_free(buf);
+		return NULL;
+	}
+
+	if (!prefix) {
+		/* Remove 0x04 prefix if requested */
+		pos = wpabuf_mhead(buf);
+		os_memmove(pos, pos + 1, pub_len - 1);
+		buf->used--;
+	}
+
+	return buf;
+#else /* OpenSSL version >= 3.0 */
 	int len, res;
 	EC_KEY *eckey;
 	struct wpabuf *buf;
 	unsigned char *pos;
 
-	eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+	eckey = EVP_PKEY_get1_EC_KEY(pkey);
 	if (!eckey)
 		return NULL;
 	EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
@@ -3367,30 +3648,92 @@
 	}
 
 	return buf;
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
-const struct crypto_ec_point *
+struct crypto_ec_point *
 crypto_ec_key_get_public_key(struct crypto_ec_key *key)
 {
-	const EC_KEY *eckey;
+	EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	char group[64];
+	unsigned char pub[256];
+	size_t len;
+	EC_POINT *point = NULL;
+	EC_GROUP *grp;
+	int res = 0;
+	OSSL_PARAM params[2];
 
-	eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+	if (!EVP_PKEY_is_a(pkey, "EC") ||
+	    EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME,
+					   group, sizeof(group), &len) != 1 ||
+	    EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
+					    pub, sizeof(pub), &len) != 1)
+		return NULL;
+
+	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+						     group, 0);
+	params[1] = OSSL_PARAM_construct_end();
+	grp = EC_GROUP_new_from_params(params, NULL, NULL);
+	if (!grp)
+		goto fail;
+	point = EC_POINT_new(grp);
+	if (!point)
+		goto fail;
+	res = EC_POINT_oct2point(grp, point, pub, len, NULL);
+
+fail:
+	if (res != 1) {
+		EC_POINT_free(point);
+		point = NULL;
+	}
+
+	EC_GROUP_free(grp);
+
+	return (struct crypto_ec_point *) point;
+#else /* OpenSSL version >= 3.0 */
+	const EC_KEY *eckey;
+	const EC_POINT *point;
+	const EC_GROUP *group;
+
+	eckey = EVP_PKEY_get0_EC_KEY(pkey);
 	if (!eckey)
 		return NULL;
-	return (const struct crypto_ec_point *) EC_KEY_get0_public_key(eckey);
+	group = EC_KEY_get0_group(eckey);
+	if (!group)
+		return NULL;
+	point = EC_KEY_get0_public_key(eckey);
+	if (!point)
+		return NULL;
+	return (struct crypto_ec_point *) EC_POINT_dup(point, group);
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
-const struct crypto_bignum *
+struct crypto_bignum *
 crypto_ec_key_get_private_key(struct crypto_ec_key *key)
 {
-	const EC_KEY *eckey;
+	EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	BIGNUM *bn = NULL;
 
-	eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+	if (!EVP_PKEY_is_a(pkey, "EC") ||
+	    EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn) != 1)
+		return NULL;
+	return (struct crypto_bignum *) bn;
+#else /* OpenSSL version >= 3.0 */
+	const EC_KEY *eckey;
+	const BIGNUM *bn;
+
+	eckey = EVP_PKEY_get0_EC_KEY(pkey);
 	if (!eckey)
 		return NULL;
-	return (const struct crypto_bignum *) EC_KEY_get0_private_key(eckey);
+	bn = EC_KEY_get0_private_key(eckey);
+	if (!bn)
+		return NULL;
+	return (struct crypto_bignum *) BN_dup(bn);
+#endif /* OpenSSL version >= 3.0 */
 }
 
 
@@ -3943,6 +4286,8 @@
 {
 	EVP_PKEY *pkey;
 	X509 *x509;
+	const ASN1_TIME *not_before, *not_after;
+	int res_before, res_after;
 
 	pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
 	if (pkey)
@@ -3953,17 +4298,36 @@
 	if (!x509)
 		return NULL;
 
+	not_before = X509_get0_notBefore(x509);
+	not_after = X509_get0_notAfter(x509);
+	if (!not_before || !not_after)
+		goto fail;
+	res_before = X509_cmp_current_time(not_before);
+	res_after = X509_cmp_current_time(not_after);
+	if (!res_before || !res_after)
+		goto fail;
+	if (res_before > 0 || res_after < 0) {
+		wpa_printf(MSG_INFO,
+			   "OpenSSL: Certificate for RSA public key is not valid at this time (%d %d)",
+			   res_before, res_after);
+		goto fail;
+	}
+
 	pkey = X509_get_pubkey(x509);
 	X509_free(x509);
 
 	if (!pkey)
 		return NULL;
 	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+		wpa_printf(MSG_INFO, "OpenSSL: No RSA public key found");
 		EVP_PKEY_free(pkey);
 		return NULL;
 	}
 
 	return pkey;
+fail:
+	X509_free(x509);
+	return NULL;
 }
 
 
diff --git a/src/crypto/fips_prf_internal.c b/src/crypto/fips_prf_internal.c
index a4bf50a..f9347d0 100644
--- a/src/crypto/fips_prf_internal.c
+++ b/src/crypto/fips_prf_internal.c
@@ -17,10 +17,11 @@
 int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
 {
 	u8 xkey[64];
-	u32 t[5], _t[5];
+	u32 _t[5];
 	int i, j, m, k;
 	u8 *xpos = x;
 	u32 carry;
+	struct SHA1Context ctx;
 
 	if (seed_len < sizeof(xkey))
 		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
@@ -30,11 +31,7 @@
 	/* FIPS 186-2 + change notice 1 */
 
 	os_memcpy(xkey, seed, seed_len);
-	t[0] = 0x67452301;
-	t[1] = 0xEFCDAB89;
-	t[2] = 0x98BADCFE;
-	t[3] = 0x10325476;
-	t[4] = 0xC3D2E1F0;
+	SHA1Init(&ctx);
 
 	m = xlen / 40;
 	for (j = 0; j < m; j++) {
@@ -43,7 +40,7 @@
 			/* XVAL = (XKEY + XSEED_j) mod 2^b */
 
 			/* w_i = G(t, XVAL) */
-			os_memcpy(_t, t, 20);
+			os_memcpy(_t, ctx.state, 20);
 			SHA1Transform(_t, xkey);
 			_t[0] = host_to_be32(_t[0]);
 			_t[1] = host_to_be32(_t[1]);
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index 4697e04..484f772 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -7,6 +7,19 @@
  */
 
 #include "includes.h"
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+/* OpenSSL 3.0 has deprecated the low-level SHA1 functions and does not
+ * include an upper layer interface that could be used to use the
+ * SHA1_Transform() function. Use the internal SHA-1 implementation instead
+ * as a workaround. */
+#include "sha1-internal.c"
+#include "fips_prf_internal.c"
+
+#else /* OpenSSL version >= 3.0 */
+
 #include <openssl/sha.h>
 
 #include "common.h"
@@ -97,3 +110,5 @@
 
 	return 0;
 }
+
+#endif /* OpenSSL version >= 3.0 */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index a1b5166..dc8a1b4 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1584,6 +1584,15 @@
 	struct tls_connection *conn = arg;
 	const u8 *pos = buf;
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if ((SSL_version(ssl) == TLS1_VERSION ||
+	     SSL_version(ssl) == TLS1_1_VERSION) &&
+	    SSL_get_security_level(ssl) > 0) {
+		wpa_printf(MSG_DEBUG,
+			   "OpenSSL: Drop security level to 0 to allow TLS 1.0/1.1 use of MD5-SHA1 signature algorithm");
+		SSL_set_security_level(ssl, 0);
+	}
+#endif /* OpenSSL version >= 3.0 */
 	if (write_p == 2) {
 		wpa_printf(MSG_DEBUG,
 			   "OpenSSL: session ver=0x%x content_type=%d",
@@ -4180,8 +4189,10 @@
 			   "TLS: Failed to decode domain parameters from '%s': %s",
 			   dh_file, ERR_error_string(ERR_get_error(), NULL));
 		BIO_free(bio);
+		OSSL_DECODER_CTX_free(ctx);
 		return -1;
 	}
+	OSSL_DECODER_CTX_free(ctx);
 	BIO_free(bio);
 
 	if (!tmpkey) {
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 46cee44..12b46b6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -66,6 +66,7 @@
 	HOSTAPD_CHAN_WIDTH_40M  = BIT(3),
 	HOSTAPD_CHAN_WIDTH_80   = BIT(4),
 	HOSTAPD_CHAN_WIDTH_160  = BIT(5),
+	HOSTAPD_CHAN_WIDTH_320  = BIT(6),
 };
 
 /* Filter gratuitous ARP */
@@ -667,6 +668,16 @@
 	 */
 	unsigned int p2p_include_6ghz:1;
 
+	/**
+	 * non_coloc_6ghz - Force scanning of non-PSC 6 GHz channels
+	 *
+	 * If this is set, the driver should scan non-PSC channels from the
+	 * scan request even if neighbor reports from 2.4/5 GHz APs did not
+	 * report a co-located AP on these channels. The default is to scan
+	 * non-PSC channels only if a co-located AP was reported on the channel.
+	 */
+	unsigned int non_coloc_6ghz:1;
+
 	/*
 	 * NOTE: Whenever adding new parameters here, please make sure
 	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -2601,6 +2612,24 @@
 	NESTED_ATTR_UNSPECIFIED = 2,
 };
 
+/* Preferred channel list information */
+
+/* GO role */
+#define WEIGHTED_PCL_GO BIT(0)
+/* P2P Client role */
+#define WEIGHTED_PCL_CLI BIT(1)
+/* Must be considered for operating channel */
+#define WEIGHTED_PCL_MUST_CONSIDER BIT(2)
+/* Should be excluded in GO negotiation */
+#define WEIGHTED_PCL_EXCLUDE BIT(3)
+
+/* Preferred channel list with weight */
+struct weighted_pcl {
+	u32 freq; /* MHz */
+	u8 weight;
+	u32 flag; /* bitmap for WEIGHTED_PCL_* */
+};
+
 /**
  * struct wpa_driver_ops - Driver interface API definition
  *
@@ -4445,14 +4474,17 @@
 	 * @priv: Private driver interface data
 	 * @if_type: Interface type
 	 * @num: Number of channels
-	 * @freq_list: Preferred channel frequency list encoded in MHz values
+	 * @freq_list: Weighted preferred channel list
 	 * Returns 0 on success, -1 on failure
 	 *
 	 * This command can be used to query the preferred frequency list from
-	 * the driver specific to a particular interface type.
+	 * the driver specific to a particular interface type. The freq_list
+	 * array needs to have room for *num entries. *num will be updated to
+	 * indicate the number of entries fetched from the driver.
 	 */
 	int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type,
-				  unsigned int *num, unsigned int *freq_list);
+				  unsigned int *num,
+				  struct weighted_pcl *freq_list);
 
 	/**
 	 * set_prob_oper_freq - Indicate probable P2P operating channel
@@ -5856,6 +5888,7 @@
 		const u8 *src;
 		const u8 *data;
 		size_t data_len;
+		enum frame_encryption encrypted;
 	} eapol_rx;
 
 	/**
@@ -6194,6 +6227,20 @@
 	event.eapol_rx.src = src;
 	event.eapol_rx.data = data;
 	event.eapol_rx.data_len = data_len;
+	event.eapol_rx.encrypted = FRAME_ENCRYPTION_UNKNOWN;
+	wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
+}
+
+static inline void drv_event_eapol_rx2(void *ctx, const u8 *src, const u8 *data,
+				      size_t data_len,
+				       enum frame_encryption encrypted)
+{
+	union wpa_event_data event;
+	os_memset(&event, 0, sizeof(event));
+	event.eapol_rx.src = src;
+	event.eapol_rx.data = data;
+	event.eapol_rx.data_len = data_len;
+	event.eapol_rx.encrypted = encrypted;
 	wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
 }
 
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 8db7861..84e6a9e 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -117,6 +117,8 @@
 		return "80+80 MHz";
 	case CHAN_WIDTH_160:
 		return "160 MHz";
+	case CHAN_WIDTH_320:
+		return "320 MHz";
 	default:
 		return "unknown";
 	}
@@ -136,6 +138,8 @@
 	case CHAN_WIDTH_80P80:
 	case CHAN_WIDTH_160:
 		return 160;
+	case CHAN_WIDTH_320:
+		return 320;
 	default:
 		return 0;
 	}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5892fc1..bb3455d 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -219,6 +219,8 @@
 		return CHAN_WIDTH_80P80;
 	case NL80211_CHAN_WIDTH_160:
 		return CHAN_WIDTH_160;
+	case NL80211_CHAN_WIDTH_320:
+		return CHAN_WIDTH_320;
 	}
 	return CHAN_WIDTH_UNKNOWN;
 }
@@ -5055,6 +5057,9 @@
 		case 160:
 			cw = NL80211_CHAN_WIDTH_160;
 			break;
+		case 320:
+			cw = NL80211_CHAN_WIDTH_320;
+			break;
 		default:
 			return -EINVAL;
 		}
@@ -5107,8 +5112,9 @@
 				NL80211_CHAN_NO_HT))
 			return -ENOBUFS;
 	}
-	if (freq->radar_background)
-		nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND);
+	if (freq->radar_background &&
+	    nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND))
+		return -ENOBUFS;
 
 	return 0;
 }
@@ -11441,9 +11447,33 @@
 
 struct nl80211_pcl {
 	unsigned int num;
-	unsigned int *freq_list;
+	struct weighted_pcl *freq_list;
 };
 
+static void get_pcl_attr_values(struct weighted_pcl *wpcl, struct nlattr *nl[])
+{
+	if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ])
+		wpcl->freq = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]);
+	if (nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT])
+		wpcl->weight = nla_get_u8(nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]);
+	if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]) {
+		u32 flags = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]);
+
+		wpcl->flag = 0;
+		if (flags & BIT(0))
+			wpcl->flag |= WEIGHTED_PCL_GO;
+		if (flags & BIT(1))
+			wpcl->flag |= WEIGHTED_PCL_CLI;
+		if (flags & BIT(2))
+			wpcl->flag |= WEIGHTED_PCL_MUST_CONSIDER;
+		if (flags & BIT(3))
+			wpcl->flag |= WEIGHTED_PCL_EXCLUDE;
+	} else {
+		wpcl->flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
+	}
+}
+
+
 static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
 {
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -11452,6 +11482,7 @@
 	struct nlattr *nl_vend, *attr;
 	enum qca_iface_type iface_type;
 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+	struct nlattr *nl_pcl[QCA_WLAN_VENDOR_ATTR_PCL_MAX + 1];
 	unsigned int num, max_num;
 	u32 *freqs;
 
@@ -11477,26 +11508,69 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
 		   iface_type);
 
-	attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
-	if (!attr) {
+	attr = tb_vendor[
+		QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL];
+	if (attr) {
+		int rem;
+		struct nlattr *wpcl = attr;
+		unsigned int i;
+
+		num = 0;
+		nla_for_each_nested(attr, wpcl, rem) {
+			if (num == param->num)
+				break; /* not enough room for all entries */
+			if (nla_parse(nl_pcl, QCA_WLAN_VENDOR_ATTR_PCL_MAX,
+				      nla_data(attr), nla_len(attr), NULL)) {
+				wpa_printf(MSG_ERROR,
+					   "nl80211: Failed to parse PCL info");
+				param->num = 0;
+				return NL_SKIP;
+			}
+			get_pcl_attr_values(&param->freq_list[num], nl_pcl);
+			num++;
+		}
+		param->num = num;
+
+		/* Sort frequencies based on their weight */
+		for (i = 0; i < num; i++) {
+			unsigned int j;
+
+			for (j = i + 1; j < num; j++) {
+				if (param->freq_list[i].weight <
+				    param->freq_list[j].weight) {
+					struct weighted_pcl tmp;
+
+					tmp = param->freq_list[i];
+					param->freq_list[i] =
+						param->freq_list[j];
+					param->freq_list[j] = tmp;
+				}
+			}
+		}
+	} else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Driver does not provide weighted PCL; use the non-weighted variant");
+		attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
+		/*
+		 * param->num has the maximum number of entries for which there
+		 * is room in the freq_list provided by the caller.
+		 */
+		freqs = nla_data(attr);
+		max_num = nla_len(attr) / sizeof(u32);
+		if (max_num > param->num)
+			max_num = param->num;
+		for (num = 0; num < max_num; num++) {
+			param->freq_list[num].freq = freqs[num];
+			param->freq_list[num].flag =
+				WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
+		}
+		param->num = num;
+	} else {
 		wpa_printf(MSG_ERROR,
 			   "nl80211: preferred_freq_list couldn't be found");
 		param->num = 0;
 		return NL_SKIP;
 	}
-
-	/*
-	 * param->num has the maximum number of entries for which there
-	 * is room in the freq_list provided by the caller.
-	 */
-	freqs = nla_data(attr);
-	max_num = nla_len(attr) / sizeof(u32);
-	if (max_num > param->num)
-		max_num = param->num;
-	for (num = 0; num < max_num; num++)
-		param->freq_list[num] = freqs[num];
-	param->num = num;
-
 	return NL_SKIP;
 }
 
@@ -11504,7 +11578,7 @@
 static int nl80211_get_pref_freq_list(void *priv,
 				      enum wpa_driver_if_type if_type,
 				      unsigned int *num,
-				      unsigned int *freq_list)
+				      struct weighted_pcl *freq_list)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -11561,7 +11635,8 @@
 	}
 	nla_nest_end(msg, params);
 
-	os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
+	if (freq_list)
+		os_memset(freq_list, 0, *num * sizeof(struct weighted_pcl));
 	ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param,
 				 NULL, NULL);
 	if (ret) {
@@ -11573,8 +11648,10 @@
 	*num = param.num;
 
 	for (i = 0; i < *num; i++) {
-		wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
-			   i, freq_list[i]);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: preferred_channel_list[%d]=%d[%d]:0x%x",
+			   i, freq_list[i].freq, freq_list[i].weight,
+			   freq_list[i].flag);
 	}
 
 	return 0;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 5c103a4..01c7ab4 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -673,6 +673,9 @@
 	case CHAN_WIDTH_80P80:
 		freq1 = cf1 - 30;
 		break;
+	case CHAN_WIDTH_320:
+		freq1 = cf1 - 150;
+		break;
 	case CHAN_WIDTH_UNKNOWN:
 	case CHAN_WIDTH_2160:
 	case CHAN_WIDTH_4320:
@@ -2789,6 +2792,9 @@
 		case NL80211_CHAN_WIDTH_160:
 			ed.sta_opmode.chan_width = CHAN_WIDTH_160;
 			break;
+		case NL80211_CHAN_WIDTH_320:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_320;
+			break;
 		default:
 			ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
 			break;
@@ -2808,6 +2814,7 @@
 {
 	u8 *src_addr;
 	u16 ethertype;
+	enum frame_encryption encrypted;
 
 	if (!tb[NL80211_ATTR_MAC] ||
 	    !tb[NL80211_ATTR_FRAME] ||
@@ -2816,6 +2823,8 @@
 
 	src_addr = nla_data(tb[NL80211_ATTR_MAC]);
 	ethertype = nla_get_u16(tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+	encrypted = nla_get_flag(tb[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) ?
+		FRAME_NOT_ENCRYPTED : FRAME_ENCRYPTED;
 
 	switch (ethertype) {
 	case ETH_P_RSN_PREAUTH:
@@ -2824,9 +2833,10 @@
 			   MAC2STR(src_addr));
 		break;
 	case ETH_P_PAE:
-		drv_event_eapol_rx(drv->ctx, src_addr,
-				   nla_data(tb[NL80211_ATTR_FRAME]),
-				   nla_len(tb[NL80211_ATTR_FRAME]));
+		drv_event_eapol_rx2(drv->ctx, src_addr,
+				    nla_data(tb[NL80211_ATTR_FRAME]),
+				    nla_len(tb[NL80211_ATTR_FRAME]),
+				    encrypted);
 		break;
 	default:
 		wpa_printf(MSG_INFO,
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index b82e5af..c31ed6e 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -203,6 +203,21 @@
 				goto fail;
 		}
 		nla_nest_end(msg, ssids);
+
+		/*
+		 * If allowed, scan for 6 GHz APs that are reported by other
+		 * APs. Note that if the flag is not set and 6 GHz channels are
+		 * to be scanned, it is highly likely that non-PSC channels
+		 * would be scanned passively (due to the Probe Request frame
+		 * transmission restrictions mandated in IEEE Std 802.11ax-2021,
+		 * 26.17.2.3 (Scanning in the 6 GHz band). Passive scanning of
+		 * all non-PSC channels would take a significant amount of time.
+		 */
+		if (!params->non_coloc_6ghz) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Scan co-located APs on 6 GHz");
+			scan_flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
+		}
 	} else {
 		wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
 	}
diff --git a/src/eap_common/eap_sake_common.c b/src/eap_common/eap_sake_common.c
index 8ee9e32..a4256e2 100644
--- a/src/eap_common/eap_sake_common.c
+++ b/src/eap_common/eap_sake_common.c
@@ -164,26 +164,33 @@
 
 	os_memset(attr, 0, sizeof(*attr));
 	while (pos < end) {
+		u8 attr_id, attr_len;
+
 		if (end - pos < 2) {
 			wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
 			return -1;
 		}
 
-		if (pos[1] < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
-				   "length (%d)", pos[1]);
+		attr_id = *pos++;
+		attr_len = *pos++;
+		/* Attribute length value includes the Type and Length fields */
+		if (attr_len < 2) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-SAKE: Invalid attribute length (%d)",
+				   attr_len);
 			return -1;
 		}
+		attr_len -= 2;
 
-		if (pos + pos[1] > end) {
+		if (attr_len > end - pos) {
 			wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
 			return -1;
 		}
 
-		if (eap_sake_parse_add_attr(attr, pos[0], pos[1] - 2, pos + 2))
+		if (eap_sake_parse_add_attr(attr, attr_id, attr_len, pos))
 			return -1;
 
-		pos += pos[1];
+		pos += attr_len;
 	}
 
 	return 0;
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 276dca3..8ceb1df 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1707,7 +1707,7 @@
 		identity_len = config->machine_identity_len;
 		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
 				  identity, identity_len);
-	} else if (config->imsi_privacy_key && config->identity &&
+	} else if (config->imsi_privacy_cert && config->identity &&
 		   config->identity_len > 0) {
 		const u8 *pos = config->identity;
 		const u8 *end = config->identity + config->identity_len;
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index b7f86c3..8dac3cb 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -103,20 +103,20 @@
 
 	data->eap_method = EAP_TYPE_AKA;
 
-	if (config && config->imsi_privacy_key) {
+	if (config && config->imsi_privacy_cert) {
 #ifdef CRYPTO_RSA_OAEP_SHA256
 		data->imsi_privacy_key = crypto_rsa_key_read(
-			config->imsi_privacy_key, false);
+			config->imsi_privacy_cert, false);
 		if (!data->imsi_privacy_key) {
 			wpa_printf(MSG_ERROR,
-				   "EAP-AKA: Failed to read/parse IMSI privacy key %s",
-				   config->imsi_privacy_key);
+				   "EAP-AKA: Failed to read/parse IMSI privacy certificate %s",
+				   config->imsi_privacy_cert);
 			os_free(data);
 			return NULL;
 		}
 #else /* CRYPTO_RSA_OAEP_SHA256 */
 		wpa_printf(MSG_ERROR,
-			   "EAP-AKA: No support for imsi_privacy_key in the build");
+			   "EAP-AKA: No support for imsi_privacy_cert in the build");
 		os_free(data);
 		return NULL;
 #endif /* CRYPTO_RSA_OAEP_SHA256 */
@@ -656,11 +656,12 @@
 #ifdef CRYPTO_RSA_OAEP_SHA256
 static struct wpabuf *
 eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
-			 const u8 *identity, size_t identity_len)
+			 const u8 *identity, size_t identity_len,
+			 const char *attr)
 {
 	struct wpabuf *imsi_buf, *enc;
 	char *b64;
-	size_t b64_len;
+	size_t b64_len, len;
 
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity",
 			  identity, identity_len);
@@ -678,7 +679,10 @@
 	if (!b64)
 		return NULL;
 
-	enc = wpabuf_alloc(1 + b64_len);
+	len = 1 + b64_len;
+	if (attr)
+		len += 1 + os_strlen(attr);
+	enc = wpabuf_alloc(len);
 	if (!enc) {
 		os_free(b64);
 		return NULL;
@@ -686,6 +690,10 @@
 	wpabuf_put_u8(enc, '\0');
 	wpabuf_put_data(enc, b64, b64_len);
 	os_free(b64);
+	if (attr) {
+		wpabuf_put_u8(enc, ',');
+		wpabuf_put_str(enc, attr);
+	}
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity",
 			  wpabuf_head(enc), wpabuf_len(enc));
 
@@ -729,9 +737,15 @@
 		}
 #ifdef CRYPTO_RSA_OAEP_SHA256
 		if (identity && data->imsi_privacy_key) {
+			struct eap_peer_config *config;
+			const char *attr = NULL;
+
+			config = eap_get_config(sm);
+			if (config)
+				attr = config->imsi_privacy_attr;
 			enc_identity = eap_aka_encrypt_identity(
 				data->imsi_privacy_key,
-				identity, identity_len);
+				identity, identity_len, attr);
 			if (!enc_identity) {
 				wpa_printf(MSG_INFO,
 					   "EAP-AKA: Failed to encrypt permanent identity");
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index eaf514b..26744ab 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -318,14 +318,24 @@
 	size_t imsi_identity_len;
 
 	/**
-	 * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+	 * imsi_privacy_cert - IMSI privacy certificate
 	 *
 	 * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
-	 * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
-	 * include a 2048-bit RSA public key and this is from the operator who
-	 * authenticates the SIM/USIM.
+	 * identity (IMSI) to improve privacy. The referenced PEM-encoded
+	 * X.509v3 certificate needs to include a 2048-bit RSA public key and
+	 * this is from the operator who authenticates the SIM/USIM.
 	 */
-	char *imsi_privacy_key;
+	char *imsi_privacy_cert;
+
+	/**
+	 * imsi_privacy_attr - IMSI privacy attribute
+	 *
+	 * This field is used to help the EAP-SIM/AKA/AKA' server to identify
+	 * the used certificate (and as such, the matching private key). This
+	 * is set to an attribute in name=value format if the operator needs
+	 * this information.
+	 */
+	char *imsi_privacy_attr;
 
 	/**
 	 * machine_identity - EAP Identity for machine credential
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 9f66db2..a555680 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -101,20 +101,20 @@
 		return NULL;
 	}
 
-	if (config && config->imsi_privacy_key) {
+	if (config && config->imsi_privacy_cert) {
 #ifdef CRYPTO_RSA_OAEP_SHA256
 		data->imsi_privacy_key = crypto_rsa_key_read(
-			config->imsi_privacy_key, false);
+			config->imsi_privacy_cert, false);
 		if (!data->imsi_privacy_key) {
 			wpa_printf(MSG_ERROR,
-				   "EAP-SIM: Failed to read/parse IMSI privacy key %s",
-				   config->imsi_privacy_key);
+				   "EAP-SIM: Failed to read/parse IMSI privacy certificate %s",
+				   config->imsi_privacy_cert);
 			os_free(data);
 			return NULL;
 		}
 #else /* CRYPTO_RSA_OAEP_SHA256 */
 		wpa_printf(MSG_ERROR,
-			   "EAP-SIM: No support for imsi_privacy_key in the build");
+			   "EAP-SIM: No support for imsi_privacy_cert in the build");
 		os_free(data);
 		return NULL;
 #endif /* CRYPTO_RSA_OAEP_SHA256 */
@@ -133,6 +133,9 @@
 					   "sim_min_num_chal configuration "
 					   "(%lu, expected 2 or 3)",
 					   (unsigned long) data->min_num_chal);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+				crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
 				os_free(data);
 				return NULL;
 			}
@@ -521,11 +524,12 @@
 #ifdef CRYPTO_RSA_OAEP_SHA256
 static struct wpabuf *
 eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
-			 const u8 *identity, size_t identity_len)
+			 const u8 *identity, size_t identity_len,
+			 const char *attr)
 {
 	struct wpabuf *imsi_buf, *enc;
 	char *b64;
-	size_t b64_len;
+	size_t b64_len, len;
 
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity",
 			  identity, identity_len);
@@ -543,7 +547,10 @@
 	if (!b64)
 		return NULL;
 
-	enc = wpabuf_alloc(1 + b64_len);
+	len = 1 + b64_len;
+	if (attr)
+		len += 1 + os_strlen(attr);
+	enc = wpabuf_alloc(len);
 	if (!enc) {
 		os_free(b64);
 		return NULL;
@@ -551,6 +558,10 @@
 	wpabuf_put_u8(enc, '\0');
 	wpabuf_put_data(enc, b64, b64_len);
 	os_free(b64);
+	if (attr) {
+		wpabuf_put_u8(enc, ',');
+		wpabuf_put_str(enc, attr);
+	}
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity",
 			  wpabuf_head(enc), wpabuf_len(enc));
 
@@ -594,9 +605,15 @@
 		}
 #ifdef CRYPTO_RSA_OAEP_SHA256
 		if (identity && data->imsi_privacy_key) {
+			struct eap_peer_config *config;
+			const char *attr = NULL;
+
+			config = eap_get_config(sm);
+			if (config)
+				attr = config->imsi_privacy_attr;
 			enc_identity = eap_sim_encrypt_identity(
 				data->imsi_privacy_key,
-				identity, identity_len);
+				identity, identity_len, attr);
 			if (!enc_identity) {
 				wpa_printf(MSG_INFO,
 					   "EAP-SIM: Failed to encrypt permanent identity");
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 4e66369..6173960 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1281,11 +1281,12 @@
  * @src: Source MAC address of the EAPOL packet
  * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
  * @len: Length of the EAPOL frame
+ * @encrypted: Whether the frame was encrypted
  * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
  * -1 failure
  */
 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
-		      size_t len)
+		      size_t len, enum frame_encryption encrypted)
 {
 	const struct ieee802_1x_hdr *hdr;
 	const struct ieee802_1x_eapol_key *key;
@@ -1295,6 +1296,14 @@
 
 	if (sm == NULL)
 		return 0;
+
+	if (encrypted == FRAME_NOT_ENCRYPTED && sm->ctx->encryption_required &&
+	    sm->ctx->encryption_required(sm->ctx->ctx)) {
+		wpa_printf(MSG_DEBUG,
+			   "EAPOL: Discard unencrypted EAPOL frame when encryption since encryption was expected");
+		return 0;
+	}
+
 	sm->dot1xSuppEapolFramesRx++;
 	if (len < sizeof(*hdr)) {
 		sm->dot1xSuppInvalidEapolFramesRx++;
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 630a38e..bbe2b6f 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -321,6 +321,13 @@
 	 * @reason_string: Information to log about the event
 	 */
 	void (*open_ssl_failure_cb)(void *ctx, const char* reason_string);
+
+	/**
+	 * encryption_required - Check whether encryption is required
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * Returns: Whether the current session requires encryption
+	 */
+	bool (*encryption_required)(void *ctx);
 };
 
 
@@ -337,7 +344,7 @@
 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
 			int startPeriod, int maxStart);
 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
-		      size_t len);
+		      size_t len, enum frame_encryption encrypted);
 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled);
 void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid);
@@ -403,7 +410,8 @@
 {
 }
 static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src,
-				    const u8 *buf, size_t len)
+				    const u8 *buf, size_t len,
+				    enum frame_encryption encrypted)
 {
 	return 0;
 }
diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c
index d1c4014..255d0fd 100644
--- a/src/fst/fst_group.c
+++ b/src/fst/fst_group.c
@@ -28,8 +28,13 @@
 	while (s >= 2) {
 		const struct multi_band_ie *mbie =
 			(const struct multi_band_ie *) p;
+		size_t len;
+
 		WPA_ASSERT(mbie->eid == WLAN_EID_MULTI_BAND);
 		WPA_ASSERT(2U + mbie->len >= sizeof(*mbie));
+		len = 2 + mbie->len;
+		if (len > s)
+			break;
 
 		fst_printf(MSG_WARNING,
 			   "%s: %s: mb_ctrl=%u band_id=%u op_class=%u chan=%u bssid="
@@ -45,8 +50,8 @@
 			   mbie->mb_connection_capability,
 			   mbie->fst_session_tmout);
 
-		p += 2 + mbie->len;
-		s -= 2 + mbie->len;
+		p += len;
+		s -= len;
 	}
 }
 
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index cd04008..b7fde1b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1803,6 +1803,7 @@
 		os_memcpy(params->passphrase, p2p->passphrase, os_strlen(p2p->passphrase));
 	} else {
 		p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+		params->passphrase[p2p->cfg->passphrase_len] = '\0';
 	}
 	p2p->passphrase_set = 0;
 	return 0;
@@ -1837,6 +1838,7 @@
 		os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
 		res.ssid_len = p2p->ssid_len;
 		p2p_random(res.passphrase, p2p->cfg->passphrase_len);
+		res.passphrase[p2p->cfg->passphrase_len] = '\0';
 	} else {
 		res.freq = peer->oper_freq;
 		if (p2p->ssid_len) {
@@ -5540,7 +5542,7 @@
 
 
 void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
-				const unsigned int *pref_freq_list,
+				const struct weighted_pcl *pref_freq_list,
 				unsigned int size)
 {
 	unsigned int i;
@@ -5548,10 +5550,11 @@
 	if (size > P2P_MAX_PREF_CHANNELS)
 		size = P2P_MAX_PREF_CHANNELS;
 	p2p->num_pref_freq = size;
+	os_memcpy(p2p->pref_freq_list, pref_freq_list,
+		  size * sizeof(struct weighted_pcl));
 	for (i = 0; i < size; i++) {
-		p2p->pref_freq_list[i] = pref_freq_list[i];
 		p2p_dbg(p2p, "Own preferred frequency list[%u]=%u MHz",
-			i, p2p->pref_freq_list[i]);
+			i, p2p->pref_freq_list[i].freq);
 	}
 }
 
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index f606fbb..768fc10 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -12,6 +12,8 @@
 #include "common/ieee802_11_defs.h"
 #include "wps/wps.h"
 
+struct weighted_pcl;
+
 /* P2P ASP Setup Capability */
 #define P2PS_SETUP_NONE 0
 #define P2PS_SETUP_NEW BIT(0)
@@ -1132,7 +1134,8 @@
 	 * the driver specific to a particular interface type.
 	 */
 	int (*get_pref_freq_list)(void *ctx, int go,
-				  unsigned int *len, unsigned int *freq_list);
+				  unsigned int *len,
+				  struct weighted_pcl *freq_list);
 };
 
 
@@ -2338,6 +2341,8 @@
 					   const u8 *go_dev_addr,
 					   const u8 *ssid, size_t ssid_len);
 
+bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go);
+
 struct p2p_nfc_params {
 	int sel;
 	const u8 *wsc_attr;
@@ -2397,7 +2402,7 @@
 void p2p_expire_peers(struct p2p_data *p2p);
 
 void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
-				const unsigned int *pref_freq_list,
+				const struct weighted_pcl *pref_freq_list,
 				unsigned int size);
 void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
 				   u8 chan);
@@ -2422,6 +2427,6 @@
 bool p2p_wfd_enabled(struct p2p_data *p2p);
 bool is_p2p_allow_6ghz(struct p2p_data *p2p);
 void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value);
-int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size);
+int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size);
 
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 4229d9b..e4f40fe 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "common/qca-vendor.h"
 #include "wps/wps_i.h"
 #include "p2p_i.h"
@@ -111,7 +112,7 @@
 
 
 void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
-				   const unsigned int *preferred_freq_list,
+				   const struct weighted_pcl *pref_freq_list,
 				   unsigned int size)
 {
 	unsigned int i, count = 0;
@@ -126,8 +127,9 @@
 	 * of the vendor IE size.
 	 */
 	for (i = 0; i < size; i++) {
-		if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
-					&op_channel) == 0)
+		if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class,
+					&op_channel) == 0 &&
+		    !(pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE))
 			count++;
 	}
 
@@ -136,10 +138,11 @@
 	wpabuf_put_be24(buf, OUI_QCA);
 	wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST);
 	for (i = 0; i < size; i++) {
-		if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
-					&op_channel) < 0) {
+		if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class,
+					&op_channel) < 0 ||
+		    (pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE)) {
 			wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz",
-				   preferred_freq_list[i]);
+				   pref_freq_list[i].freq);
 			continue;
 		}
 		wpabuf_put_u8(buf, op_class);
@@ -149,7 +152,7 @@
 
 
 void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
-			      struct p2p_channels *chan)
+			      struct p2p_channels *chan, bool is_6ghz_capab)
 {
 	u8 *len;
 	size_t i;
@@ -161,6 +164,9 @@
 
 	for (i = 0; i < chan->reg_classes; i++) {
 		struct p2p_reg_class *c = &chan->reg_class[i];
+
+		if (is_6ghz_op_class(c->reg_class) && !is_6ghz_capab)
+			continue;
 		wpabuf_put_u8(buf, c->reg_class);
 		wpabuf_put_u8(buf, c->channels);
 		wpabuf_put_data(buf, c->channel, c->channels);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 1d53d52..e3d704b 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -142,6 +142,7 @@
 	u8 group_capab;
 	size_t extra = 0;
 	u16 pw_id;
+	bool is_6ghz_capab;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (p2p->wfd_ie_go_neg)
@@ -179,7 +180,22 @@
 		p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
 					      p2p->ext_listen_interval);
 	p2p_buf_add_intended_addr(buf, p2p->intended_addr);
-	p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+	is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+		p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+	if (p2p->num_pref_freq) {
+		bool go = p2p->go_intent == 15;
+		struct p2p_channels pref_chanlist;
+
+		p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list,
+					p2p->num_pref_freq, &pref_chanlist, go);
+		p2p_channels_dump(p2p, "channel list after filtering",
+				  &pref_chanlist);
+		p2p_buf_add_channel_list(buf, p2p->cfg->country,
+					 &pref_chanlist, is_6ghz_capab);
+	} else {
+		p2p_buf_add_channel_list(buf, p2p->cfg->country,
+					 &p2p->channels, is_6ghz_capab);
+	}
 	p2p_buf_add_device_info(buf, p2p, peer);
 	p2p_buf_add_operating_channel(buf, p2p->cfg->country,
 				      p2p->op_reg_class, p2p->op_channel);
@@ -278,6 +294,8 @@
 	u8 group_capab;
 	size_t extra = 0;
 	u16 pw_id;
+	bool is_6ghz_capab;
+	struct p2p_channels pref_chanlist;
 
 	p2p_dbg(p2p, "Building GO Negotiation Response");
 
@@ -328,17 +346,35 @@
 					      p2p->op_channel);
 	}
 	p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+	if (p2p->num_pref_freq) {
+		bool go = (peer && peer->go_state == LOCAL_GO) ||
+			p2p->go_intent == 15;
+
+		p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list,
+					p2p->num_pref_freq, &pref_chanlist, go);
+		p2p_channels_dump(p2p, "channel list after filtering",
+				  &pref_chanlist);
+	} else {
+		p2p_copy_channels(&pref_chanlist, &p2p->channels,
+				  p2p->allow_6ghz);
+	}
 	if (status || peer == NULL) {
 		p2p_buf_add_channel_list(buf, p2p->cfg->country,
-					 &p2p->channels);
+					 &pref_chanlist, false);
 	} else if (peer->go_state == REMOTE_GO) {
+		is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+			p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
 		p2p_buf_add_channel_list(buf, p2p->cfg->country,
-					 &p2p->channels);
+					 &pref_chanlist, is_6ghz_capab);
 	} else {
 		struct p2p_channels res;
-		p2p_channels_intersect(&p2p->channels, &peer->channels,
+
+		is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+			p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+		p2p_channels_intersect(&pref_chanlist, &peer->channels,
 				       &res);
-		p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+		p2p_buf_add_channel_list(buf, p2p->cfg->country, &res,
+				       is_6ghz_capab);
 	}
 	p2p_buf_add_device_info(buf, p2p, peer);
 	if (peer && peer->go_state == LOCAL_GO) {
@@ -562,7 +598,8 @@
 static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
 					struct p2p_device *dev,
 					struct p2p_message *msg,
-					unsigned freq_list[], unsigned int size)
+					const struct weighted_pcl freq_list[],
+					unsigned int size)
 {
 	u8 op_class, op_channel;
 	unsigned int oper_freq = 0, i, j;
@@ -577,10 +614,11 @@
 	 */
 	for (i = 0; i < size && !found; i++) {
 		/* Make sure that the common frequency is supported by peer. */
-		oper_freq = freq_list[i];
+		oper_freq = freq_list[i].freq;
 		if (p2p_freq_to_channel(oper_freq, &op_class,
-					&op_channel) < 0)
-			continue; /* cannot happen due to earlier check */
+					&op_channel) < 0 ||
+		    !p2p_pref_freq_allowed(&freq_list[i], go))
+			continue;
 		for (j = 0; j < msg->channel_list_len; j++) {
 			if (!msg->channel_list ||
 			    op_channel != msg->channel_list[j])
@@ -609,7 +647,8 @@
 static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
 				     struct p2p_device *dev,
 				     struct p2p_message *msg,
-				     unsigned freq_list[], unsigned int size)
+				     const struct weighted_pcl freq_list[],
+				     unsigned int size)
 {
 	u8 op_class, op_channel;
 	unsigned int oper_freq = 0, i, j;
@@ -625,11 +664,13 @@
 			oper_freq = p2p_channel_to_freq(
 				msg->pref_freq_list[2 * j],
 				msg->pref_freq_list[2 * j + 1]);
-			if (freq_list[i] != oper_freq)
+			if (freq_list[i].freq != oper_freq)
 				continue;
 			if (p2p_freq_to_channel(oper_freq, &op_class,
 						&op_channel) < 0)
 				continue; /* cannot happen */
+			if (!p2p_pref_freq_allowed(&freq_list[i], go))
+				break;
 			p2p->op_reg_class = op_class;
 			p2p->op_channel = op_channel;
 			os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -652,7 +693,7 @@
 void p2p_check_pref_chan(struct p2p_data *p2p, int go,
 			 struct p2p_device *dev, struct p2p_message *msg)
 {
-	unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
+	unsigned int size;
 	unsigned int i;
 	u8 op_class, op_channel;
 	char txt[100], *pos, *end;
@@ -669,25 +710,30 @@
 
 	/* Obtain our preferred frequency list from driver based on P2P role. */
 	size = P2P_MAX_PREF_CHANNELS;
-	if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
-					 freq_list))
+	if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go,
+					 &p2p->num_pref_freq,
+					 p2p->pref_freq_list))
+		return;
+	size = p2p->num_pref_freq;
+	if (!size)
 		return;
 	/* Filter out frequencies that are not acceptable for P2P use */
 	i = 0;
 	while (i < size) {
-		if (p2p_freq_to_channel(freq_list[i], &op_class,
-					&op_channel) < 0 ||
+		if (p2p_freq_to_channel(p2p->pref_freq_list[i].freq,
+					&op_class, &op_channel) < 0 ||
 		    (!p2p_channels_includes(&p2p->cfg->channels,
 					    op_class, op_channel) &&
 		     (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
 						   op_class, op_channel)))) {
 			p2p_dbg(p2p,
 				"Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
-				freq_list[i], go);
+				p2p->pref_freq_list[i].freq, go);
 			if (size - i - 1 > 0)
-				os_memmove(&freq_list[i], &freq_list[i + 1],
+				os_memmove(&p2p->pref_freq_list[i],
+					   &p2p->pref_freq_list[i + 1],
 					   (size - i - 1) *
-					   sizeof(unsigned int));
+					   sizeof(struct weighted_pcl));
 			size--;
 			continue;
 		}
@@ -699,7 +745,8 @@
 	pos = txt;
 	end = pos + sizeof(txt);
 	for (i = 0; i < size; i++) {
-		res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
+		res = os_snprintf(pos, end - pos, " %u",
+				  p2p->pref_freq_list[i].freq);
 		if (os_snprintf_error(end - pos, res))
 			break;
 		pos += res;
@@ -713,11 +760,14 @@
 	 * our preferred channel list.
 	 */
 	for (i = 0; i < size; i++) {
-		if (freq_list[i] == (unsigned int) dev->oper_freq)
+		if (p2p->pref_freq_list[i].freq ==
+		    (unsigned int) dev->oper_freq &&
+		    p2p_pref_freq_allowed(&p2p->pref_freq_list[i], go))
 			break;
 	}
 	if (i != size &&
-	    p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
+	    p2p_freq_to_channel(p2p->pref_freq_list[i].freq, &op_class,
+				&op_channel) == 0) {
 		/* Peer operating channel preference matches our preference */
 		p2p->op_reg_class = op_class;
 		p2p->op_channel = op_channel;
@@ -735,9 +785,11 @@
 	  * _not_ included in the GO Negotiation Request or Invitation Request.
 	  */
 	if (msg->pref_freq_list_len == 0)
-		p2p_check_pref_chan_no_recv(p2p, go, dev, msg, freq_list, size);
+		p2p_check_pref_chan_no_recv(p2p, go, dev, msg,
+					    p2p->pref_freq_list, size);
 	else
-		p2p_check_pref_chan_recv(p2p, go, dev, msg, freq_list, size);
+		p2p_check_pref_chan_recv(p2p, go, dev, msg,
+					 p2p->pref_freq_list, size);
 }
 
 
@@ -1085,6 +1137,7 @@
 	struct p2p_channels res;
 	u8 group_capab;
 	size_t extra = 0;
+	bool is_6ghz_capab;
 
 	p2p_dbg(p2p, "Building GO Negotiation Confirm");
 
@@ -1128,7 +1181,9 @@
 		p2p_buf_add_operating_channel(buf, (const char *) resp_chan,
 					      resp_chan[3], resp_chan[4]);
 	p2p_channels_intersect(&p2p->channels, &peer->channels, &res);
-	p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+	is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+		p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+	p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, is_6ghz_capab);
 	if (go) {
 		p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
 				     p2p->ssid_len);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index b5e5c2b..bebc5e2 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -10,6 +10,7 @@
 #define P2P_I_H
 
 #include "utils/list.h"
+#include "drivers/driver.h"
 #include "p2p.h"
 #include "ap/ap_config.h"
 
@@ -553,7 +554,7 @@
 
 	struct wpabuf **vendor_elem;
 
-	unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
+	struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
 	unsigned int num_pref_freq;
 
 	/* Override option for preferred operating channel in GO Negotiation */
@@ -769,7 +770,7 @@
 void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
 				   u8 reg_class, u8 channel);
 void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
-			      struct p2p_channels *chan);
+			      struct p2p_channels *chan, bool is_6ghz_capab);
 void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout,
 				u8 client_timeout);
 void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr);
@@ -800,7 +801,7 @@
 int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
 		     int all_attr);
 void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
-				   const unsigned int *preferred_freq_list,
+				   const struct weighted_pcl *pref_freq_list,
 				   unsigned int size);
 
 /* p2p_sd.c */
@@ -902,6 +903,10 @@
 void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
 int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
 			  u8 *status);
+void p2p_pref_channel_filter(const struct p2p_channels *a,
+			     const struct weighted_pcl *freq_list,
+			     unsigned int num_channels,
+			     struct p2p_channels *res, bool go);
 void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
 PRINTF_FORMAT(2, 3);
 void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index ab00722..bca5b90 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -24,6 +24,7 @@
 	u8 *len;
 	const u8 *dev_addr;
 	size_t extra = 0;
+	bool is_6ghz_capab;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
@@ -74,7 +75,10 @@
 					      p2p->op_channel);
 	if (p2p->inv_bssid_set)
 		p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
-	p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+	is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+		p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+	p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels,
+				 is_6ghz_capab);
 	if (go_dev_addr)
 		dev_addr = go_dev_addr;
 	else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
@@ -155,8 +159,14 @@
 					      reg_class, channel);
 	if (group_bssid)
 		p2p_buf_add_group_bssid(buf, group_bssid);
-	if (channels)
-		p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
+	if (channels) {
+		bool is_6ghz_capab;
+
+		is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+			p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+		p2p_buf_add_channel_list(buf, p2p->cfg->country, channels,
+					 is_6ghz_capab);
+	}
 	p2p_buf_update_ie_hdr(buf, len);
 
 #ifdef CONFIG_WIFI_DISPLAY
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 338b47e..1a78e14 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -124,9 +124,15 @@
 		}
 
 		if (shared_group ||
-		    (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW)))
+		    (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) {
+			bool is_6ghz_capab;
+
+			is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+				p2p_is_peer_6ghz_capab(
+					p2p, dev->info.p2p_device_addr);
 			p2p_buf_add_channel_list(buf, p2p->cfg->country,
-						 &p2p->channels);
+						 &p2p->channels, is_6ghz_capab);
+		}
 
 		if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
 		    (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
@@ -356,9 +362,15 @@
 		}
 
 		if (persist ||
-		    (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+		    (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) {
+			bool is_6ghz_capab;
+
+			is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+				p2p_is_peer_6ghz_capab(
+					p2p, dev->info.p2p_device_addr);
 			p2p_buf_add_channel_list(buf, p2p->cfg->country,
-						 &p2p->channels);
+						 &p2p->channels, is_6ghz_capab);
+		}
 
 		if (!persist && conncap)
 			p2p_buf_add_connection_capability(buf, conncap);
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index a203606..c1f0084 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -519,14 +519,14 @@
 }
 
 
-int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size)
+int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size)
 {
 	int i;
 
 	for (i = 0; i < size; i++) {
-		if (is_6ghz_freq(pref_freq_list[i])) {
+		if (is_6ghz_freq(pref_freq_list[i].freq)) {
 			wpa_printf(MSG_DEBUG, "P2P: Remove 6 GHz channel %d",
-				   pref_freq_list[i]);
+				   pref_freq_list[i].freq);
 			size--;
 			os_memmove(&pref_freq_list[i], &pref_freq_list[i + 1],
 				   (size - i) * sizeof(pref_freq_list[0]));
@@ -535,3 +535,79 @@
 	}
 	return i;
 }
+
+
+/**
+ * p2p_pref_freq_allowed - Based on the flags set, check if the preferred
+ * frequency is allowed
+ * @freq_list: Weighted preferred channel list
+ * @go: Whether the local device is the group owner
+ * Returns: Whether the preferred frequency is allowed
+ */
+bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go)
+{
+	if (freq_list->flag & WEIGHTED_PCL_EXCLUDE)
+		return false;
+	if (!(freq_list->flag & WEIGHTED_PCL_CLI) && !go)
+		return false;
+	if (!(freq_list->flag & WEIGHTED_PCL_GO) && go)
+		return false;
+	return true;
+}
+
+
+static int p2p_check_pref_channel(int channel, u8 op_class,
+				  const struct weighted_pcl *freq_list,
+				  unsigned int num_channels, bool go)
+{
+	unsigned int i;
+
+	/* If the channel is present in the preferred channel list, check if it
+	 * has appropriate flags for the role.
+	 */
+	for (i = 0; i < num_channels; i++) {
+		if (p2p_channel_to_freq(op_class, channel) !=
+		    (int) freq_list[i].freq)
+			continue;
+		if (!p2p_pref_freq_allowed(&freq_list[i], go))
+			return -1;
+		break;
+	}
+
+	return 0;
+}
+
+
+void p2p_pref_channel_filter(const struct p2p_channels *p2p_chan,
+			     const struct weighted_pcl *freq_list,
+			     unsigned int num_channels,
+			     struct p2p_channels *res, bool go)
+{
+	size_t i, j;
+
+	os_memset(res, 0, sizeof(*res));
+
+	for (i = 0; i < p2p_chan->reg_classes; i++) {
+		const struct p2p_reg_class *reg = &p2p_chan->reg_class[i];
+		struct p2p_reg_class *res_reg = &res->reg_class[i];
+
+		if (num_channels > 0) {
+			for (j = 0; j < reg->channels; j++) {
+				if (p2p_check_pref_channel(reg->channel[j],
+							   reg->reg_class,
+							   freq_list,
+							   num_channels,
+							   go) < 0)
+					continue;
+
+				res_reg->channel[res_reg->channels++] =
+					reg->channel[j];
+			}
+		}
+
+		if (res_reg->channels == 0)
+			continue;
+		res->reg_classes++;
+		res_reg->reg_class = reg->reg_class;
+	}
+}
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 1a38bf6..a96655f 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -75,7 +75,8 @@
 		return;
 	}
 
-	eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
+	eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len,
+			  FRAME_ENCRYPTION_UNKNOWN);
 }
 
 
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 00b7e84..17a79f9 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -187,7 +187,7 @@
 	u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
 
 	if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
-	    wpa_sm_get_state(sm) == WPA_COMPLETED) {
+	    wpa_sm_get_state(sm) == WPA_COMPLETED && !error) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: PTK0 rekey not allowed, reconnecting");
 		wpa_sm_reconnect(sm);
@@ -553,6 +553,8 @@
 		       sm->proto == WPA_PROTO_OSEN) ?
 		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
 	key_info = ver | WPA_KEY_INFO_KEY_TYPE;
+	if (sm->ptk_set && sm->proto != WPA_PROTO_WPA)
+		key_info |= WPA_KEY_INFO_SECURE;
 	if (mic_len)
 		key_info |= WPA_KEY_INFO_MIC;
 	else
@@ -673,7 +675,8 @@
 					  const unsigned char *src_addr,
 					  const struct wpa_eapol_key *key,
 					  u16 ver, const u8 *key_data,
-					  size_t key_data_len)
+					  size_t key_data_len,
+					  enum frame_encryption encrypted)
 {
 	struct wpa_eapol_ie_parse ie;
 	struct wpa_ptk *ptk;
@@ -681,6 +684,13 @@
 	u8 *kde, *kde_buf = NULL;
 	size_t kde_len;
 
+	if (encrypted == FRAME_NOT_ENCRYPTED && sm->tk_set &&
+	    wpa_sm_pmf_enabled(sm)) {
+		wpa_printf(MSG_DEBUG,
+			   "RSN: Discard unencrypted EAPOL-Key msg 1/4 when TK is set and PMF is enabled");
+		return;
+	}
+
 	if (wpa_sm_get_network_ctx(sm) == NULL) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
 			"found (msg 1 of 4)");
@@ -695,7 +705,6 @@
 		return;
 	}
 
-	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
 	wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RX message 1 of 4-Way "
 		"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
 
@@ -705,8 +714,11 @@
 		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
 		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
 			    key_data, key_data_len);
-		if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
-			goto failed;
+		if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RSN: Discard EAPOL-Key msg 1/4 with invalid IEs/KDEs");
+			return;
+		}
 		if (ie.pmkid) {
 			wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
 				    "Authenticator", ie.pmkid, PMKID_LEN);
@@ -722,6 +734,8 @@
 	if (res)
 		goto failed;
 
+	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
+
 	if (sm->renew_snonce) {
 		if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -969,6 +983,7 @@
 	os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
 	sm->ptk.tk_len = 0;
 	sm->ptk.installed = 1;
+	sm->tk_set = true;
 
 	if (sm->wpa_ptk_rekey) {
 		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
@@ -2476,6 +2491,7 @@
  * @src_addr: Source MAC address of the EAPOL packet
  * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
  * @len: Length of the EAPOL frame
+ * @encrypted: Whether the frame was encrypted
  * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
  *
  * This function is called for each received EAPOL frame. Other than EAPOL-Key
@@ -2487,7 +2503,7 @@
  * successful key handshake.
  */
 int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
-		    const u8 *buf, size_t len)
+		    const u8 *buf, size_t len, enum frame_encryption encrypted)
 {
 	size_t plen, data_len, key_data_len;
 	const struct ieee802_1x_hdr *hdr;
@@ -2722,7 +2738,8 @@
 			/* 1/4 4-Way Handshake */
 			wpa_supplicant_process_1_of_4(sm, src_addr, key,
 						      ver, key_data,
-						      key_data_len);
+						      key_data_len,
+						      encrypted);
 		}
 	} else {
 		if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
@@ -3063,6 +3080,7 @@
 		os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
 		os_memset(&sm->igtk, 0, sizeof(sm->igtk));
 		os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
+		sm->tk_set = false;
 	}
 
 #ifdef CONFIG_TDLS
@@ -3850,6 +3868,7 @@
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
 	sm->ptk_set = 0;
 	sm->tptk_set = 0;
+	sm->tk_set = false;
 	sm->pmk_len = 0;
 	os_memset(sm->pmk, 0, sizeof(sm->pmk));
 	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
@@ -3886,7 +3905,7 @@
 {
 	if (!sm)
 		return 0;
-	return sm->ptk.installed;
+	return sm->tk_set || sm->ptk.installed;
 }
 
 
@@ -5033,6 +5052,7 @@
 	os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
 	sm->ptk.tk_len = 0;
 	sm->ptk.installed = 1;
+	sm->tk_set = true;
 
 	/* FILS HLP Container */
 	fils_process_hlp_container(sm, ie_start, end - ie_start);
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 00fa0bc..7cca718 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -19,6 +19,7 @@
 struct wpa_config_blob;
 struct hostapd_freq_params;
 struct wpa_channel_info;
+enum frame_encryption;
 
 struct wpa_sm_ctx {
 	void *ctx; /* pointer to arbitrary upper level context */
@@ -184,7 +185,7 @@
 void wpa_sm_aborted_cached(struct wpa_sm *sm);
 void wpa_sm_aborted_external_cached(struct wpa_sm *sm);
 int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
-		    const u8 *buf, size_t len);
+		    const u8 *buf, size_t len, enum frame_encryption encrypted);
 int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
 int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
 struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm);
@@ -368,7 +369,8 @@
 }
 
 static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
-				  const u8 *buf, size_t len)
+				  const u8 *buf, size_t len,
+				  enum frame_encryption encrypted)
 {
 	return -1;
 }
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 9d3b538..6d4b07b 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -467,6 +467,7 @@
 		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
 		return -1;
 	}
+	sm->tk_set = true;
 
 	wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
 			 sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 579616f..fabd6cb 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -27,6 +27,7 @@
 	size_t pmk_len;
 	struct wpa_ptk ptk, tptk;
 	int ptk_set, tptk_set;
+	bool tk_set; /* Whether any TK is configured to the driver */
 	unsigned int msg_3_of_4_ok:1;
 	u8 snonce[WPA_NONCE_LEN];
 	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index d1436e2..1eaebde 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -276,6 +276,7 @@
 OBJS += src/common/sae.c
 ifdef CONFIG_SAE_PK
 L_CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
 OBJS += src/common/sae_pk.c
 endif
 NEED_ECC=y
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 1c6911b..0a71558 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -266,6 +266,7 @@
 OBJS += ../src/common/sae.o
 ifdef CONFIG_SAE_PK
 CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
 OBJS += ../src/common/sae_pk.o
 endif
 NEED_ECC=y
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index a099a85..0cc5f39 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -168,11 +168,16 @@
 # milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
 #	format
 #
-# imsi_privacy_key: IMSI privacy key (PEM encoded X.509v3 certificate)
+# imsi_privacy_cert: IMSI privacy certificate (PEM encoded X.509v3 certificate)
 #	This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
 #	identity (IMSI) to improve privacy. The X.509v3 certificate needs to
 #	include a 2048-bit RSA public key and this is from the operator who
 #	authenticates the SIM/USIM.
+# imsi_privacy_attr: IMSI privacy attribute
+#	This field is used to help the EAP-SIM/AKA/AKA' server to identify
+#	the used certificate (and as such, the matching private key). This
+#	is set to an attribute in name=value format if the operator needs
+#	this information.
 #
 # domain_suffix_match: Constraint for server domain name
 #	If set, this FQDN is used as a suffix match requirement for the AAA
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 7b31d8e..7de9249 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -90,7 +90,7 @@
 					      &conf->op_class,
 					      &conf->channel);
 
-	if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) {
+	if (hostapd_get_oper_chwidth(conf) == CONF_OPER_CHWIDTH_80P80MHZ) {
 		ieee80211_freq_to_chan(ssid->vht_center_freq2,
 				       &freq_seg_idx);
 		hostapd_set_oper_centr_freq_seg1_idx(conf, freq_seg_idx);
@@ -112,15 +112,15 @@
 
 #ifdef CONFIG_P2P
 	switch (hostapd_get_oper_chwidth(conf)) {
-	case CHANWIDTH_80MHZ:
-	case CHANWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
 		center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel,
 							conf->op_class);
 		wpa_printf(MSG_DEBUG,
 			   "VHT center channel %u for 80 or 80+80 MHz bandwidth",
 			   center_chan);
 		break;
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel,
 							 conf->op_class);
 		wpa_printf(MSG_DEBUG,
@@ -133,7 +133,7 @@
 		 * try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
 		 * not supported.
 		 */
-		hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
+		hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ);
 		ieee80211_freq_to_channel_ext(ssid->frequency, 0,
 					      conf->vht_oper_chwidth,
 					      &conf->op_class,
@@ -145,7 +145,7 @@
 				   "VHT center channel %u for auto-selected 160 MHz bandwidth",
 				   center_chan);
 		} else {
-			hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
+			hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_80MHZ);
 			ieee80211_freq_to_channel_ext(ssid->frequency, 0,
 						      conf->vht_oper_chwidth,
 						      &conf->op_class,
@@ -174,7 +174,7 @@
 		   conf->channel);
 	hostapd_set_oper_centr_freq_seg0_idx(
 		conf, conf->channel + conf->secondary_channel * 2);
-	hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+	hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_USE_HT);
 }
 
 
@@ -201,14 +201,14 @@
 static int get_max_oper_chwidth_6ghz(int chwidth)
 {
 	switch (chwidth) {
-	case CHANWIDTH_USE_HT:
+	case CONF_OPER_CHWIDTH_USE_HT:
 		return 20;
-	case CHANWIDTH_40MHZ_6GHZ:
+	case CONF_OPER_CHWIDTH_40MHZ_6GHZ:
 		return 40;
-	case CHANWIDTH_80MHZ:
+	case CONF_OPER_CHWIDTH_80MHZ:
 		return 80;
-	case CHANWIDTH_80P80MHZ:
-	case CHANWIDTH_160MHZ:
+	case CONF_OPER_CHWIDTH_80P80MHZ:
+	case CONF_OPER_CHWIDTH_160MHZ:
 		return 160;
 	default:
 		return 0;
@@ -249,8 +249,8 @@
 		wpa_printf(MSG_DEBUG,
 			   "Secondary channel offset %d for P2P group",
 			   conf->secondary_channel);
-		if (ssid->max_oper_chwidth == CHANWIDTH_40MHZ_6GHZ)
-			ssid->max_oper_chwidth = CHANWIDTH_USE_HT;
+		if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_40MHZ_6GHZ)
+			ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT;
 	}
 
 	if ((is_chanwidth_40_80 || is_chanwidth_160) && ssid->p2p_group &&
@@ -266,7 +266,7 @@
 			      struct hostapd_config *conf)
 {
 	conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0,
-						      CHANWIDTH_USE_HT,
+						      CONF_OPER_CHWIDTH_USE_HT,
 						      &conf->op_class,
 						      &conf->channel);
 	if (conf->hw_mode == NUM_HOSTAPD_MODES) {
@@ -1234,9 +1234,11 @@
 
 
 void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
-				const u8 *src_addr, const u8 *buf, size_t len)
+				const u8 *src_addr, const u8 *buf, size_t len,
+				enum frame_encryption encrypted)
 {
-	ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len);
+	ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len,
+			   encrypted);
 }
 
 
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index ccd3e7b..865429e 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -16,7 +16,8 @@
 			     struct wpa_ssid *ssid);
 void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
-				const u8 *src_addr, const u8 *buf, size_t len);
+				const u8 *src_addr, const u8 *buf, size_t len,
+				enum frame_encryption encrypted);
 int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			      const u8 *p2p_dev_addr);
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 429c6e7..eb97a61 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1281,12 +1281,16 @@
 	end = pos + bss->beacon_ie_len;
 
 	while (end - pos > 1) {
-		if (2 + pos[1] > end - pos)
+		u8 id, len;
+
+		id = *pos++;
+		len = *pos++;
+		if (len > end - pos)
 			break;
-		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
-		    vendor_type == WPA_GET_BE32(&pos[2]))
-			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
-		pos += 2 + pos[1];
+		if (id == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
+		    vendor_type == WPA_GET_BE32(pos))
+			wpabuf_put_data(buf, pos + 4, len - 4);
+		pos += len;
 	}
 
 	if (wpabuf_len(buf) == 0) {
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index c8844bb..aa775ca 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2434,8 +2434,8 @@
 	{ INT_RANGE(ht, 0, 1) },
 	{ INT_RANGE(vht, 0, 1) },
 	{ INT_RANGE(ht40, -1, 1) },
-	{ INT_RANGE(max_oper_chwidth, CHANWIDTH_USE_HT,
-		    CHANWIDTH_80P80MHZ) },
+	{ INT_RANGE(max_oper_chwidth, CONF_OPER_CHWIDTH_USE_HT,
+		    CONF_OPER_CHWIDTH_80P80MHZ) },
 	{ INT(vht_center_freq1) },
 	{ INT(vht_center_freq2) },
 #ifdef IEEE8021X_EAPOL
@@ -2503,7 +2503,8 @@
 	{ INTe(machine_ocsp, machine_cert.ocsp) },
 	{ INT(eapol_flags) },
 	{ INTe(sim_num, sim_num) },
-	{ STRe(imsi_privacy_key, imsi_privacy_key) },
+	{ STRe(imsi_privacy_cert, imsi_privacy_cert) },
+	{ STRe(imsi_privacy_attr, imsi_privacy_attr) },
 	{ STRe(openssl_ciphers, openssl_ciphers) },
 	{ INTe(erp, erp) },
 #endif /* IEEE8021X_EAPOL */
@@ -2771,7 +2772,8 @@
 	bin_clear_free(eap->identity, eap->identity_len);
 	os_free(eap->anonymous_identity);
 	os_free(eap->imsi_identity);
-	os_free(eap->imsi_privacy_key);
+	os_free(eap->imsi_privacy_cert);
+	os_free(eap->imsi_privacy_attr);
 	os_free(eap->machine_identity);
 	bin_clear_free(eap->password, eap->password_len);
 	bin_clear_free(eap->machine_password, eap->machine_password_len);
@@ -2875,7 +2877,8 @@
 		os_free(cred->req_conn_capab_port[i]);
 	os_free(cred->req_conn_capab_port);
 	os_free(cred->req_conn_capab_proto);
-	os_free(cred->imsi_privacy_key);
+	os_free(cred->imsi_privacy_cert);
+	os_free(cred->imsi_privacy_attr);
 	os_free(cred);
 }
 
@@ -3911,9 +3914,15 @@
 		return 0;
 	}
 
-	if (os_strcmp(var, "imsi_privacy_key") == 0) {
-		os_free(cred->imsi_privacy_key);
-		cred->imsi_privacy_key = val;
+	if (os_strcmp(var, "imsi_privacy_cert") == 0) {
+		os_free(cred->imsi_privacy_cert);
+		cred->imsi_privacy_cert = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "imsi_privacy_attr") == 0) {
+		os_free(cred->imsi_privacy_attr);
+		cred->imsi_privacy_attr = val;
 		return 0;
 	}
 
@@ -4067,8 +4076,11 @@
 	if (os_strcmp(var, "imsi") == 0)
 		return alloc_strdup(cred->imsi);
 
-	if (os_strcmp(var, "imsi_privacy_key") == 0)
-		return alloc_strdup(cred->imsi_privacy_key);
+	if (os_strcmp(var, "imsi_privacy_cert") == 0)
+		return alloc_strdup(cred->imsi_privacy_cert);
+
+	if (os_strcmp(var, "imsi_privacy_attr") == 0)
+		return alloc_strdup(cred->imsi_privacy_attr);
 
 	if (os_strcmp(var, "milenage") == 0) {
 		if (!(cred->milenage))
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 77d6ab5..f33618c 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -182,14 +182,24 @@
 	char *milenage;
 
 	/**
-	 * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+	 * imsi_privacy_cert - IMSI privacy certificate
 	 *
 	 * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
-	 * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
-	 * include a 2048-bit RSA public key and this is from the operator who
-	 * authenticates the SIM/USIM.
+	 * identity (IMSI) to improve privacy. The referenced PEM-encoded
+	 * X.509v3 certificate needs to include a 2048-bit RSA public key and
+	 * this is from the operator who authenticates the SIM/USIM.
 	 */
-	char *imsi_privacy_key;
+	char *imsi_privacy_cert;
+
+	/**
+	 * imsi_privacy_attr - IMSI privacy attribute
+	 *
+	 * This field is used to help the EAP-SIM/AKA/AKA' server to identify
+	 * the used certificate (and as such, the matching private key). This
+	 * is set to an attribute in name=value format if the operator needs
+	 * this information.
+	 */
+	char *imsi_privacy_attr;
 
 	/**
 	 * engine - Use an engine for private key operations
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 978cc6a..3b9f60b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1036,6 +1036,13 @@
 		fprintf(f, "\tcert_id=\"%s\"\n", cred->cert_id);
 	if (cred->ca_cert_id)
 		fprintf(f, "\tca_cert_id=\"%s\"\n", cred->ca_cert_id);
+
+	if (cred->imsi_privacy_cert)
+		fprintf(f, "\timsi_privacy_cert=\"%s\"\n",
+			cred->imsi_privacy_cert);
+	if (cred->imsi_privacy_attr)
+		fprintf(f, "\timsi_privacy_attr=\"%s\"\n",
+			cred->imsi_privacy_attr);
 }
 
 
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 4d3d114..f1f6cc4 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -560,7 +560,7 @@
 
 	int he;
 
-	int max_oper_chwidth;
+	enum oper_chan_width max_oper_chwidth;
 
 	unsigned int vht_center_freq1;
 	unsigned int vht_center_freq2;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e8a8118..8cc02a6 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -866,6 +866,8 @@
 	} else if (os_strcasecmp(cmd,
 				 "dpp_ignore_netaccesskey_mismatch") == 0) {
 		wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
+	} else if (os_strcasecmp(cmd, "dpp_discard_public_action") == 0) {
+		wpa_s->dpp_discard_public_action = atoi(value);
 	} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
 		dpp_test = atoi(value);
 #endif /* CONFIG_DPP */
@@ -5978,17 +5980,19 @@
 	if (freq2 < 0)
 		return -1;
 	if (freq2)
-		return CHANWIDTH_80P80MHZ;
+		return CONF_OPER_CHWIDTH_80P80MHZ;
 
 	switch (chwidth) {
 	case 0:
 	case 20:
 	case 40:
-		return CHANWIDTH_USE_HT;
+		return CONF_OPER_CHWIDTH_USE_HT;
 	case 80:
-		return CHANWIDTH_80MHZ;
+		return CONF_OPER_CHWIDTH_80MHZ;
 	case 160:
-		return CHANWIDTH_160MHZ;
+		return CONF_OPER_CHWIDTH_160MHZ;
+	case 320:
+		return CONF_OPER_CHWIDTH_320MHZ;
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
 			   chwidth);
@@ -6095,7 +6099,7 @@
 		return -1;
 
 	if (allow_6ghz && chwidth == 40)
-		max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+		max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
 
 	pos2 = os_strstr(pos, " ssid=");
 	if (pos2) {
@@ -6751,7 +6755,7 @@
 	allow_6ghz = os_strstr(cmd, " allow_6ghz") != NULL;
 
 	if (allow_6ghz && chwidth == 40)
-		max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+		max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
 
 	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
 			       max_oper_chwidth, pref_freq, he, edmg,
@@ -6897,7 +6901,7 @@
 		return -1;
 
 	if (allow_6ghz && chwidth == 40)
-		max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+		max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
 
 	/* Allow DFS to be used for Autonomous GO */
 	wpa_s->p2p_go_allow_dfs = !!(wpa_s->drv_flags &
@@ -8123,7 +8127,7 @@
 int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
 						enum wpa_driver_if_type if_type,
 						unsigned int *num,
-						unsigned int *freq_list)
+						struct weighted_pcl *freq_list)
 {
 	char *pos = wpa_s->get_pref_freq_list_override;
 	char *end;
@@ -8147,7 +8151,8 @@
 	pos++;
 	end = os_strchr(pos, ' ');
 	while (pos && (!end || pos < end) && count < *num) {
-		freq_list[count++] = atoi(pos);
+		freq_list[count].freq = atoi(pos);
+		freq_list[count++].flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
 		pos = os_strchr(pos, ',');
 		if (pos)
 			pos++;
@@ -8162,10 +8167,11 @@
 static int wpas_ctrl_iface_get_pref_freq_list(
 	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
 {
-	unsigned int freq_list[100], num = 100, i;
+	unsigned int num = 100, i;
 	int ret;
 	enum wpa_driver_if_type iface_type;
 	char *pos, *end;
+	struct weighted_pcl freq_list[100];
 
 	pos = buf;
 	end = buf + buflen;
@@ -8196,7 +8202,7 @@
 
 	for (i = 0; i < num; i++) {
 		ret = os_snprintf(pos, end - pos, "%s%u",
-				  i > 0 ? "," : "", freq_list[i]);
+				  i > 0 ? "," : "", freq_list[i].freq);
 		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
@@ -8556,6 +8562,8 @@
 	wpa_s->dpp_discovery_override = NULL;
 	os_free(wpa_s->dpp_groups_override);
 	wpa_s->dpp_groups_override = NULL;
+	wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
+	wpa_s->dpp_discard_public_action = 0;
 	dpp_test = DPP_TEST_DISABLED;
 #endif /* CONFIG_DPP */
 #endif /* CONFIG_TESTING_OPTIONS */
@@ -8840,6 +8848,7 @@
 	unsigned int manual_scan_only_new = 0;
 	unsigned int scan_only = 0;
 	unsigned int scan_id_count = 0;
+	unsigned int manual_non_coloc_6ghz = 0;
 	int scan_id[MAX_SCAN_ID];
 	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
 				 struct wpa_scan_results *scan_res);
@@ -8917,6 +8926,10 @@
 				os_strstr(params, "wildcard_ssid=1") != NULL;
 		}
 
+		pos = os_strstr(params, "non_coloc_6ghz=");
+		if (pos)
+			manual_non_coloc_6ghz = !!atoi(pos + 15);
+
 		pos = params;
 		while (pos && *pos != '\0') {
 			if (os_strncmp(pos, "ssid ", 5) == 0) {
@@ -8986,6 +8999,7 @@
 		wpa_s->manual_scan_use_id = manual_scan_use_id;
 		wpa_s->manual_scan_only_new = manual_scan_only_new;
 		wpa_s->scan_id_count = scan_id_count;
+		wpa_s->manual_non_coloc_6ghz = manual_non_coloc_6ghz;
 		os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
 		wpa_s->scan_res_handler = scan_res_handler;
 		os_free(wpa_s->manual_scan_freqs);
@@ -9009,6 +9023,7 @@
 		wpa_s->manual_scan_use_id = manual_scan_use_id;
 		wpa_s->manual_scan_only_new = manual_scan_only_new;
 		wpa_s->scan_id_count = scan_id_count;
+		wpa_s->manual_non_coloc_6ghz = manual_non_coloc_6ghz;
 		os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
 		wpa_s->scan_res_handler = scan_res_handler;
 		os_free(wpa_s->manual_scan_freqs);
@@ -9523,7 +9538,7 @@
 		return -1;
 	}
 
-	wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
+	wpa_supplicant_rx_eapol(wpa_s, src, buf, len, FRAME_ENCRYPTION_UNKNOWN);
 	os_free(buf);
 
 	return 0;
@@ -10022,8 +10037,9 @@
 		setup_cmd = atoi(tok_s + os_strlen(" setup_cmd="));
 
 	tok_s = os_strstr(cmd, " twt=");
-	if (tok_s)
-		sscanf(tok_s + os_strlen(" twt="), "%llu", &twt);
+	if (tok_s &&
+	    sscanf(tok_s + os_strlen(" twt="), "%llu", &twt) != 1)
+		return -1;
 
 	tok_s = os_strstr(cmd, " requestor=");
 	if (tok_s)
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index b6dbc98..60342cd 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -802,7 +802,17 @@
 	}
 
 	addr = get_param(cmd, " tcp_addr=");
-	if (addr) {
+	if (addr && os_strcmp(addr, "from-uri") == 0) {
+		os_free(addr);
+		if (!peer_bi->host) {
+			wpa_printf(MSG_INFO,
+				   "DPP: TCP address not available in peer URI");
+			return -1;
+		}
+		tcp = 1;
+		os_memcpy(&ipaddr, peer_bi->host, sizeof(ipaddr));
+		tcp_port = peer_bi->port;
+	} else if (addr) {
 		int res;
 
 		res = hostapd_parse_ip_addr(addr, &ipaddr);
@@ -3140,6 +3150,13 @@
 		return;
 	if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
 		return;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->dpp_discard_public_action) {
+		wpa_printf(MSG_DEBUG,
+			   "TESTING: Discard received DPP Public Action frame");
+		return;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	hdr = buf;
 	buf += 4;
 	len -= 4;
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 237f4e0..b0af1cd 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -964,7 +964,7 @@
 static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s,
 					     enum wpa_driver_if_type if_type,
 					     unsigned int *num,
-					     unsigned int *freq_list)
+					     struct weighted_pcl *freq_list)
 {
 #ifdef CONFIG_TESTING_OPTIONS
 	if (wpa_s->get_pref_freq_list_override)
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index f806895..efec31c 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -714,7 +714,7 @@
 
 	printf("Sending fake EAP-Request-Identity\n");
 	eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf,
-			  sizeof(*hdr) + 5);
+			  sizeof(*hdr) + 5, FRAME_ENCRYPTION_UNKNOWN);
 }
 
 
@@ -842,7 +842,8 @@
 			  wpabuf_len(eap));
 		eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
 				  (u8 *) dot1x,
-				  sizeof(*dot1x) + wpabuf_len(eap));
+				  sizeof(*dot1x) + wpabuf_len(eap),
+				  FRAME_ENCRYPTION_UNKNOWN);
 		os_free(dot1x);
 	}
 }
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7234de4..6080eb3 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3665,7 +3665,8 @@
 			wpa_supplicant_rx_eapol(
 				wpa_s, wpa_s->pending_eapol_rx_src,
 				wpabuf_head(wpa_s->pending_eapol_rx),
-				wpabuf_len(wpa_s->pending_eapol_rx));
+				wpabuf_len(wpa_s->pending_eapol_rx),
+				wpa_s->pending_eapol_encrypted);
 		}
 		wpabuf_free(wpa_s->pending_eapol_rx);
 		wpa_s->pending_eapol_rx = NULL;
@@ -5647,7 +5648,8 @@
 	case EVENT_EAPOL_RX:
 		wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
 					data->eapol_rx.data,
-					data->eapol_rx.data_len);
+					data->eapol_rx.data_len,
+					data->eapol_rx.encrypted);
 		break;
 	case EVENT_SIGNAL_CHANGE:
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index a6172d6..802f120 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -30,6 +30,8 @@
 #define GAS_QUERY_WAIT_TIME_INITIAL 1000
 #define GAS_QUERY_WAIT_TIME_COMEBACK 150
 
+#define GAS_QUERY_MAX_COMEBACK_DELAY 60000
+
 /**
  * struct gas_query_pending - Pending GAS query
  */
@@ -589,6 +591,8 @@
 	if (pos + 2 > data + len)
 		return 0;
 	comeback_delay = WPA_GET_LE16(pos);
+	if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY)
+		comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY;
 	pos += 2;
 
 	/* Advertisement Protocol element */
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 02e6390..874c2bf 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -772,7 +772,8 @@
 
 static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
 				     struct ibss_rsn_peer *peer,
-				     const u8 *buf, size_t len)
+				     const u8 *buf, size_t len,
+				     enum frame_encryption encrypted)
 {
 	int supp;
 	u8 *tmp;
@@ -788,7 +789,7 @@
 		peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
 		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
 			   MACSTR, MAC2STR(peer->addr));
-		wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
+		wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len, encrypted);
 	} else {
 		if (ibss_rsn_is_auth_started(peer) == 0) {
 			wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for "
@@ -809,7 +810,8 @@
 
 
 int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
-		      const u8 *buf, size_t len)
+		      const u8 *buf, size_t len,
+		      enum frame_encryption encrypted)
 {
 	struct ibss_rsn_peer *peer;
 
@@ -818,7 +820,8 @@
 
 	peer = ibss_rsn_get_peer(ibss_rsn, src_addr);
 	if (peer)
-		return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len);
+		return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len,
+						 encrypted);
 
 	if (ibss_rsn_eapol_dst_supp(buf, len) > 0) {
 		/*
@@ -836,7 +839,7 @@
 					    IBSS_RSN_AUTH_EAPOL_BY_US);
 
 		return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
-						 buf, len);
+						 buf, len, encrypted);
 	}
 
 	return 0;
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 626c543..cff45a7 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -57,7 +57,8 @@
 int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
 void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
 int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
-		      const u8 *buf, size_t len);
+		      const u8 *buf, size_t len,
+		      enum frame_encryption encrypted);
 void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
 void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
 			  size_t len);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 9a459c2..6198bd7 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1065,9 +1065,15 @@
 			goto fail;
 	}
 
-	if (cred->imsi_privacy_key && cred->imsi_privacy_key[0]) {
-		if (wpa_config_set_quoted(ssid, "imsi_privacy_key",
-					  cred->imsi_privacy_key) < 0)
+	if (cred->imsi_privacy_cert && cred->imsi_privacy_cert[0]) {
+		if (wpa_config_set_quoted(ssid, "imsi_privacy_cert",
+					  cred->imsi_privacy_cert) < 0)
+			goto fail;
+	}
+
+	if (cred->imsi_privacy_attr && cred->imsi_privacy_attr[0]) {
+		if (wpa_config_set_quoted(ssid, "imsi_privacy_attr",
+					  cred->imsi_privacy_attr) < 0)
 			goto fail;
 	}
 
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index b67396d..16530fb 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -643,18 +643,20 @@
 		switch (params->freq.bandwidth) {
 		case 80:
 			if (params->freq.center_freq2) {
-				ssid->max_oper_chwidth = CHANWIDTH_80P80MHZ;
+				ssid->max_oper_chwidth =
+					CONF_OPER_CHWIDTH_80P80MHZ;
 				ssid->vht_center_freq2 =
 					params->freq.center_freq2;
 			} else {
-				ssid->max_oper_chwidth = CHANWIDTH_80MHZ;
+				ssid->max_oper_chwidth =
+					CONF_OPER_CHWIDTH_80MHZ;
 			}
 			break;
 		case 160:
-			ssid->max_oper_chwidth = CHANWIDTH_160MHZ;
+			ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
 			break;
 		default:
-			ssid->max_oper_chwidth = CHANWIDTH_USE_HT;
+			ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT;
 			break;
 		}
 	}
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index bd53c5c..5dca8f7 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -470,8 +470,9 @@
 	 * or used.
 	 */
 	if (wpas_sta_secondary_channel_offset(bss, &current, &chan) < 0 &&
-	    ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT,
-					  &current, &chan) == NUM_HOSTAPD_MODES)
+	    ieee80211_freq_to_channel_ext(bss->freq, 0,
+					  CONF_OPER_CHWIDTH_USE_HT, &current,
+					  &chan) == NUM_HOSTAPD_MODES)
 		return 0;
 
 	/*
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index c8f2e5c..ccbb1b7 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -129,7 +129,7 @@
 			       const u8 *ssid, size_t ssid_len);
 static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
 				int *force_freq, int *pref_freq, int go,
-				unsigned int *pref_freq_list,
+				struct weighted_pcl *pref_freq_list,
 				unsigned int *num_pref_freq);
 static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
 				   const u8 *ssid, size_t ssid_len);
@@ -705,7 +705,8 @@
 	struct wpa_supplicant *go_wpa_s, *cli_wpa_s;
 	struct wpa_ssid *persistent_go;
 	int p2p_no_group_iface;
-	unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+	struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+	unsigned int size;
 
 	wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
 
@@ -4732,7 +4733,7 @@
 
 static int wpas_p2p_get_pref_freq_list(void *ctx, int go,
 				       unsigned int *len,
-				       unsigned int *freq_list)
+				       struct weighted_pcl *freq_list)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
@@ -5708,7 +5709,7 @@
 
 static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
 				int *force_freq, int *pref_freq, int go,
-				unsigned int *pref_freq_list,
+				struct weighted_pcl *pref_freq_list,
 				unsigned int *num_pref_freq)
 {
 	struct wpa_used_freq_data *freqs;
@@ -5822,16 +5823,19 @@
 				i = 0;
 				while (i < *num_pref_freq &&
 					(!p2p_supported_freq(wpa_s->global->p2p,
-						pref_freq_list[i]) ||
-					wpas_p2p_disallowed_freq(wpa_s->global,
-							pref_freq_list[i]))) {
+						pref_freq_list[i].freq) ||
+					wpas_p2p_disallowed_freq(
+						wpa_s->global,
+						pref_freq_list[i].freq) ||
+					!p2p_pref_freq_allowed(&pref_freq_list[i],
+						go))) {
 					wpa_printf(MSG_DEBUG,
 						"P2P: preferred_freq_list[%d]=%d is disallowed",
-						i, pref_freq_list[i]);
+						i, pref_freq_list[i].freq);
 					i++;
 				}
 				if (i != *num_pref_freq) {
-					best_freq = pref_freq_list[i];
+					best_freq = pref_freq_list[i].freq;
 					wpa_printf(MSG_DEBUG,
 						"P2P: Using preferred_freq_list[%d]=%d",
 						i, best_freq);
@@ -5955,7 +5959,8 @@
 	enum wpa_driver_if_type iftype;
 	const u8 *if_addr;
 	struct wpa_ssid *ssid = NULL;
-	unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+	struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+	unsigned int size;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
@@ -6240,7 +6245,7 @@
 
 	if (!wpa_s->conf->num_p2p_pref_chan && !freq) {
 		unsigned int i, size = P2P_MAX_PREF_CHANNELS;
-		unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
+		struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
 		int res;
 
 		res = wpa_drv_get_pref_freq_list(wpa_s, WPA_IF_P2P_GO,
@@ -6252,16 +6257,19 @@
 			i = 0;
 			while (i < size &&
 			       (!p2p_supported_freq(wpa_s->global->p2p,
-						    pref_freq_list[i]) ||
-				wpas_p2p_disallowed_freq(wpa_s->global,
-							 pref_freq_list[i]))) {
+						    pref_freq_list[i].freq) ||
+				wpas_p2p_disallowed_freq(
+					wpa_s->global,
+					pref_freq_list[i].freq) ||
+				!p2p_pref_freq_allowed(&pref_freq_list[i],
+						       true))) {
 				wpa_printf(MSG_DEBUG,
 					   "P2P: preferred_freq_list[%d]=%d is disallowed",
-					   i, pref_freq_list[i]);
+					   i, pref_freq_list[i].freq);
 				i++;
 			}
 			if (i != size) {
-				freq = pref_freq_list[i];
+				freq = pref_freq_list[i].freq;
 				wpa_printf(MSG_DEBUG,
 					   "P2P: Using preferred_freq_list[%d]=%d",
 					   i, freq);
@@ -6740,8 +6748,8 @@
 
 			if (!is_6ghz &&
 			    ieee80211_freq_to_channel_ext(
-				    cand, -1, CHANWIDTH_USE_HT, &op_class,
-				    &chan) != NUM_HOSTAPD_MODES &&
+				    cand, -1, CONF_OPER_CHWIDTH_USE_HT,
+				    &op_class, &chan) != NUM_HOSTAPD_MODES &&
 			    wpas_p2p_verify_channel(
 				    wpa_s, hwmode, op_class, chan,
 				    BW40MINUS) == ALLOWED)
@@ -6749,8 +6757,8 @@
 
 			if (!supported && !is_6ghz &&
 			    ieee80211_freq_to_channel_ext(
-				    cand, 1, CHANWIDTH_USE_HT, &op_class,
-				    &chan) != NUM_HOSTAPD_MODES &&
+				    cand, 1, CONF_OPER_CHWIDTH_USE_HT,
+				    &op_class, &chan) != NUM_HOSTAPD_MODES &&
 			    wpas_p2p_verify_channel(
 				    wpa_s, hwmode, op_class, chan,
 				    BW40PLUS) == ALLOWED)
@@ -7636,7 +7644,8 @@
 	int force_freq = 0;
 	int res;
 	int no_pref_freq_given = pref_freq == 0;
-	unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+	struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+	unsigned int size;
 
 	if (wpas_p2p_check_6ghz(wpa_s, NULL, allow_6ghz, freq))
 		return -1;
@@ -7725,7 +7734,8 @@
 	int persistent;
 	int freq = 0, force_freq = 0, pref_freq = 0;
 	int res;
-	unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+	struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+	unsigned int size;
 
 	wpa_s->p2p_persistent_go_freq = 0;
 	wpa_s->p2p_go_ht40 = 0;
@@ -9781,13 +9791,15 @@
 		csa_settings.freq_params.center_freq2 = freq2;
 
 		switch (conf->vht_oper_chwidth) {
-		case CHANWIDTH_80MHZ:
-		case CHANWIDTH_80P80MHZ:
+		case CONF_OPER_CHWIDTH_80MHZ:
+		case CONF_OPER_CHWIDTH_80P80MHZ:
 			csa_settings.freq_params.bandwidth = 80;
 			break;
-		case CHANWIDTH_160MHZ:
+		case CONF_OPER_CHWIDTH_160MHZ:
 			csa_settings.freq_params.bandwidth = 160;
 			break;
+		default:
+			break;
 		}
 	}
 
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
index 6110797..f269fb6 100644
--- a/wpa_supplicant/robust_av.c
+++ b/wpa_supplicant/robust_av.c
@@ -1294,11 +1294,17 @@
 		attr = qos_ie + 6;
 		rem_attrs_len = qos_ie[1] - 4;
 
-		while (rem_attrs_len > 2 && rem_attrs_len >= 2 + attr[1]) {
-			wpas_fill_dscp_policy(&policy, attr[0], attr[1],
-					      &attr[2]);
-			rem_attrs_len -= 2 + attr[1];
-			attr += 2 + attr[1];
+		while (rem_attrs_len > 2) {
+			u8 attr_id, attr_len;
+
+			attr_id = *attr++;
+			attr_len = *attr++;
+			rem_attrs_len -= 2;
+			if (attr_len > rem_attrs_len)
+				break;
+			wpas_fill_dscp_policy(&policy, attr_id, attr_len, attr);
+			rem_attrs_len -= attr_len;
+			attr += attr_len;
 		}
 
 		rem_len -= ie_len;
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 4457b6c..238fe68 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -731,24 +731,24 @@
 		vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
 
 		switch (vht_oper->vht_op_info_chwidth) {
-		case 1:
+		case CHANWIDTH_80MHZ:
 			seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx;
 			seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx;
 			if (seg1 && abs(seg1 - seg0) == 8)
-				vht = CHANWIDTH_160MHZ;
+				vht = CONF_OPER_CHWIDTH_160MHZ;
 			else if (seg1)
-				vht = CHANWIDTH_80P80MHZ;
+				vht = CONF_OPER_CHWIDTH_80P80MHZ;
 			else
-				vht = CHANWIDTH_80MHZ;
+				vht = CONF_OPER_CHWIDTH_80MHZ;
 			break;
-		case 2:
-			vht = CHANWIDTH_160MHZ;
+		case CHANWIDTH_160MHZ:
+			vht = CONF_OPER_CHWIDTH_160MHZ;
 			break;
-		case 3:
-			vht = CHANWIDTH_80P80MHZ;
+		case CHANWIDTH_80P80MHZ:
+			vht = CONF_OPER_CHWIDTH_80P80MHZ;
 			break;
 		default:
-			vht = CHANWIDTH_USE_HT;
+			vht = CONF_OPER_CHWIDTH_USE_HT;
 			break;
 		}
 	}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 042b24e..4be0718 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1341,6 +1341,12 @@
 		}
 	}
 
+	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+	    wpa_s->manual_non_coloc_6ghz) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Collocated 6 GHz logic is disabled");
+		params.non_coloc_6ghz = 1;
+	}
+
 	scan_params = &params;
 
 scan:
@@ -2928,6 +2934,7 @@
 	params->relative_adjust_band = src->relative_adjust_band;
 	params->relative_adjust_rssi = src->relative_adjust_rssi;
 	params->p2p_include_6ghz = src->p2p_include_6ghz;
+	params->non_coloc_6ghz = src->non_coloc_6ghz;
 	return params;
 
 failed:
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index cc55fa6..80cb6bb 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1297,21 +1297,24 @@
 		token_len = len - sizeof(le16);
 		h2e = wpa_s->sme.sae.h2e;
 		if (h2e) {
+			u8 id, elen, extid;
+
 			if (token_len < 3) {
 				wpa_dbg(wpa_s, MSG_DEBUG,
 					"SME: Too short SAE anti-clogging token container");
 				return -1;
 			}
-			if (token_pos[0] != WLAN_EID_EXTENSION ||
-			    token_pos[1] == 0 ||
-			    token_pos[1] > token_len - 2 ||
-			    token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
+			id = *token_pos++;
+			elen = *token_pos++;
+			extid = *token_pos++;
+			if (id != WLAN_EID_EXTENSION ||
+			    elen == 0 || elen > token_len - 2 ||
+			    extid != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
 				wpa_dbg(wpa_s, MSG_DEBUG,
 					"SME: Invalid SAE anti-clogging token container header");
 				return -1;
 			}
-			token_len = token_pos[1] - 1;
-			token_pos += 3;
+			token_len = elen - 1;
 		}
 		wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
 		wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 4c7e6dc..5393f1c 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -921,7 +921,8 @@
 {
 	const u8 *ie;
 	u8 op_class, chan;
-	int sec_chan = 0, vht = 0;
+	int sec_chan = 0;
+	enum oper_chan_width vht = CONF_OPER_CHWIDTH_USE_HT;
 	enum phy_type phy_type;
 	u32 info;
 	struct ieee80211_ht_operation *ht_oper = NULL;
@@ -1457,15 +1458,22 @@
 
 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
 		char url[256];
+		u8 url_len;
 
-		if (end - pos < 1 || 1 + pos[0] > end - pos) {
+		if (end - pos < 1) {
 			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
 				   "Management Request (URL)");
 			return;
 		}
-		os_memcpy(url, pos + 1, pos[0]);
-		url[pos[0]] = '\0';
-		pos += 1 + pos[0];
+		url_len = *pos++;
+		if (url_len > end - pos) {
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Invalid BSS Transition Management Request (URL truncated)");
+			return;
+		}
+		os_memcpy(url, pos, url_len);
+		url[url_len] = '\0';
+		pos += url_len;
 
 		wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
 			wpa_sm_pmf_enabled(wpa_s->wpa),
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index c5d7168..ff1fb67 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -1134,7 +1134,8 @@
 
 
 void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
-			     const u8 *buf, size_t len)
+			     const u8 *buf, size_t len,
+			     enum frame_encryption encrypted)
 {
 	struct wpa_priv_interface *iface = ctx;
 	struct msghdr msg;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 24c8818..8ee8ca6 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -17,6 +17,7 @@
 #endif /* CONFIG_MATCH_IFACE */
 
 #include "common.h"
+#include "crypto/crypto.h"
 #include "crypto/random.h"
 #include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
@@ -2708,7 +2709,7 @@
 	if (!ibss_mesh_is_80mhz_avail(channel, mode))
 		return;
 
-	chwidth = CHANWIDTH_80MHZ;
+	chwidth = CONF_OPER_CHWIDTH_80MHZ;
 	seg0 = channel + 6;
 	seg1 = 0;
 
@@ -2724,14 +2725,14 @@
 
 		for (j = 0; j < ARRAY_SIZE(bw160); j++) {
 			if (freq->freq == bw160[j]) {
-				chwidth = CHANWIDTH_160MHZ;
+				chwidth = CONF_OPER_CHWIDTH_160MHZ;
 				seg0 = channel + 14;
 				break;
 			}
 		}
 	}
 
-	if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
+	if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
 		/* setup center_freq2, bandwidth */
 		for (k = 0; k < ARRAY_SIZE(bw80); k++) {
 			/* Only accept 80 MHz segments separated by a gap */
@@ -2755,28 +2756,28 @@
 					continue;
 
 				/* Found a suitable second segment for 80+80 */
-				chwidth = CHANWIDTH_80P80MHZ;
+				chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
 				if (!is_6ghz)
 					vht_caps |=
 						VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
 				seg1 = channel + 6;
 			}
 
-			if (chwidth == CHANWIDTH_80P80MHZ)
+			if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
 				break;
 		}
-	} else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) {
+	} else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
 		if (freq->freq == 5180) {
-			chwidth = CHANWIDTH_160MHZ;
+			chwidth = CONF_OPER_CHWIDTH_160MHZ;
 			vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
 			seg0 = 50;
 		} else if (freq->freq == 5520) {
-			chwidth = CHANWIDTH_160MHZ;
+			chwidth = CONF_OPER_CHWIDTH_160MHZ;
 			vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
 			seg0 = 114;
 		}
-	} else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
-		chwidth = CHANWIDTH_USE_HT;
+	} else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_USE_HT) {
+		chwidth = CONF_OPER_CHWIDTH_USE_HT;
 		seg0 = channel + 2;
 #ifdef CONFIG_HT_OVERRIDES
 		if (ssid->disable_ht40)
@@ -3797,6 +3798,11 @@
 		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
 	}
 
+	/* Set current_ssid before changing state to ASSOCIATING, so that the
+	 * selected SSID is available to wpas_notify_state_changed(). */
+	old_ssid = wpa_s->current_ssid;
+	wpa_s->current_ssid = ssid;
+
 	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
 	if (bss) {
 		params.ssid = bss->ssid;
@@ -4042,7 +4048,7 @@
 #endif /* CONFIG_P2P */
 
 	if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
-	    wpa_s->current_ssid)
+	    old_ssid)
 		params.prev_bssid = prev_bssid;
 
 #ifdef CONFIG_SAE
@@ -4112,15 +4118,13 @@
 	}
 #endif /* CONFIG_WEP */
 
-	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
+	if (old_ssid && old_ssid != ssid) {
 		/*
 		 * Do not allow EAP session resumption between different
 		 * network configurations.
 		 */
 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
 	}
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = ssid;
 
 	if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
 		wpa_s->current_bss = bss;
@@ -5031,6 +5035,7 @@
  * @src_addr: Source address of the EAPOL frame
  * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
  * @len: Length of the EAPOL data
+ * @encrypted: Whether the frame was encrypted
  *
  * This function is called for each received EAPOL frame. Most driver
  * interfaces rely on more generic OS mechanism for receiving frames through
@@ -5039,11 +5044,13 @@
  * code by calling this function.
  */
 void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
-			     const u8 *buf, size_t len)
+			     const u8 *buf, size_t len,
+			     enum frame_encryption encrypted)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " (encrypted=%d)",
+		MAC2STR(src_addr), encrypted);
 	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
 
 	if (wpa_s->own_disconnect_req) {
@@ -5089,6 +5096,7 @@
 			os_get_reltime(&wpa_s->pending_eapol_rx_time);
 			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
 				  ETH_ALEN);
+			wpa_s->pending_eapol_encrypted = encrypted;
 		}
 		return;
 	}
@@ -5098,7 +5106,8 @@
 
 #ifdef CONFIG_AP
 	if (wpa_s->ap_iface) {
-		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
+		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len,
+					   encrypted);
 		return;
 	}
 #endif /* CONFIG_AP */
@@ -5158,7 +5167,8 @@
 #ifdef CONFIG_IBSS_RSN
 	if (wpa_s->current_ssid &&
 	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
-		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
+		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len,
+				  encrypted);
 		return;
 	}
 #endif /* CONFIG_IBSS_RSN */
@@ -5173,11 +5183,12 @@
 	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
 	    wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
 	    wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
-	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
+	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len,
+			      encrypted) > 0)
 		return;
 	wpa_drv_poll(wpa_s);
 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
-		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len, encrypted);
 	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
 		/*
 		 * Set portValid = true here since we are going to skip 4-way
@@ -5190,6 +5201,14 @@
 }
 
 
+static void wpa_supplicant_rx_eapol_cb(void *ctx, const u8 *src_addr,
+				       const u8 *buf, size_t len)
+{
+	wpa_supplicant_rx_eapol(ctx, src_addr, buf, len,
+				FRAME_ENCRYPTION_UNKNOWN);
+}
+
+
 static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
 {
 	return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
@@ -5207,7 +5226,7 @@
 					   wpa_drv_get_mac_addr(wpa_s),
 					   ETH_P_EAPOL,
 					   wpas_eapol_needs_l2_packet(wpa_s) ?
-					   wpa_supplicant_rx_eapol : NULL,
+					   wpa_supplicant_rx_eapol_cb : NULL,
 					   wpa_s, 0);
 		if (wpa_s->l2 == NULL)
 			return -1;
@@ -5261,7 +5280,7 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
 		" (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
 	wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
-				len - sizeof(*eth));
+				len - sizeof(*eth), FRAME_ENCRYPTION_UNKNOWN);
 }
 
 
@@ -5987,6 +6006,7 @@
 void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
 				       struct fst_wpa_obj *iface_obj)
 {
+	os_memset(iface_obj, 0, sizeof(*iface_obj));
 	iface_obj->ctx              = wpa_s;
 	iface_obj->get_bssid        = wpas_fst_get_bssid_cb;
 	iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
@@ -8063,6 +8083,24 @@
 	    !ssid->mem_only_psk)
 		return 1;
 
+#ifdef CRYPTO_RSA_OAEP_SHA256
+	if (ssid->eap.imsi_privacy_cert) {
+		struct crypto_rsa_key *key;
+		bool failed = false;
+
+		key = crypto_rsa_key_read(ssid->eap.imsi_privacy_cert, false);
+		if (!key)
+			failed = true;
+		crypto_rsa_key_free(key);
+		if (failed) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid imsi_privacy_cert (%s) - disable network",
+				   ssid->eap.imsi_privacy_cert);
+			return 1;
+		}
+	}
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
 	return 0;
 }
 
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3adb819..9daf908 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -902,6 +902,7 @@
 	unsigned int own_scan_requested:1;
 	unsigned int own_scan_running:1;
 	unsigned int clear_driver_scan_cache:1;
+	unsigned int manual_non_coloc_6ghz:1;
 	unsigned int manual_scan_id;
 	int scan_interval; /* time in sec between scans to find suitable AP */
 	int normal_scans; /* normal scans run before sched_scan */
@@ -966,6 +967,7 @@
 	struct wpabuf *pending_eapol_rx;
 	struct os_reltime pending_eapol_rx_time;
 	u8 pending_eapol_rx_src[ETH_ALEN];
+	enum frame_encryption pending_eapol_encrypted;
 	unsigned int last_eapol_matches_bssid:1;
 	unsigned int eapol_failed:1;
 	unsigned int eap_expected_failure:1;
@@ -1522,6 +1524,7 @@
 	char *dpp_discovery_override;
 	char *dpp_groups_override;
 	unsigned int dpp_ignore_netaccesskey_mismatch:1;
+	unsigned int dpp_discard_public_action:1;
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_DPP */
 
@@ -1653,7 +1656,8 @@
 			      struct wpa_ssid *ssid);
 void wpa_supplicant_terminate_proc(struct wpa_global *global);
 void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
-			     const u8 *buf, size_t len);
+			     const u8 *buf, size_t len,
+			     enum frame_encryption encrypted);
 void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
 void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -1890,7 +1894,7 @@
 int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
 						enum wpa_driver_if_type if_type,
 						unsigned int *num,
-						unsigned int *freq_list);
+						struct weighted_pcl *freq_list);
 
 int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
 int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index c2bd45f..8a0fe8d 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1183,6 +1183,16 @@
 
 	wpas_notify_open_ssl_failure(wpa_s, reason_string);
 }
+
+static bool wpas_encryption_required(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	return wpa_s->wpa &&
+		wpa_sm_has_ptk_installed(wpa_s->wpa) &&
+		wpa_sm_pmf_enabled(wpa_s->wpa);
+}
+
 #endif /* IEEE8021X_EAPOL */
 
 
@@ -1231,6 +1241,7 @@
 	ctx->set_anon_id = wpa_supplicant_set_anon_id;
 	ctx->eap_method_selected_cb = wpa_supplicant_eap_method_selected_cb;
 	ctx->open_ssl_failure_cb = wpa_supplicant_open_ssl_failure_cb;
+	ctx->encryption_required = wpas_encryption_required;
 	ctx->cb_ctx = wpa_s;
 	wpa_s->eapol = eapol_sm_init(ctx);
 	if (wpa_s->eapol == NULL) {