Merge "[wpa_supplicant] Cumulative patch from commit e4eb009d9" into rvc-dev
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index eb01da5..dff5704 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -156,6 +156,7 @@
 OBJS += src/utils/wpabuf.c
 OBJS += src/utils/os_$(CONFIG_OS).c
 OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
 
 OBJS += src/common/ieee802_11_common.c
 OBJS += src/common/wpa_common.c
@@ -295,10 +296,6 @@
 OBJS += src/ap/wnm_ap.c
 endif
 
-ifdef CONFIG_IEEE80211N
-L_CFLAGS += -DCONFIG_IEEE80211N
-endif
-
 ifdef CONFIG_IEEE80211AC
 L_CFLAGS += -DCONFIG_IEEE80211AC
 endif
@@ -327,6 +324,10 @@
 endif
 endif
 
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
 
 include $(LOCAL_PATH)/src/drivers/drivers.mk
 
@@ -558,6 +559,7 @@
 NEED_JSON=y
 NEED_GAS=y
 NEED_BASE64=y
+NEED_ASN1=y
 ifdef CONFIG_DPP2
 L_CFLAGS += -DCONFIG_DPP2
 endif
@@ -695,12 +697,12 @@
 OBJS += src/tls/tlsv1_server.c
 OBJS += src/tls/tlsv1_server_write.c
 OBJS += src/tls/tlsv1_server_read.c
-OBJS += src/tls/asn1.c
 OBJS += src/tls/rsa.c
 OBJS += src/tls/x509v3.c
 OBJS += src/tls/pkcs1.c
 OBJS += src/tls/pkcs5.c
 OBJS += src/tls/pkcs8.c
+NEED_ASN1=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
 ifdef CONFIG_TLSV12
@@ -950,6 +952,10 @@
 OBJS += src/crypto/sha512-internal.c
 endif
 
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
 ifdef NEED_DH_GROUPS
 OBJS += src/crypto/dh_groups.c
 endif
@@ -1008,9 +1014,7 @@
 OBJS += src/ap/dfs.c
 L_CFLAGS += -DNEED_AP_MLME
 endif
-ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
-endif
 
 ifdef CONFIG_IEEE80211AC
 OBJS += src/ap/ieee802_11_vht.c
diff --git a/hostapd/Makefile b/hostapd/Makefile
index f01f581..4adf996 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -158,6 +158,7 @@
 OBJS += ../src/utils/wpabuf.o
 OBJS += ../src/utils/os_$(CONFIG_OS).o
 OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
 
 OBJS += ../src/common/ieee802_11_common.o
 OBJS += ../src/common/wpa_common.o
@@ -334,10 +335,6 @@
 OBJS += ../src/ap/wnm_ap.o
 endif
 
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
-endif
-
 ifdef CONFIG_IEEE80211AC
 CFLAGS += -DCONFIG_IEEE80211AC
 endif
@@ -586,6 +583,7 @@
 NEED_JSON=y
 NEED_GAS=y
 NEED_BASE64=y
+NEED_ASN1=y
 ifdef CONFIG_DPP2
 CFLAGS += -DCONFIG_DPP2
 endif
@@ -759,12 +757,12 @@
 OBJS += ../src/tls/tlsv1_server.o
 OBJS += ../src/tls/tlsv1_server_write.o
 OBJS += ../src/tls/tlsv1_server_read.o
-OBJS += ../src/tls/asn1.o
 OBJS += ../src/tls/rsa.o
 OBJS += ../src/tls/x509v3.o
 OBJS += ../src/tls/pkcs1.o
 OBJS += ../src/tls/pkcs5.o
 OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
 ifdef CONFIG_TLSV12
@@ -835,12 +833,12 @@
 OBJS += ../src/tls/tlsv1_server.o
 OBJS += ../src/tls/tlsv1_server_write.o
 OBJS += ../src/tls/tlsv1_server_read.o
-OBJS += ../src/tls/asn1.o
 OBJS += ../src/tls/rsa.o
 OBJS += ../src/tls/x509v3.o
 OBJS += ../src/tls/pkcs1.o
 OBJS += ../src/tls/pkcs5.o
 OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
 ifdef CONFIG_TLSV12
@@ -1088,6 +1086,10 @@
 OBJS += ../src/crypto/sha512-internal.o
 endif
 
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
 ifdef NEED_DH_GROUPS
 OBJS += ../src/crypto/dh_groups.o
 endif
@@ -1153,9 +1155,7 @@
 OBJS += ../src/ap/dfs.o
 CFLAGS += -DNEED_AP_MLME
 endif
-ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
-endif
 
 ifdef CONFIG_IEEE80211AC
 OBJS += ../src/ap/ieee802_11_vht.o
@@ -1242,6 +1242,10 @@
 endif
 endif
 
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
 ALL=hostapd hostapd_cli
 
 all: verify_config $(ALL)
diff --git a/hostapd/android.config b/hostapd/android.config
index 68fec32..c53875c 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -125,12 +125,6 @@
 # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
 #CONFIG_DRIVER_RADIUS_ACL=y
 
-# IEEE 802.11n (High Throughput) support
-CONFIG_IEEE80211N=y
-
-# IEEE 802.11ac (Very High Throughput) support
-CONFIG_IEEE80211AC=y
-
 # Remove debugging code that is printing out debug messages to stdout.
 # This can be used to reduce the size of the hostapd considerably if debugging
 # code is not needed.
@@ -225,3 +219,12 @@
 
 # WPA3-Personal (SAE)
 CONFIG_SAE=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
+
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 21c9ab2..1d8c039 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -793,6 +793,7 @@
 }
 
 
+#ifdef CONFIG_WEP
 static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
 				   char *val)
 {
@@ -843,6 +844,7 @@
 
 	return 0;
 }
+#endif /* CONFIG_WEP */
 
 
 static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
@@ -1151,7 +1153,6 @@
 #endif /* CONFIG_IEEE80211R_AP */
 
 
-#ifdef CONFIG_IEEE80211N
 static int hostapd_config_ht_capab(struct hostapd_config *conf,
 				   const char *capab)
 {
@@ -1171,14 +1172,6 @@
 	}
 	if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
 		conf->secondary_channel = 0;
-	if (os_strstr(capab, "[SMPS-STATIC]")) {
-		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
-		conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
-	}
-	if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
-		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
-		conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
-	}
 	if (os_strstr(capab, "[GF]"))
 		conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
 	if (os_strstr(capab, "[SHORT-GI-20]"))
@@ -1212,7 +1205,6 @@
 
 	return 0;
 }
-#endif /* CONFIG_IEEE80211N */
 
 
 #ifdef CONFIG_IEEE80211AC
@@ -2471,6 +2463,13 @@
 	} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
 		bss->skip_inactivity_poll = atoi(pos);
 	} else if (os_strcmp(buf, "country_code") == 0) {
+		if (pos[0] < 'A' || pos[0] > 'Z' ||
+		    pos[1] < 'A' || pos[1] > 'Z') {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid country_code '%s'",
+				   line, pos);
+			return 1;
+		}
 		os_memcpy(conf->country, pos, 2);
 	} else if (os_strcmp(buf, "country3") == 0) {
 		conf->country[2] = strtol(pos, NULL, 16);
@@ -2674,6 +2673,7 @@
 	} else if (os_strcmp(buf, "erp_domain") == 0) {
 		os_free(bss->erp_domain);
 		bss->erp_domain = os_strdup(pos);
+#ifdef CONFIG_WEP
 	} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
 		int val = atoi(pos);
 
@@ -2701,6 +2701,7 @@
 				   line, bss->wep_rekeying_period);
 			return 1;
 		}
+#endif /* CONFIG_WEP */
 	} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
 		bss->eap_reauth_period = atoi(pos);
 		if (bss->eap_reauth_period < 0) {
@@ -2875,6 +2876,16 @@
 		}
 	} else if (os_strcmp(buf, "wpa") == 0) {
 		bss->wpa = atoi(pos);
+	} else if (os_strcmp(buf, "extended_key_id") == 0) {
+		int val = atoi(pos);
+
+		if (val < 0 || val > 2) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid extended_key_id=%d; allowed range 0..2",
+				   line, val);
+			return 1;
+		}
+		bss->extended_key_id = val;
 	} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
 		bss->wpa_group_rekey = atoi(pos);
 		bss->wpa_group_rekey_set = 1;
@@ -2884,6 +2895,15 @@
 		bss->wpa_gmk_rekey = atoi(pos);
 	} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
 		bss->wpa_ptk_rekey = atoi(pos);
+	} else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) {
+		bss->wpa_deny_ptk0_rekey = atoi(pos);
+		if (bss->wpa_deny_ptk0_rekey < 0 ||
+		    bss->wpa_deny_ptk0_rekey > 2) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2",
+				   line, bss->wpa_deny_ptk0_rekey);
+			return 1;
+		}
 	} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
 		char *endp;
 		unsigned long val = strtoul(pos, &endp, 0);
@@ -3312,6 +3332,7 @@
 		bss->ignore_broadcast_ssid = atoi(pos);
 	} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
 		bss->no_probe_resp_if_max_sta = atoi(pos);
+#ifdef CONFIG_WEP
 	} else if (os_strcmp(buf, "wep_default_key") == 0) {
 		bss->ssid.wep.idx = atoi(pos);
 		if (bss->ssid.wep.idx > 3) {
@@ -3330,6 +3351,7 @@
 				   line, buf);
 			return 1;
 		}
+#endif /* CONFIG_WEP */
 #ifndef CONFIG_NO_VLAN
 	} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
 		bss->ssid.dynamic_vlan = atoi(pos);
@@ -3408,6 +3430,8 @@
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "beacon_prot") == 0) {
+		bss->beacon_prot = atoi(pos);
 	} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
 		bss->assoc_sa_query_max_timeout = atoi(pos);
 		if (bss->assoc_sa_query_max_timeout == 0) {
@@ -3428,7 +3452,6 @@
 		if (bss->ocv && !bss->ieee80211w)
 			bss->ieee80211w = 1;
 #endif /* CONFIG_OCV */
-#ifdef CONFIG_IEEE80211N
 	} else if (os_strcmp(buf, "ieee80211n") == 0) {
 		conf->ieee80211n = atoi(pos);
 	} else if (os_strcmp(buf, "ht_capab") == 0) {
@@ -3441,7 +3464,6 @@
 		conf->require_ht = atoi(pos);
 	} else if (os_strcmp(buf, "obss_interval") == 0) {
 		conf->obss_interval = atoi(pos);
-#endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_IEEE80211AC
 	} else if (os_strcmp(buf, "ieee80211ac") == 0) {
 		conf->ieee80211ac = atoi(pos);
@@ -3474,7 +3496,10 @@
 	} else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
 		conf->he_phy_capab.he_mu_beamformer = atoi(pos);
 	} else if (os_strcmp(buf, "he_bss_color") == 0) {
-		conf->he_op.he_bss_color = atoi(pos);
+		conf->he_op.he_bss_color = atoi(pos) & 0x3f;
+		conf->he_op.he_bss_color_disabled = 0;
+	} else if (os_strcmp(buf, "he_bss_color_partial") == 0) {
+		conf->he_op.he_bss_color_partial = atoi(pos);
 	} else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
 		conf->he_op.he_default_pe_duration = atoi(pos);
 	} else if (os_strcmp(buf, "he_twt_required") == 0) {
@@ -3762,6 +3787,9 @@
 	} else if (os_strcmp(buf, "server_id") == 0) {
 		os_free(bss->server_id);
 		bss->server_id = os_strdup(pos);
+	} else if (os_strcmp(buf, "wps_application_ext") == 0) {
+		wpabuf_free(bss->wps_application_ext);
+		bss->wps_application_ext = wpabuf_parse_bin(pos);
 #ifdef CONFIG_WPS_NFC
 	} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
 		bss->wps_nfc_dev_pw_id = atoi(pos);
@@ -4165,9 +4193,28 @@
 	} else if (os_strcmp(buf, "sae_commit_override") == 0) {
 		wpabuf_free(bss->sae_commit_override);
 		bss->sae_commit_override = wpabuf_parse_bin(pos);
+	} else if (os_strcmp(buf, "rsne_override_eapol") == 0) {
+		wpabuf_free(bss->rsne_override_eapol);
+		bss->rsne_override_eapol = wpabuf_parse_bin(pos);
 	} else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
 		wpabuf_free(bss->rsnxe_override_eapol);
 		bss->rsnxe_override_eapol = wpabuf_parse_bin(pos);
+	} else if (os_strcmp(buf, "rsne_override_ft") == 0) {
+		wpabuf_free(bss->rsne_override_ft);
+		bss->rsne_override_ft = wpabuf_parse_bin(pos);
+	} else if (os_strcmp(buf, "rsnxe_override_ft") == 0) {
+		wpabuf_free(bss->rsnxe_override_ft);
+		bss->rsnxe_override_ft = wpabuf_parse_bin(pos);
+	} else if (os_strcmp(buf, "gtk_rsc_override") == 0) {
+		wpabuf_free(bss->gtk_rsc_override);
+		bss->gtk_rsc_override = wpabuf_parse_bin(pos);
+	} else if (os_strcmp(buf, "igtk_rsc_override") == 0) {
+		wpabuf_free(bss->igtk_rsc_override);
+		bss->igtk_rsc_override = wpabuf_parse_bin(pos);
+	} else if (os_strcmp(buf, "no_beacon_rsnxe") == 0) {
+		bss->no_beacon_rsnxe = atoi(pos);
+	} else if (os_strcmp(buf, "skip_prune_assoc") == 0) {
+		bss->skip_prune_assoc = atoi(pos);
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_SAE
 	} else if (os_strcmp(buf, "sae_password") == 0) {
@@ -4370,6 +4417,18 @@
 	} else if (os_strcmp(buf, "dpp_controller") == 0) {
 		if (hostapd_dpp_controller_parse(bss, pos))
 			return 1;
+	} else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
+		bss->dpp_configurator_connectivity = atoi(pos);
+	} else if (os_strcmp(buf, "dpp_pfs") == 0) {
+		int val = atoi(pos);
+
+		if (val < 0 || val > 2) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid dpp_pfs value '%s'",
+				   line, pos);
+			return -1;
+		}
+		bss->dpp_pfs = val;
 #endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
 #ifdef CONFIG_OWE
@@ -4403,9 +4462,11 @@
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "owe_ptk_workaround") == 0) {
+		bss->owe_ptk_workaround = atoi(pos);
+#endif /* CONFIG_OWE */
 	} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
 		bss->coloc_intf_reporting = atoi(pos);
-#endif /* CONFIG_OWE */
 	} else if (os_strcmp(buf, "multi_ap") == 0) {
 		int val = atoi(pos);
 
@@ -4422,6 +4483,8 @@
 		conf->rssi_reject_assoc_timeout = atoi(pos);
 	} else if (os_strcmp(buf, "pbss") == 0) {
 		bss->pbss = atoi(pos);
+	} else if (os_strcmp(buf, "transition_disable") == 0) {
+		bss->transition_disable = strtol(pos, NULL, 16);
 #ifdef CONFIG_AIRTIME_POLICY
 	} else if (os_strcmp(buf, "airtime_mode") == 0) {
 		int val = atoi(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 9758881..d90b5dc 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -11,7 +11,11 @@
 #ifndef CONFIG_NATIVE_WINDOWS
 
 #ifdef CONFIG_TESTING_OPTIONS
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#else
 #include <net/ethernet.h>
+#endif
 #include <netinet/ip.h>
 #endif /* CONFIG_TESTING_OPTIONS */
 
@@ -55,6 +59,7 @@
 #include "ap/neighbor_db.h"
 #include "ap/rrm.h"
 #include "ap/dpp_hostapd.h"
+#include "ap/dfs.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
 #include "fst/fst_ctrl_iface.h"
@@ -65,9 +70,6 @@
 #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
 
 #ifdef CONFIG_CTRL_IFACE_UDP
-#define COOKIE_LEN 8
-static unsigned char cookie[COOKIE_LEN];
-static unsigned char gcookie[COOKIE_LEN];
 #define HOSTAPD_CTRL_IFACE_PORT		8877
 #define HOSTAPD_CTRL_IFACE_PORT_LIMIT	50
 #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT		8878
@@ -1286,6 +1288,22 @@
 		pos += ret;
 	}
 
+	if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
+		ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
+				  hapd->conf->wpa_deny_ptk0_rekey);
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+
+	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
+		ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
+				  hapd->conf->extended_key_id);
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+
 	return pos - buf;
 }
 
@@ -1658,7 +1676,7 @@
 		return -1;
 	}
 
-	res = hostapd_drv_send_mlme(hapd, buf, len, 0);
+	res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0);
 	os_free(buf);
 	return res;
 }
@@ -1857,7 +1875,7 @@
 {
 	struct hostapd_data *hapd = ctx;
 	const struct ether_header *eth;
-	struct iphdr ip;
+	struct ip ip;
 	const u8 *pos;
 	unsigned int i;
 	char extra[30];
@@ -1873,14 +1891,14 @@
 	os_memcpy(&ip, eth + 1, sizeof(ip));
 	pos = &buf[sizeof(*eth) + sizeof(ip)];
 
-	if (ip.ihl != 5 || ip.version != 4 ||
-	    ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+	if (ip.ip_hl != 5 || ip.ip_v != 4 ||
+	    ntohs(ip.ip_len) > HWSIM_IP_LEN) {
 		wpa_printf(MSG_DEBUG,
 			   "test data: RX - ignore unexpect IP header");
 		return;
 	}
 
-	for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+	for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
 		if (*pos != (u8) i) {
 			wpa_printf(MSG_DEBUG,
 				   "test data: RX - ignore mismatching payload");
@@ -1890,8 +1908,8 @@
 	}
 
 	extra[0] = '\0';
-	if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
-		os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+	if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+		os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
 	wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
 		MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
 }
@@ -1944,7 +1962,7 @@
 	u8 tos;
 	u8 buf[2 + HWSIM_PACKETLEN];
 	struct ether_header *eth;
-	struct iphdr *ip;
+	struct ip *ip;
 	u8 *dpos;
 	unsigned int i;
 	size_t send_len = HWSIM_IP_LEN;
@@ -1983,17 +2001,17 @@
 	os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
 	os_memcpy(eth->ether_shost, src, ETH_ALEN);
 	eth->ether_type = htons(ETHERTYPE_IP);
-	ip = (struct iphdr *) (eth + 1);
+	ip = (struct ip *) (eth + 1);
 	os_memset(ip, 0, sizeof(*ip));
-	ip->ihl = 5;
-	ip->version = 4;
-	ip->ttl = 64;
-	ip->tos = tos;
-	ip->tot_len = htons(send_len);
-	ip->protocol = 1;
-	ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
-	ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
-	ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+	ip->ip_hl = 5;
+	ip->ip_v = 4;
+	ip->ip_ttl = 64;
+	ip->ip_tos = tos;
+	ip->ip_len = htons(send_len);
+	ip->ip_p = 1;
+	ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+	ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+	ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
 	dpos = (u8 *) (ip + 1);
 	for (i = 0; i < send_len - sizeof(*ip); i++)
 		*dpos++ = i;
@@ -2150,17 +2168,19 @@
 		if (hostapd_drv_set_key(hapd->conf->iface, hapd,
 					hapd->last_igtk_alg,
 					broadcast_ether_addr,
-					hapd->last_igtk_key_idx, 1, NULL, 0,
-					zero, hapd->last_igtk_len) < 0)
+					hapd->last_igtk_key_idx, 0, 1, NULL, 0,
+					zero, hapd->last_igtk_len,
+					KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 			return -1;
 
 		/* Set the previously configured key to reset its TSC */
 		return hostapd_drv_set_key(hapd->conf->iface, hapd,
 					   hapd->last_igtk_alg,
 					   broadcast_ether_addr,
-					   hapd->last_igtk_key_idx, 1, NULL, 0,
-					   hapd->last_igtk,
-					   hapd->last_igtk_len);
+					   hapd->last_igtk_key_idx, 0, 1, NULL,
+					   0, hapd->last_igtk,
+					   hapd->last_igtk_len,
+					   KEY_FLAG_GROUP_TX_DEFAULT);
 	}
 
 	if (is_broadcast_ether_addr(addr)) {
@@ -2174,16 +2194,19 @@
 		if (hostapd_drv_set_key(hapd->conf->iface, hapd,
 					hapd->last_gtk_alg,
 					broadcast_ether_addr,
-					hapd->last_gtk_key_idx, 1, NULL, 0,
-					zero, hapd->last_gtk_len) < 0)
+					hapd->last_gtk_key_idx, 0, 1, NULL, 0,
+					zero, hapd->last_gtk_len,
+					KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 			return -1;
 
 		/* Set the previously configured key to reset its TSC */
 		return hostapd_drv_set_key(hapd->conf->iface, hapd,
 					   hapd->last_gtk_alg,
 					   broadcast_ether_addr,
-					   hapd->last_gtk_key_idx, 1, NULL, 0,
-					   hapd->last_gtk, hapd->last_gtk_len);
+					   hapd->last_gtk_key_idx, 0, 1, NULL,
+					   0, hapd->last_gtk,
+					   hapd->last_gtk_len,
+					   KEY_FLAG_GROUP_TX_DEFAULT);
 	}
 
 	sta = ap_get_sta(hapd, addr);
@@ -2199,14 +2222,16 @@
 	/* First, use a zero key to avoid any possible duplicate key avoidance
 	 * in the driver. */
 	if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
-				sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-				zero, sta->last_tk_len) < 0)
+				sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+				zero, sta->last_tk_len,
+				KEY_FLAG_PAIRWISE_RX_TX) < 0)
 		return -1;
 
 	/* Set the previously configured key to reset its TSC/RSC */
 	return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
-				   sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-				   sta->last_tk, sta->last_tk_len);
+				   sta->addr, sta->last_tk_key_idx, 0, 1, NULL,
+				   0, sta->last_tk, sta->last_tk_len,
+				   KEY_FLAG_PAIRWISE_RX_TX);
 }
 
 
@@ -2215,11 +2240,12 @@
 	u8 addr[ETH_ALEN];
 	const char *pos = cmd;
 	enum wpa_alg alg;
+	enum key_flag key_flag;
 	int idx, set_tx;
 	u8 seq[6], key[WPA_TK_MAX_LEN];
 	size_t key_len;
 
-	/* parameters: alg addr idx set_tx seq key */
+	/* parameters: alg addr idx set_tx seq key key_flag */
 
 	alg = atoi(pos);
 	pos = os_strchr(pos, ' ');
@@ -2248,13 +2274,24 @@
 	if (*pos != ' ')
 		return -1;
 	pos++;
-	key_len = os_strlen(pos) / 2;
+	if (!os_strchr(pos, ' '))
+		return -1;
+	key_len = (os_strchr(pos, ' ') - pos) / 2;
 	if (hexstr2bin(pos, key, key_len) < 0)
 		return -1;
+	pos += 2 * key_len;
+	if (*pos != ' ')
+		return -1;
+
+	pos++;
+	key_flag = atoi(pos);
+	pos = os_strchr(pos, ' ');
+	if (pos)
+		return -1;
 
 	wpa_printf(MSG_INFO, "TESTING: Set key");
-	return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
-				   set_tx, seq, 6, key, key_len);
+	return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0,
+				   set_tx, seq, 6, key, key_len, key_flag);
 }
 
 
@@ -2269,8 +2306,9 @@
 	 * in replay protection issues for now since there is no clean way of
 	 * preventing encryption of a single EAPOL frame. */
 	hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
-			    sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-			    sta->last_tk, sta->last_tk_len);
+			    sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+			    sta->last_tk, sta->last_tk_len,
+			    KEY_FLAG_PAIRWISE_RX_TX);
 }
 
 
@@ -2293,8 +2331,8 @@
 		wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
-				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+				    0, NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
@@ -2323,8 +2361,8 @@
 		wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
-				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+				    0, NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
@@ -2353,8 +2391,8 @@
 		wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
-				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+				    0, NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	wpa_printf(MSG_INFO,
@@ -2364,21 +2402,204 @@
 					plain ? restore_tk : NULL, hapd, sta);
 }
 
+
+static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
+				char *buf, size_t buflen)
+{
+	struct sta_info *sta;
+	u8 addr[ETH_ALEN];
+	const u8 *pmk;
+	int pmk_len;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta || !sta->wpa_sm) {
+		wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
+			   MAC2STR(addr));
+		return -1;
+	}
+	pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+	if (!pmk) {
+		wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
+static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
+{
+	switch (params->bandwidth) {
+	case 0:
+		/* bandwidth not specified: use 20 MHz by default */
+		/* fall-through */
+	case 20:
+		if (params->center_freq1 &&
+		    params->center_freq1 != params->freq)
+			return -1;
+
+		if (params->center_freq2 || params->sec_channel_offset)
+			return -1;
+		break;
+	case 40:
+		if (params->center_freq2 || !params->sec_channel_offset)
+			return -1;
+
+		if (!params->center_freq1)
+			break;
+		switch (params->sec_channel_offset) {
+		case 1:
+			if (params->freq + 10 != params->center_freq1)
+				return -1;
+			break;
+		case -1:
+			if (params->freq - 10 != params->center_freq1)
+				return -1;
+			break;
+		default:
+			return -1;
+		}
+		break;
+	case 80:
+		if (!params->center_freq1 || !params->sec_channel_offset)
+			return 1;
+
+		switch (params->sec_channel_offset) {
+		case 1:
+			if (params->freq - 10 != params->center_freq1 &&
+			    params->freq + 30 != params->center_freq1)
+				return 1;
+			break;
+		case -1:
+			if (params->freq + 10 != params->center_freq1 &&
+			    params->freq - 30 != params->center_freq1)
+				return -1;
+			break;
+		default:
+			return -1;
+		}
+
+		/* Adjacent and overlapped are not allowed for 80+80 */
+		if (params->center_freq2 &&
+		    params->center_freq1 - params->center_freq2 <= 80 &&
+		    params->center_freq2 - params->center_freq1 <= 80)
+			return 1;
+		break;
+	case 160:
+		if (!params->center_freq1 || params->center_freq2 ||
+		    !params->sec_channel_offset)
+			return -1;
+
+		switch (params->sec_channel_offset) {
+		case 1:
+			if (params->freq + 70 != params->center_freq1 &&
+			    params->freq + 30 != params->center_freq1 &&
+			    params->freq - 10 != params->center_freq1 &&
+			    params->freq - 50 != params->center_freq1)
+				return -1;
+			break;
+		case -1:
+			if (params->freq + 50 != params->center_freq1 &&
+			    params->freq + 10 != params->center_freq1 &&
+			    params->freq - 30 != params->center_freq1 &&
+			    params->freq - 70 != params->center_freq1)
+				return -1;
+			break;
+		default:
+			return -1;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
 static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
 					  char *pos)
 {
 #ifdef NEED_AP_MLME
 	struct csa_settings settings;
 	int ret;
+	int dfs_range = 0;
 	unsigned int i;
+	int bandwidth;
+	u8 chan;
 
 	ret = hostapd_parse_csa_settings(pos, &settings);
 	if (ret)
 		return ret;
 
+	ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
+	if (ret) {
+		wpa_printf(MSG_INFO,
+			   "chanswitch: invalid frequency settings provided");
+		return ret;
+	}
+
+	switch (settings.freq_params.bandwidth) {
+	case 40:
+		bandwidth = CHAN_WIDTH_40;
+		break;
+	case 80:
+		if (settings.freq_params.center_freq2)
+			bandwidth = CHAN_WIDTH_80P80;
+		else
+			bandwidth = CHAN_WIDTH_80;
+		break;
+	case 160:
+		bandwidth = CHAN_WIDTH_160;
+		break;
+	default:
+		bandwidth = CHAN_WIDTH_20;
+		break;
+	}
+
+	if (settings.freq_params.center_freq1)
+		dfs_range += hostapd_is_dfs_overlap(
+			iface, bandwidth, settings.freq_params.center_freq1);
+	else
+		dfs_range += hostapd_is_dfs_overlap(
+			iface, bandwidth, settings.freq_params.freq);
+
+	if (settings.freq_params.center_freq2)
+		dfs_range += hostapd_is_dfs_overlap(
+			iface, bandwidth, settings.freq_params.center_freq2);
+
+	if (dfs_range) {
+		ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
+		if (ret == NUM_HOSTAPD_MODES) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
+				   settings.freq_params.freq,
+				   settings.freq_params.sec_channel_offset,
+				   settings.freq_params.bandwidth);
+			return -1;
+		}
+
+		settings.freq_params.channel = chan;
+
+		wpa_printf(MSG_DEBUG,
+			   "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
+			   settings.freq_params.channel,
+			   settings.freq_params.freq,
+			   settings.freq_params.sec_channel_offset,
+			   settings.freq_params.bandwidth,
+			   settings.freq_params.center_freq1);
+
+		/* Perform CAC and switch channel */
+		hostapd_switch_channel_fallback(iface, &settings.freq_params);
+		return 0;
+	}
+
 	for (i = 0; i < iface->num_bss; i++) {
 
 		/* Save CHAN_SWITCH VHT config */
@@ -3232,6 +3453,9 @@
 	} else if (os_strcmp(buf, "REKEY_GTK") == 0) {
 		if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "GET_PMK ", 8) == 0) {
+		reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply,
+						 reply_size);
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
 		if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -3348,6 +3572,24 @@
 			if (os_snprintf_error(reply_size, reply_len))
 				reply_len = -1;
 		}
+	} else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+		res = hostapd_dpp_nfc_handover_req(hapd, buf + 20);
+		if (res < 0) {
+			reply_len = -1;
+		} else {
+			reply_len = os_snprintf(reply, reply_size, "%d", res);
+			if (os_snprintf_error(reply_size, reply_len))
+				reply_len = -1;
+		}
+	} else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+		res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20);
+		if (res < 0) {
+			reply_len = -1;
+		} else {
+			reply_len = os_snprintf(reply, reply_size, "%d", res);
+			if (os_snprintf_error(reply_size, reply_len))
+				reply_len = -1;
+		}
 	} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
 		res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
 		if (res < 0) {
@@ -3377,6 +3619,11 @@
 		reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
 					       atoi(buf + 19),
 			reply, reply_size);
+	} else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+		if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
+				      atoi(buf + 18),
+				      os_strchr(buf + 18, ' ')) < 0)
+			reply_len = -1;
 	} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
 		if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
 			reply_len = -1;
@@ -3456,7 +3703,7 @@
 	int reply_len;
 	int level = MSG_DEBUG;
 #ifdef CONFIG_CTRL_IFACE_UDP
-	unsigned char lcookie[COOKIE_LEN];
+	unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
 #endif /* CONFIG_CTRL_IFACE_UDP */
 
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -3481,28 +3728,30 @@
 #ifdef CONFIG_CTRL_IFACE_UDP
 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
 		os_memcpy(reply, "COOKIE=", 7);
-		wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
-				 cookie, COOKIE_LEN);
-		reply_len = 7 + 2 * COOKIE_LEN;
+		wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+				 hapd->ctrl_iface_cookie,
+				 CTRL_IFACE_COOKIE_LEN);
+		reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
 		goto done;
 	}
 
 	if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
-	    hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+	    hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "CTRL: No cookie in the request - drop request");
 		os_free(reply);
 		return;
 	}
 
-	if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+	if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
+		      CTRL_IFACE_COOKIE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG,
 			   "CTRL: Invalid cookie in the request - drop request");
 		os_free(reply);
 		return;
 	}
 
-	pos = buf + 7 + 2 * COOKIE_LEN;
+	pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
 	while (*pos == ' ')
 		pos++;
 #endif /* CONFIG_CTRL_IFACE_UDP */
@@ -3591,7 +3840,7 @@
 
 	dl_list_init(&hapd->ctrl_dst);
 	hapd->ctrl_sock = -1;
-	os_get_random(cookie, COOKIE_LEN);
+	os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
 
 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
 	hints.ai_flags = AI_PASSIVE;
@@ -4170,7 +4419,7 @@
 static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
 					      void *sock_ctx)
 {
-	void *interfaces = eloop_ctx;
+	struct hapd_interfaces *interfaces = eloop_ctx;
 	char buffer[256], *buf = buffer;
 	int res;
 	struct sockaddr_storage from;
@@ -4179,7 +4428,7 @@
 	int reply_len;
 	const int reply_size = 4096;
 #ifdef CONFIG_CTRL_IFACE_UDP
-	unsigned char lcookie[COOKIE_LEN];
+	unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
 #endif /* CONFIG_CTRL_IFACE_UDP */
 
 	res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
@@ -4208,28 +4457,30 @@
 #ifdef CONFIG_CTRL_IFACE_UDP
 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
 		os_memcpy(reply, "COOKIE=", 7);
-		wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
-				 gcookie, COOKIE_LEN);
-		reply_len = 7 + 2 * COOKIE_LEN;
+		wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+				 interfaces->ctrl_iface_cookie,
+				 CTRL_IFACE_COOKIE_LEN);
+		reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
 		goto send_reply;
 	}
 
 	if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
-	    hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+	    hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "CTRL: No cookie in the request - drop request");
 		os_free(reply);
 		return;
 	}
 
-	if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+	if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
+		      CTRL_IFACE_COOKIE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG,
 			   "CTRL: Invalid cookie in the request - drop request");
 		os_free(reply);
 		return;
 	}
 
-	buf += 7 + 2 * COOKIE_LEN;
+	buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
 	while (*buf == ' ')
 		buf++;
 #endif /* CONFIG_CTRL_IFACE_UDP */
@@ -4373,7 +4624,7 @@
 		}
 	}
 
-	os_get_random(gcookie, COOKIE_LEN);
+	os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
 
 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
 	hints.ai_flags = AI_PASSIVE;
@@ -4616,13 +4867,8 @@
 		return;
 	idx = 0;
 	if (ifname) {
-#ifdef CONFIG_CTRL_IFACE_UDP
-		io[idx].iov_base = "IFACE=";
-		io[idx].iov_len = 6;
-#else /* CONFIG_CTRL_IFACE_UDP */
 		io[idx].iov_base = "IFNAME=";
 		io[idx].iov_len = 7;
-#endif /* CONFIG_CTRL_IFACE_UDP */
 		idx++;
 		io[idx].iov_base = (char *) ifname;
 		io[idx].iov_len = os_strlen(ifname);
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 6e2eaa3..f630a22 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -148,9 +148,6 @@
 # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
 #CONFIG_DRIVER_RADIUS_ACL=y
 
-# IEEE 802.11n (High Throughput) support
-#CONFIG_IEEE80211N=y
-
 # Wireless Network Management (IEEE Std 802.11v-2011)
 # Note: This is experimental and not complete implementation.
 #CONFIG_WNM=y
@@ -388,3 +385,11 @@
 # Override default value for the wpa_disable_eapol_key_retries configuration
 # parameter. See that parameter in hostapd.conf for more details.
 #CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 263a04e..812c09a 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -72,7 +72,7 @@
 # run as non-root users. However, since the control interface can be used to
 # change the network configuration, this access needs to be protected in many
 # cases. By default, hostapd is configured to use gid 0 (root). If you
-# want to allow non-root users to use the contron interface, add a new group
+# want to allow non-root users to use the control interface, add a new group
 # and change this value to match with that group. Add users that should have
 # control interface access to this group.
 #
@@ -598,8 +598,6 @@
 #	channels if needed or creation of 40 MHz channel maybe rejected based
 #	on overlapping BSSes. These changes are done automatically when hostapd
 #	is setting up the 40 MHz channel.
-# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
-#	(SMPS disabled if neither is set)
 # HT-greenfield: [GF] (disabled if not set)
 # Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
 # Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
@@ -806,6 +804,9 @@
 # he_bss_color: BSS color (1-63)
 #he_bss_color=1
 
+# he_bss_color_partial: BSS color AID equation
+#he_bss_color_partial=0
+
 #he_default_pe_duration: The duration of PE field in an HE PPDU in us
 # Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
 #he_default_pe_duration=0
@@ -903,6 +904,8 @@
 
 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
 # reauthentication).
+# Note: Reauthentications may enforce a disconnection, check the related
+# parameter wpa_deny_ptk0_rekey for details.
 #eap_reauth_period=3600
 
 # Use PAE group address (01:80:c2:00:00:03) instead of individual target
@@ -1507,6 +1510,17 @@
 # wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
 #wpa=2
 
+# Extended Key ID support for Individually Addressed frames
+#
+# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
+# PTK rekeying with only a single Key ID 0 has. It can only be used when the
+# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
+#
+# 0 = force off, i.e., use only Key ID 0 (default)
+# 1 = enable and use Extended Key ID support when possible
+# 2 = identical to 1 but start with Key ID 1 when possible
+#extended_key_id=0
+
 # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
 # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
 # (8..63 characters) that will be converted to PSK. This conversion uses SSID
@@ -1607,8 +1621,26 @@
 
 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
 # PTK to mitigate some attacks against TKIP deficiencies.
+# Warning: PTK rekeying is buggy with many drivers/devices and with such
+# devices, the only secure method to rekey the PTK without Extended Key ID
+# support requires a disconnection. Check the related parameter
+# wpa_deny_ptk0_rekey for details.
 #wpa_ptk_rekey=600
 
+# Workaround for PTK rekey issues
+#
+# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually
+# Addressed Frames") can degrade the security and stability with some cards.
+# To avoid such issues hostapd can replace those PTK rekeys (including EAP
+# reauthentications) with disconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+#	this operation without issues
+# 2 = never allow PTK0 rekeys
+#wpa_deny_ptk0_rekey=0
+
 # The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
 # Handshake are retried per 4-Way Handshake attempt.
 # (dot11RSNAConfigPairwiseUpdateCount)
@@ -1677,6 +1709,12 @@
 # available in deployed devices.
 #group_mgmt_cipher=AES-128-CMAC
 
+# Beacon Protection (management frame protection for Beacon frames)
+# This depends on management frame protection being enabled (ieee80211w != 0).
+# 0 = disabled (default)
+# 1 = enabled
+#beacon_prot=0
+
 # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
 # (maximum time to wait for a SA Query response)
 # dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@@ -1784,11 +1822,13 @@
 #sae_confirm_immediate=0
 
 # SAE mechanism for PWE derivation
-# 0 = hunting-and-pecking loop only (default)
-# 1 = hash-to-element only
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
 # 2 = both hunting-and-pecking loop and hash-to-element enabled
 # Note: The default value is likely to change from 0 to 2 once the new
 # hash-to-element mechanism has received more interoperability testing.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
 #sae_pwe=0
 
 # FILS Cache Identifier (16-bit value in hexdump format)
@@ -1815,6 +1855,19 @@
 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
 #owe_groups=19 20 21
 
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all OWE
+# groups. This was supposed to change to SHA384 for group 20 and SHA512 for
+# group 21. This parameter can be used to enable workaround for interoperability
+# with stations that use SHA256 with groups 20 and 21. By default (0) only the
+# appropriate hash function is accepted. When workaround is enabled (1), the
+# appropriate hash function is tried first and if that fails, SHA256-based PTK
+# derivation is attempted. This workaround can result in reduced security for
+# groups 20 and 21, but is required for interoperability with older
+# implementations. There is no impact to group 19 behavior. The workaround is
+# disabled by default and can be enabled by uncommenting the following line.
+#owe_ptk_workaround=1
+
 # OWE transition mode configuration
 # Pointer to the matching open/OWE BSS
 #owe_transition_bssid=<bssid>
@@ -1852,6 +1905,23 @@
 # default: 30 TUs (= 30.72 milliseconds)
 #fils_hlp_wait_time=30
 
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode in their
+# network profiles when the network has completed transition steps, i.e., once
+# sufficiently large number of APs in the ESS have been updated to support the
+# more secure alternative. When this indication is used, the stations are
+# expected to automatically disable transition mode and less secure security
+# options. This includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only
+#	allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE)
+# (default: 0 = do not include Transition Disable KDE)
+#transition_disable=0x01
+
 ##### IEEE 802.11r configuration ##############################################
 
 # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -2205,6 +2275,13 @@
 #wps_nfc_dh_privkey: Hexdump of DH Private Key
 #wps_nfc_dev_pw: Hexdump of Device Password
 
+# Application Extension attribute for Beacon and Probe Response frames
+# This parameter can be used to add application extension into WPS IE. The
+# contents of this parameter starts with 16-octet (32 hexdump characters) of
+# UUID to identify the specific application and that is followed by the actual
+# application specific data.
+#wps_application_ext=<hexdump>
+
 ##### Wi-Fi Direct (P2P) ######################################################
 
 # Enable P2P Device management
@@ -2227,6 +2304,17 @@
 #dpp_csign
 #dpp_controller
 
+# Configurator Connectivity indication
+# 0: no Configurator is currently connected (default)
+# 1: advertise that a Configurator is available
+#dpp_configurator_connectivity=0
+
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
 #### TDLS (IEEE 802.11z-2010) #################################################
 
 # Prohibit use of TDLS in this BSS
@@ -2607,7 +2695,7 @@
 # Default is 0 = OCE disabled
 #oce=0
 
-# RSSI-based assocition rejection
+# RSSI-based association rejection
 #
 # Reject STA association if RSSI is below given threshold (in dBm)
 # Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk
index 166e59e..2ce5ff2 100644
--- a/hostapd/hostapd.wpa_psk
+++ b/hostapd/hostapd.wpa_psk
@@ -7,9 +7,15 @@
 # keyid=<keyid_string>
 # An optional VLAN ID can be specified by prefixing the line with
 # vlanid=<VLAN ID>.
+# An optional WPS tag can be added by prefixing the line with
+# wps=<0/1> (default: 0). Any matching entry with that tag will be used when
+# generating a PSK for a WPS Enrollee instead of generating a new random
+# per-Enrollee PSK.
 00:00:00:00:00:00 secret passphrase
 00:11:22:33:44:55 another passphrase
 00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
 keyid=example_id 00:11:22:33:44:77 passphrase with keyid
 vlanid=3 00:00:00:00:00:00 passphrase with vlanid
+wps=1 00:00:00:00:00:00 passphrase for WPS
+wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS
 00:00:00:00:00:00 another passphrase for all STAs
diff --git a/hostapd/main.c b/hostapd/main.c
index f08d60e..85c1fd1 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -220,7 +220,6 @@
 		struct wowlan_triggers *triggs;
 
 		iface->drv_flags = capa.flags;
-		iface->smps_modes = capa.smps_modes;
 		iface->probe_resp_offloads = capa.probe_resp_offloads;
 		/*
 		 * Use default extended capa values from per-radio information
@@ -262,7 +261,7 @@
 	struct hostapd_iface *iface;
 	int k;
 
-	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
+	wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
 	iface = hostapd_init(interfaces, config_fname);
 	if (!iface)
 		return NULL;
@@ -453,11 +452,12 @@
 static void show_version(void)
 {
 	fprintf(stderr,
-		"hostapd v" VERSION_STR "\n"
+		"hostapd v%s\n"
 		"User space daemon for IEEE 802.11 AP management,\n"
 		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
 		"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
-		"and contributors\n");
+		"and contributors\n",
+		VERSION_STR);
 }
 
 
@@ -772,7 +772,7 @@
 
 	if (log_file)
 		wpa_debug_open_file(log_file);
-	else
+	if (!log_file && !wpa_debug_syslog)
 		wpa_debug_setup_stdout();
 #ifdef CONFIG_DEBUG_SYSLOG
 	if (wpa_debug_syslog)
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index 67f6f55..cc2af03 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -30,8 +30,17 @@
 
 ifndef CONFIG_NO_BROWSER
 ifndef CONFIG_BROWSER_SYSTEM
+TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0)
+ifeq ($(TEST_WK),)
+# Try webkit2
+GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0)
+GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0)
+CFLAGS += -DUSE_WEBKIT2
+else
 GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
 GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
+endif
+
 CFLAGS += $(GTKCFLAGS)
 LIBS += $(GTKLIBS)
 endif
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index d75c845..bcd68b8 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -407,7 +407,7 @@
 	wpa_printf(MSG_INFO, "Data: %s", data);
 	wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
 	write_summary(ctx, "Launch browser to URI '%s'", data);
-	res = hs20_web_browser(data);
+	res = hs20_web_browser(data, 1);
 	xml_node_get_text_free(ctx->xml, data);
 	if (res > 0) {
 		wpa_printf(MSG_INFO, "User response in browser completed successfully");
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index a94f40c..11bf0db 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2233,7 +2233,7 @@
 	wpa_ctrl_close(mon);
 
 	if (res < 0) {
-		wpa_printf(MSG_INFO, "Could not connect");
+		wpa_printf(MSG_INFO, "Could not connect to OSU network");
 		write_summary(ctx, "Could not connect to OSU network");
 		wpa_printf(MSG_INFO, "Remove OSU network connection");
 		snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
@@ -2406,7 +2406,7 @@
 
 	snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
 	write_summary(ctx, "Start web browser with OSU provider selection page");
-	ret = hs20_web_browser(fname);
+	ret = hs20_web_browser(fname, 0);
 
 selected:
 	if (ret > 0 && (size_t) ret <= osu_count) {
@@ -2907,7 +2907,7 @@
 static int osu_cert_cb(void *_ctx, struct http_cert *cert)
 {
 	struct hs20_osu_client *ctx = _ctx;
-	unsigned int i, j;
+	size_t i, j;
 	int found;
 	char *host = NULL;
 
@@ -3002,7 +3002,7 @@
 		size_t name_len = os_strlen(name);
 
 		wpa_printf(MSG_INFO,
-			   "[%i] Looking for icon file name '%s' match",
+			   "[%zu] Looking for icon file name '%s' match",
 			   j, name);
 		for (i = 0; i < cert->num_logo; i++) {
 			struct http_logo *logo = &cert->logo[i];
@@ -3010,7 +3010,7 @@
 			char *pos;
 
 			wpa_printf(MSG_INFO,
-				   "[%i] Comparing to '%s' uri_len=%d name_len=%d",
+				   "[%zu] Comparing to '%s' uri_len=%d name_len=%d",
 				   i, logo->uri, (int) uri_len, (int) name_len);
 			if (uri_len < 1 + name_len) {
 				wpa_printf(MSG_INFO, "URI Length is too short");
@@ -3044,7 +3044,7 @@
 
 			if (logo->hash_len != 32) {
 				wpa_printf(MSG_INFO,
-					   "[%i][%i] Icon hash length invalid (should be 32): %d",
+					   "[%zu][%zu] Icon hash length invalid (should be 32): %d",
 					   j, i, (int) logo->hash_len);
 				continue;
 			}
@@ -3054,7 +3054,7 @@
 			}
 
 			wpa_printf(MSG_DEBUG,
-				   "[%u][%u] Icon hash did not match", j, i);
+				   "[%zu][%zu] Icon hash did not match", j, i);
 			wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
 					  logo->hash, 32);
 			wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
@@ -3152,7 +3152,7 @@
 
 static void usage(void)
 {
-	printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
+	printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n"
 	       "    [-w<wpa_supplicant ctrl_iface dir>] "
 	       "[-r<result file>] [-f<debug file>] \\\n"
 	       "    [-s<summary file>] \\\n"
@@ -3198,7 +3198,7 @@
 		return -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
+		c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -3236,6 +3236,9 @@
 		case 't':
 			wpa_debug_timestamp++;
 			break;
+		case 'T':
+			ctx.ignore_tls = 1;
+			break;
 		case 'w':
 			wpas_ctrl_path = optarg;
 			break;
@@ -3403,7 +3406,7 @@
 
 		wpa_printf(MSG_INFO, "Launch web browser to URL %s",
 			   argv[optind + 1]);
-		ret = hs20_web_browser(argv[optind + 1]);
+		ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
 		wpa_printf(MSG_INFO, "Web browser result: %d", ret);
 	} else if (strcmp(argv[optind], "parse_cert") == 0) {
 		if (argc - optind < 2) {
diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h
index 5c8e6d0..9b45b03 100644
--- a/hs20/client/osu_client.h
+++ b/hs20/client/osu_client.h
@@ -50,6 +50,8 @@
 	const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
 #define WORKAROUND_OCSP_OPTIONAL 0x00000001
 	unsigned long int workarounds;
+	int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
+			 * server certificate */
 };
 
 
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index c619541..39d10e0 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -547,7 +547,7 @@
 		}
 		wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
 		write_summary(ctx, "Launch browser to URI '%s'", uri);
-		res = hs20_web_browser(uri);
+		res = hs20_web_browser(uri, 1);
 		xml_node_get_text_free(ctx->xml, uri);
 		if (res > 0) {
 			wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
diff --git a/hs20/server/ca/ocsp-responder.sh b/hs20/server/ca/ocsp-responder.sh
index 8cebd74..620947d 100644
--- a/hs20/server/ca/ocsp-responder.sh
+++ b/hs20/server/ca/ocsp-responder.sh
@@ -1,3 +1,3 @@
 #!/bin/sh
 
-openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text
+openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err
diff --git a/hs20/server/ca/ocsp-update-cache.sh b/hs20/server/ca/ocsp-update-cache.sh
index 8ddef9b..f2b2325 100644
--- a/hs20/server/ca/ocsp-update-cache.sh
+++ b/hs20/server/ca/ocsp-update-cache.sh
@@ -1,5 +1,6 @@
 #!/bin/sh
 
+# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
 openssl ocsp \
 	-no_nonce \
 	-CAfile ca.pem \
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
index 6c74f54..347c40a 100644
--- a/hs20/server/hs20_spp_server.c
+++ b/hs20/server/hs20_spp_server.c
@@ -176,7 +176,7 @@
 			ctx.root_dir = optarg;
 			break;
 		case 'v':
-			printf("hs20_spp_server v" VERSION_STR "\n");
+			printf("hs20_spp_server v%s\n", VERSION_STR);
 			return 0;
 		default:
 			usage();
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 232afa8..5c01610 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -261,13 +261,13 @@
 }
 
 
-void acs_cleanup(struct hostapd_iface *iface)
+static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
 {
 	int i;
 	struct hostapd_channel_data *chan;
 
-	for (i = 0; i < iface->current_mode->num_channels; i++) {
-		chan = &iface->current_mode->channels[i];
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
 
 		if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
 			acs_clean_chan_surveys(chan);
@@ -276,6 +276,15 @@
 		chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
 		chan->min_nf = 0;
 	}
+}
+
+
+void acs_cleanup(struct hostapd_iface *iface)
+{
+	int i;
+
+	for (i = 0; i < iface->num_hw_features; i++)
+		acs_cleanup_mode(&iface->hw_features[i]);
 
 	iface->chans_surveyed = 0;
 	iface->acs_num_completed_scans = 0;
@@ -453,21 +462,35 @@
 }
 
 
-static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode)
 {
 	int i;
 	struct hostapd_channel_data *chan;
-	int valid = 0;
 
-	for (i = 0; i < iface->current_mode->num_channels; i++) {
-		chan = &iface->current_mode->channels[i];
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
 		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
 		    acs_survey_list_is_sufficient(chan))
-			valid++;
+			return 1;
 	}
 
-	/* We need at least survey data for one channel */
-	return !!valid;
+	return 0;
+}
+
+
+static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+{
+	int i;
+	struct hostapd_hw_modes *mode;
+
+	for (i = 0; i < iface->num_hw_features; i++) {
+		mode = &iface->hw_features[i];
+		if (!hostapd_hw_skip_mode(iface, mode) &&
+		    acs_surveys_are_sufficient_mode(mode))
+			return 1;
+	}
+
+	return 0;
 }
 
 
@@ -489,14 +512,14 @@
 }
 
 
-static void acs_survey_all_chans_intereference_factor(
-	struct hostapd_iface *iface)
+static void acs_survey_mode_interference_factor(
+	struct hostapd_iface *iface, struct hostapd_hw_modes *mode)
 {
 	int i;
 	struct hostapd_channel_data *chan;
 
-	for (i = 0; i < iface->current_mode->num_channels; i++) {
-		chan = &iface->current_mode->channels[i];
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
 
 		if (!acs_usable_chan(chan))
 			continue;
@@ -515,14 +538,28 @@
 }
 
 
-static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
-						  int freq)
+static void acs_survey_all_chans_interference_factor(
+	struct hostapd_iface *iface)
+{
+	int i;
+	struct hostapd_hw_modes *mode;
+
+	for (i = 0; i < iface->num_hw_features; i++) {
+		mode = &iface->hw_features[i];
+		if (!hostapd_hw_skip_mode(iface, mode))
+			acs_survey_mode_interference_factor(iface, mode);
+	}
+}
+
+
+static struct hostapd_channel_data *
+acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
 {
 	struct hostapd_channel_data *chan;
 	int i;
 
-	for (i = 0; i < iface->current_mode->num_channels; i++) {
-		chan = &iface->current_mode->channels[i];
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
 
 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
@@ -535,6 +572,26 @@
 }
 
 
+static struct hostapd_channel_data *
+acs_find_chan(struct hostapd_iface *iface, int freq)
+{
+	int i;
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+
+	for (i = 0; i < iface->num_hw_features; i++) {
+		mode = &iface->hw_features[i];
+		if (!hostapd_hw_skip_mode(iface, mode)) {
+			chan = acs_find_chan_mode(mode, freq);
+			if (chan)
+				return chan;
+		}
+	}
+
+	return NULL;
+}
+
+
 static int is_24ghz_mode(enum hostapd_hw_mode mode)
 {
 	return mode == HOSTAPD_MODE_IEEE80211B ||
@@ -565,58 +622,24 @@
 #define ACS_24GHZ_PREFER_1_6_11 0.8
 #endif /* ACS_24GHZ_PREFER_1_6_11 */
 
-/*
- * At this point it's assumed chan->interface_factor has been computed.
- * This function should be reusable regardless of interference computation
- * option (survey, BSS, spectral, ...). chan->interference factor must be
- * summable (i.e., must be always greater than zero).
- */
-static struct hostapd_channel_data *
-acs_find_ideal_chan(struct hostapd_iface *iface)
+static void
+acs_find_ideal_chan_mode(struct hostapd_iface *iface,
+			 struct hostapd_hw_modes *mode,
+			 int n_chans, u32 bw,
+			 struct hostapd_channel_data **rand_chan,
+			 struct hostapd_channel_data **ideal_chan,
+			 long double *ideal_factor)
 {
-	struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
-		*rand_chan = NULL;
-	long double factor, ideal_factor = 0;
+	struct hostapd_channel_data *chan, *adj_chan = NULL;
+	long double factor;
 	int i, j;
-	int n_chans = 1;
-	u32 bw;
 	unsigned int k;
 
-	/* TODO: HT40- support */
-
-	if (iface->conf->ieee80211n &&
-	    iface->conf->secondary_channel == -1) {
-		wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
-		return NULL;
-	}
-
-	if (iface->conf->ieee80211n &&
-	    iface->conf->secondary_channel)
-		n_chans = 2;
-
-	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
-		switch (hostapd_get_oper_chwidth(iface->conf)) {
-		case CHANWIDTH_80MHZ:
-			n_chans = 4;
-			break;
-		case CHANWIDTH_160MHZ:
-			n_chans = 8;
-			break;
-		}
-	}
-
-	bw = num_chan_to_bw(n_chans);
-
-	/* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
-
-	wpa_printf(MSG_DEBUG,
-		   "ACS: Survey analysis for selected bandwidth %d MHz", bw);
-
-	for (i = 0; i < iface->current_mode->num_channels; i++) {
+	for (i = 0; i < mode->num_channels; i++) {
 		double total_weight;
 		struct acs_bias *bias, tmp_bias;
 
-		chan = &iface->current_mode->channels[i];
+		chan = &mode->channels[i];
 
 		/* Since in the current ACS implementation the first channel is
 		 * always a primary channel, skip channels not available as
@@ -637,7 +660,7 @@
 
 		/* HT40 on 5 GHz has a limited set of primary channels as per
 		 * 11n Annex J */
-		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+		if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
 		    iface->conf->ieee80211n &&
 		    iface->conf->secondary_channel &&
 		    !acs_usable_ht40_chan(chan)) {
@@ -646,7 +669,7 @@
 			continue;
 		}
 
-		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+		if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
 		    (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
 			if (hostapd_get_oper_chwidth(iface->conf) ==
 			    CHANWIDTH_80MHZ &&
@@ -698,7 +721,7 @@
 
 		/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
 		 * channel interference factor. */
-		if (is_24ghz_mode(iface->current_mode->mode)) {
+		if (is_24ghz_mode(mode->mode)) {
 			for (j = 0; j < n_chans; j++) {
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 5);
@@ -744,7 +767,7 @@
 					break;
 				bias = NULL;
 			}
-		} else if (is_24ghz_mode(iface->current_mode->mode) &&
+		} else if (is_24ghz_mode(mode->mode) &&
 			   is_common_24ghz_chan(chan->chan)) {
 			tmp_bias.channel = chan->chan;
 			tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
@@ -763,14 +786,71 @@
 		}
 
 		if (acs_usable_chan(chan) &&
-		    (!ideal_chan || factor < ideal_factor)) {
-			ideal_factor = factor;
-			ideal_chan = chan;
+		    (!*ideal_chan || factor < *ideal_factor)) {
+			*ideal_factor = factor;
+			*ideal_chan = chan;
 		}
 
 		/* This channel would at least be usable */
-		if (!rand_chan)
-			rand_chan = chan;
+		if (!(*rand_chan))
+			*rand_chan = chan;
+	}
+}
+
+
+/*
+ * At this point it's assumed chan->interference_factor has been computed.
+ * This function should be reusable regardless of interference computation
+ * option (survey, BSS, spectral, ...). chan->interference factor must be
+ * summable (i.e., must be always greater than zero).
+ */
+static struct hostapd_channel_data *
+acs_find_ideal_chan(struct hostapd_iface *iface)
+{
+	struct hostapd_channel_data *ideal_chan = NULL,
+		*rand_chan = NULL;
+	long double ideal_factor = 0;
+	int i;
+	int n_chans = 1;
+	u32 bw;
+	struct hostapd_hw_modes *mode;
+
+	/* TODO: HT40- support */
+
+	if (iface->conf->ieee80211n &&
+	    iface->conf->secondary_channel == -1) {
+		wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
+		return NULL;
+	}
+
+	if (iface->conf->ieee80211n &&
+	    iface->conf->secondary_channel)
+		n_chans = 2;
+
+	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+		switch (hostapd_get_oper_chwidth(iface->conf)) {
+		case CHANWIDTH_80MHZ:
+			n_chans = 4;
+			break;
+		case CHANWIDTH_160MHZ:
+			n_chans = 8;
+			break;
+		}
+	}
+
+	bw = num_chan_to_bw(n_chans);
+
+	/* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
+
+	wpa_printf(MSG_DEBUG,
+		   "ACS: Survey analysis for selected bandwidth %d MHz", bw);
+
+	for (i = 0; i < iface->num_hw_features; i++) {
+		mode = &iface->hw_features[i];
+		if (!hostapd_hw_skip_mode(iface, mode))
+			acs_find_ideal_chan_mode(iface, mode, n_chans, bw,
+						 &rand_chan, &ideal_chan,
+						 &ideal_factor);
 	}
 
 	if (ideal_chan) {
@@ -826,7 +906,7 @@
 		return -1;
 	}
 
-	acs_survey_all_chans_intereference_factor(iface);
+	acs_survey_all_chans_interference_factor(iface);
 	return 0;
 }
 
@@ -918,21 +998,15 @@
 }
 
 
-static int acs_request_scan(struct hostapd_iface *iface)
+static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
+					struct hostapd_hw_modes *mode,
+					int *freq)
 {
-	struct wpa_driver_scan_params params;
 	struct hostapd_channel_data *chan;
-	int i, *freq;
+	int i;
 
-	os_memset(&params, 0, sizeof(params));
-	params.freqs = os_calloc(iface->current_mode->num_channels + 1,
-				 sizeof(params.freqs[0]));
-	if (params.freqs == NULL)
-		return -1;
-
-	freq = params.freqs;
-	for (i = 0; i < iface->current_mode->num_channels; i++) {
-		chan = &iface->current_mode->channels[i];
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
 			continue;
 
@@ -941,6 +1015,39 @@
 
 		*freq++ = chan->freq;
 	}
+
+	return freq;
+}
+
+
+static int acs_request_scan(struct hostapd_iface *iface)
+{
+	struct wpa_driver_scan_params params;
+	int i, *freq;
+	int num_channels;
+	struct hostapd_hw_modes *mode;
+
+	os_memset(&params, 0, sizeof(params));
+
+	num_channels = 0;
+	for (i = 0; i < iface->num_hw_features; i++) {
+		mode = &iface->hw_features[i];
+		if (!hostapd_hw_skip_mode(iface, mode))
+			num_channels += mode->num_channels;
+	}
+
+	params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
+	if (params.freqs == NULL)
+		return -1;
+
+	freq = params.freqs;
+
+	for (i = 0; i < iface->num_hw_features; i++) {
+		mode = &iface->hw_features[i];
+		if (!hostapd_hw_skip_mode(iface, mode))
+			freq = acs_request_scan_add_freqs(iface, mode, freq);
+	}
+
 	*freq = 0;
 
 	if (params.freqs == freq) {
@@ -978,7 +1085,8 @@
 		return HOSTAPD_CHAN_ACS;
 	}
 
-	if (!iface->current_mode)
+	if (!iface->current_mode &&
+	    iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
 		return HOSTAPD_CHAN_INVALID;
 
 	acs_cleanup(iface);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 68af3c1..5bf4502 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -54,16 +54,21 @@
 	bss->logger_syslog = (unsigned int) -1;
 	bss->logger_stdout = (unsigned int) -1;
 
+#ifdef CONFIG_WEP
 	bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
 
 	bss->wep_rekeying_period = 300;
 	/* use key0 in individual key and key1 in broadcast key */
 	bss->broadcast_key_idx_min = 1;
 	bss->broadcast_key_idx_max = 2;
+#else /* CONFIG_WEP */
+	bss->auth_algs = WPA_AUTH_ALG_OPEN;
+#endif /* CONFIG_WEP */
 	bss->eap_reauth_period = 3600;
 
 	bss->wpa_group_rekey = 600;
 	bss->wpa_gmk_rekey = 86400;
+	bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
 	bss->wpa_group_update_count = 4;
 	bss->wpa_pairwise_update_count = 4;
 	bss->wpa_disable_eapol_key_retries =
@@ -251,6 +256,9 @@
 		HE_OPERATION_RTS_THRESHOLD_OFFSET;
 	/* Set default basic MCS/NSS set to single stream MCS 0-7 */
 	conf->he_op.he_basic_mcs_nss_set = 0xfffc;
+	conf->he_op.he_bss_color_disabled = 1;
+	conf->he_op.he_bss_color_partial = 0;
+	conf->he_op.he_bss_color = 1;
 #endif /* CONFIG_IEEE80211AX */
 
 	/* The third octet of the country string uses an ASCII space character
@@ -301,6 +309,7 @@
 
 	while (fgets(buf, sizeof(buf), f)) {
 		int vlan_id = 0;
+		int wps = 0;
 
 		line++;
 
@@ -331,6 +340,8 @@
 				value = "";
 			if (!os_strcmp(name, "keyid")) {
 				keyid = value;
+			} else if (!os_strcmp(name, "wps")) {
+				wps = atoi(value);
 			} else if (!os_strcmp(name, "vlanid")) {
 				vlan_id = atoi(value);
 			} else {
@@ -348,8 +359,9 @@
 		if (!token)
 			token = "";
 		if (hwaddr_aton(token, addr)) {
-			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
-				   "line %d in '%s'", token, line, fname);
+			wpa_printf(MSG_ERROR,
+				   "Invalid MAC address '%s' on line %d in '%s'",
+				   token, line, fname);
 			ret = -1;
 			break;
 		}
@@ -377,16 +389,17 @@
 
 		ok = 0;
 		len = os_strlen(pos);
-		if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+		if (len == 2 * PMK_LEN &&
+		    hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
 			ok = 1;
-		else if (len >= 8 && len < 64) {
-			pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
-				    4096, psk->psk, PMK_LEN);
+		else if (len >= 8 && len < 64 &&
+			 pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+				     4096, psk->psk, PMK_LEN) == 0)
 			ok = 1;
-		}
 		if (!ok) {
-			wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
-				   "'%s'", pos, line, fname);
+			wpa_printf(MSG_ERROR,
+				   "Invalid PSK '%s' on line %d in '%s'",
+				   pos, line, fname);
 			os_free(psk);
 			ret = -1;
 			break;
@@ -404,6 +417,8 @@
 			}
 		}
 
+		psk->wps = wps;
+
 		psk->next = ssid->wpa_psk;
 		ssid->wpa_psk = psk;
 	}
@@ -441,7 +456,9 @@
 	struct hostapd_ssid *ssid = &conf->ssid;
 	struct sae_password_entry *pw;
 
-	if (conf->sae_pwe == 0 || !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
+	if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) ||
+	    conf->sae_pwe == 3 ||
+	    !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
 		return 0; /* PT not needed */
 
 	sae_deinit_pt(ssid->pt);
@@ -623,6 +640,7 @@
 }
 
 
+#ifdef CONFIG_WEP
 static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
 {
 	int i;
@@ -631,6 +649,7 @@
 		keys->key[i] = NULL;
 	}
 }
+#endif /* CONFIG_WEP */
 
 
 void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
@@ -719,7 +738,9 @@
 
 	str_clear_free(conf->ssid.wpa_passphrase);
 	os_free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_WEP
 	hostapd_config_free_wep(&conf->ssid.wep);
+#endif /* CONFIG_WEP */
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	os_free(conf->ssid.vlan_tagged_interface);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -813,6 +834,7 @@
 	os_free(conf->upc);
 	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
 		wpabuf_free(conf->wps_vendor_ext[i]);
+	wpabuf_free(conf->wps_application_ext);
 	wpabuf_free(conf->wps_nfc_dh_pubkey);
 	wpabuf_free(conf->wps_nfc_dh_privkey);
 	wpabuf_free(conf->wps_nfc_dev_pw);
@@ -880,7 +902,12 @@
 #ifdef CONFIG_TESTING_OPTIONS
 	wpabuf_free(conf->own_ie_override);
 	wpabuf_free(conf->sae_commit_override);
+	wpabuf_free(conf->rsne_override_eapol);
 	wpabuf_free(conf->rsnxe_override_eapol);
+	wpabuf_free(conf->rsne_override_ft);
+	wpabuf_free(conf->rsnxe_override_ft);
+	wpabuf_free(conf->gtk_rsc_override);
+	wpabuf_free(conf->igtk_rsc_override);
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	os_free(conf->no_probe_resp_if_seen_on);
@@ -1090,6 +1117,7 @@
 		return -1;
 	}
 
+#ifdef CONFIG_WEP
 	if (bss->wpa) {
 		int wep, i;
 
@@ -1107,6 +1135,7 @@
 			return -1;
 		}
 	}
+#endif /* CONFIG_WEP */
 
 	if (full_config && bss->wpa &&
 	    bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
@@ -1154,7 +1183,6 @@
 	}
 #endif /* CONFIG_IEEE80211R_AP */
 
-#ifdef CONFIG_IEEE80211N
 	if (full_config && conf->ieee80211n &&
 	    conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
 		bss->disable_11n = 1;
@@ -1162,12 +1190,14 @@
 			   "allowed, disabling HT capabilities");
 	}
 
+#ifdef CONFIG_WEP
 	if (full_config && conf->ieee80211n &&
 	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
 		bss->disable_11n = 1;
 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
 			   "allowed, disabling HT capabilities");
 	}
+#endif /* CONFIG_WEP */
 
 	if (full_config && conf->ieee80211n && bss->wpa &&
 	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1179,15 +1209,16 @@
 			   "requires CCMP/GCMP to be enabled, disabling HT "
 			   "capabilities");
 	}
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
+#ifdef CONFIG_WEP
 	if (full_config && conf->ieee80211ac &&
 	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
 		bss->disable_11ac = 1;
 		wpa_printf(MSG_ERROR,
 			   "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
 	}
+#endif /* CONFIG_WEP */
 
 	if (full_config && conf->ieee80211ac && bss->wpa &&
 	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1207,12 +1238,14 @@
 		bss->wps_state = 0;
 	}
 
+#ifdef CONFIG_WEP
 	if (full_config && bss->wps_state &&
 	    bss->ssid.wep.keys_set && bss->wpa == 0) {
 		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
 			   "disabled");
 		bss->wps_state = 0;
 	}
+#endif /* CONFIG_WEP */
 
 	if (full_config && bss->wps_state && bss->wpa &&
 	    (!(bss->wpa & 2) ||
@@ -1336,11 +1369,13 @@
 void hostapd_set_security_params(struct hostapd_bss_config *bss,
 				 int full_config)
 {
+#ifdef CONFIG_WEP
 	if (bss->individual_wep_key_len == 0) {
 		/* individual keys are not use; can use key idx0 for
 		 * broadcast keys */
 		bss->broadcast_key_idx_min = 0;
 	}
+#endif /* CONFIG_WEP */
 
 	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
 		bss->rsn_pairwise = bss->wpa_pairwise;
@@ -1366,6 +1401,7 @@
 	} else if (bss->ieee802_1x) {
 		int cipher = WPA_CIPHER_NONE;
 		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+#ifdef CONFIG_WEP
 		bss->ssid.wep.default_len = bss->default_wep_key_len;
 		if (full_config && bss->default_wep_key_len) {
 			cipher = bss->default_wep_key_len >= 13 ?
@@ -1376,11 +1412,13 @@
 			else
 				cipher = WPA_CIPHER_WEP40;
 		}
+#endif /* CONFIG_WEP */
 		bss->wpa_group = cipher;
 		bss->wpa_pairwise = cipher;
 		bss->rsn_pairwise = cipher;
 		if (full_config)
 			bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+#ifdef CONFIG_WEP
 	} else if (bss->ssid.wep.keys_set) {
 		int cipher = WPA_CIPHER_WEP40;
 		if (bss->ssid.wep.len[0] >= 13)
@@ -1391,6 +1429,7 @@
 		bss->rsn_pairwise = cipher;
 		if (full_config)
 			bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+#endif /* CONFIG_WEP */
 	} else if (bss->osen) {
 		bss->ssid.security_policy = SECURITY_OSEN;
 		bss->wpa_group = WPA_CIPHER_CCMP;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 83b8aee..2a0bf07 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -67,6 +67,7 @@
 struct ft_remote_r0kh;
 struct ft_remote_r1kh;
 
+#ifdef CONFIG_WEP
 #define NUM_WEP_KEYS 4
 struct hostapd_wep_keys {
 	u8 idx;
@@ -75,10 +76,13 @@
 	int keys_set;
 	size_t default_len; /* key length used for dynamic key generation */
 };
+#endif /* CONFIG_WEP */
 
 typedef enum hostap_security_policy {
 	SECURITY_PLAINTEXT = 0,
+#ifdef CONFIG_WEP
 	SECURITY_STATIC_WEP = 1,
+#endif /* CONFIG_WEP */
 	SECURITY_IEEE_802_1X = 2,
 	SECURITY_WPA_PSK = 3,
 	SECURITY_WPA = 4,
@@ -88,6 +92,7 @@
 struct hostapd_ssid {
 	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
+	u32 short_ssid;
 	unsigned int ssid_set:1;
 	unsigned int utf8_ssid:1;
 	unsigned int wpa_passphrase_set:1;
@@ -101,7 +106,9 @@
 	char *wpa_psk_file;
 	struct sae_pt *pt;
 
+#ifdef CONFIG_WEP
 	struct hostapd_wep_keys wep;
+#endif /* CONFIG_WEP */
 
 #define DYNAMIC_VLAN_DISABLED 0
 #define DYNAMIC_VLAN_OPTIONAL 1
@@ -151,6 +158,7 @@
 	struct hostapd_wpa_psk *next;
 	int group;
 	char keyid[KEYID_LEN];
+	int wps;
 	u8 psk[PMK_LEN];
 	u8 addr[ETH_ALEN];
 	u8 p2p_dev_addr[ETH_ALEN];
@@ -319,10 +327,12 @@
 	size_t eap_req_id_text_len;
 	int eapol_key_index_workaround;
 
+#ifdef CONFIG_WEP
 	size_t default_wep_key_len;
 	int individual_wep_key_len;
 	int wep_rekeying_period;
 	int broadcast_key_idx_min, broadcast_key_idx_max;
+#endif /* CONFIG_WEP */
 	int eap_reauth_period;
 	int erp_send_reauth_start;
 	char *erp_domain;
@@ -344,9 +354,11 @@
 			* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
 
 	int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+	int extended_key_id;
 	int wpa_key_mgmt;
 	enum mfp_options ieee80211w;
 	int group_mgmt_cipher;
+	int beacon_prot;
 	/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
 	unsigned int assoc_sa_query_max_timeout;
 	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
@@ -367,6 +379,7 @@
 	int wpa_strict_rekey;
 	int wpa_gmk_rekey;
 	int wpa_ptk_rekey;
+	enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
 	u32 wpa_group_update_count;
 	u32 wpa_pairwise_update_count;
 	int wpa_disable_eapol_key_retries;
@@ -497,6 +510,7 @@
 	char *model_url;
 	char *upc;
 	struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+	struct wpabuf *wps_application_ext;
 	int wps_nfc_pw_from_config;
 	int wps_nfc_dev_pw_id;
 	struct wpabuf *wps_nfc_dh_pubkey;
@@ -664,7 +678,14 @@
 	struct wpabuf *own_ie_override;
 	int sae_reflection_attack;
 	struct wpabuf *sae_commit_override;
+	struct wpabuf *rsne_override_eapol;
 	struct wpabuf *rsnxe_override_eapol;
+	struct wpabuf *rsne_override_ft;
+	struct wpabuf *rsnxe_override_ft;
+	struct wpabuf *gtk_rsc_override;
+	struct wpabuf *igtk_rsc_override;
+	int no_beacon_rsnxe;
+	int skip_prune_assoc;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #define MESH_ENABLED BIT(0)
@@ -720,6 +741,8 @@
 	struct wpabuf *dpp_csign;
 #ifdef CONFIG_DPP2
 	struct dpp_controller_conf *dpp_controller;
+	int dpp_configurator_connectivity;
+	int dpp_pfs;
 #endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
 
@@ -729,12 +752,15 @@
 	size_t owe_transition_ssid_len;
 	char owe_transition_ifname[IFNAMSIZ + 1];
 	int *owe_groups;
+	int owe_ptk_workaround;
 #endif /* CONFIG_OWE */
 
 	int coloc_intf_reporting;
 
 	u8 send_probe_response;
 
+	u8 transition_disable;
+
 #define BACKHAUL_BSS 1
 #define FRONTHAUL_BSS 2
 	int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
@@ -848,6 +874,8 @@
  */
 struct he_operation {
 	u8 he_bss_color;
+	u8 he_bss_color_disabled;
+	u8 he_bss_color_partial;
 	u8 he_default_pe_duration;
 	u8 he_twt_required;
 	u16 he_rts_threshold;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 7585866..1f284f0 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -588,7 +588,7 @@
 int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
 			  int total_flags, int flags_or, int flags_and)
 {
-	if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+	if (!hapd->driver || !hapd->drv_priv || !hapd->driver->sta_set_flags)
 		return 0;
 	return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
 					   flags_or, flags_and);
@@ -680,36 +680,41 @@
 
 int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
 			enum wpa_alg alg, const u8 *addr,
-			int key_idx, int set_tx,
+			int key_idx, int vlan_id, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
+			const u8 *key, size_t key_len, enum key_flag key_flag)
 {
+	struct wpa_driver_set_key_params params;
+
 	if (hapd->driver == NULL || hapd->driver->set_key == NULL)
 		return 0;
-	return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
-				     key_idx, set_tx, seq, seq_len, key,
-				     key_len);
+
+	os_memset(&params, 0, sizeof(params));
+	params.ifname = ifname;
+	params.alg = alg;
+	params.addr = addr;
+	params.key_idx = key_idx;
+	params.set_tx = set_tx;
+	params.seq = seq;
+	params.seq_len = seq_len;
+	params.key = key;
+	params.key_len = key_len;
+	params.vlan_id = vlan_id;
+	params.key_flag = key_flag;
+
+	return hapd->driver->set_key(hapd->drv_priv, &params);
 }
 
 
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
-			  const void *msg, size_t len, int noack)
+			  const void *msg, size_t len, int noack,
+			  const u16 *csa_offs, size_t csa_offs_len,
+			  int no_encrypt)
 {
 	if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
-				       NULL, 0);
-}
-
-
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
-			      const void *msg, size_t len, int noack,
-			      const u16 *csa_offs, size_t csa_offs_len)
-{
-	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
-		return 0;
-	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
-				       csa_offs, csa_offs_len);
+				       csa_offs, csa_offs_len, no_encrypt, 0);
 }
 
 
@@ -933,6 +938,7 @@
 	}
 
 	params.freq_list = freq_list;
+	params.edmg_enabled = hapd->iface->conf->enable_edmg;
 
 	params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
 	params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index fa413df..56d1ad8 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -89,14 +89,13 @@
 int hostapd_drv_set_key(const char *ifname,
 			struct hostapd_data *hapd,
 			enum wpa_alg alg, const u8 *addr,
-			int key_idx, int set_tx,
+			int key_idx, int vlan_id, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len);
+			const u8 *key, size_t key_len, enum key_flag key_flag);
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
-			  const void *msg, size_t len, int noack);
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
-			      const void *msg, size_t len, int noack,
-			      const u16 *csa_offs, size_t csa_offs_len);
+			  const void *msg, size_t len, int noack,
+			  const u16 *csa_offs, size_t csa_offs_len,
+			  int no_encrypt);
 int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
 			   const u8 *addr, int reason);
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 8bf6dde..20be7f8 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -228,7 +228,6 @@
 		set_beacon++;
 	}
 
-#ifdef CONFIG_IEEE80211N
 	if (!iface->olbc_ht && !ap->ht_support &&
 	    (ap->channel == 0 ||
 	     ap->channel == iface->conf->channel ||
@@ -241,7 +240,6 @@
 			   MAC2STR(ap->addr), ap->channel);
 		set_beacon++;
 	}
-#endif /* CONFIG_IEEE80211N */
 
 	if (set_beacon)
 		ieee802_11_update_beacons(iface);
@@ -285,14 +283,12 @@
 			iface->olbc = 0;
 			set_beacon++;
 		}
-#ifdef CONFIG_IEEE80211N
 		if (!olbc_ht && iface->olbc_ht) {
 			wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
 			iface->olbc_ht = 0;
 			hostapd_ht_operation_update(iface);
 			set_beacon++;
 		}
-#endif /* CONFIG_IEEE80211N */
 	}
 
 	if (set_beacon)
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 331c09b..47ced9a 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -36,27 +36,6 @@
 
 #ifdef NEED_AP_MLME
 
-static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
-					 size_t len)
-{
-	size_t i;
-
-	for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
-		if (hapd->conf->radio_measurements[i])
-			break;
-	}
-
-	if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
-		return eid;
-
-	*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
-	*eid++ = RRM_CAPABILITIES_IE_LEN;
-	os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
-
-	return eid + RRM_CAPABILITIES_IE_LEN;
-}
-
-
 static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
 {
 	if (len < 2 + 5)
@@ -287,17 +266,101 @@
 }
 
 
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+{
+	const u8 *ies;
+	size_t ies_len;
+
+	ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+	if (!ies)
+		return NULL;
+
+	return get_ie(ies, ies_len, eid);
+}
+
+
+static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
+					u32 vendor_type)
+{
+	const u8 *ies;
+	size_t ies_len;
+
+	ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+	if (!ies)
+		return NULL;
+
+	return get_vendor_ie(ies, ies_len, vendor_type);
+}
+
+
+static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
 {
 	const u8 *ie;
-	size_t ielen;
 
-	ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
-	if (ie == NULL || ielen > len)
-		return eid;
+	ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
+	if (!ie || 2U + ie[1] > len)
+		return pos;
 
-	os_memcpy(eid, ie, ielen);
-	return eid + ielen;
+	os_memcpy(pos, ie, 2 + ie[1]);
+	return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+	const u8 *ie;
+
+	ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+	if (!ie || 2U + ie[1] > len)
+		return pos;
+
+	os_memcpy(pos, ie, 2 + ie[1]);
+	return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+	const u8 *ie;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->conf->no_beacon_rsnxe) {
+		wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
+		return pos;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+	ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+	if (!ie || 2U + ie[1] > len)
+		return pos;
+
+	os_memcpy(pos, ie, 2 + ie[1]);
+	return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+	const u8 *ie;
+
+	ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
+	if (!ie || 2U + ie[1] > len)
+		return pos;
+
+	os_memcpy(pos, ie, 2 + ie[1]);
+	return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+	const u8 *ie;
+
+	ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
+	if (!ie || 2U + ie[1] > len)
+		return pos;
+
+	os_memcpy(pos, ie, 2 + ie[1]);
+	return pos + 2 + ie[1];
 }
 
 
@@ -405,6 +468,7 @@
 
 	buflen += hostapd_mbo_ie_len(hapd);
 	buflen += hostapd_eid_owe_trans_len(hapd);
+	buflen += hostapd_eid_dpp_cc_len(hapd);
 
 	resp = os_zalloc(buflen);
 	if (resp == NULL)
@@ -455,14 +519,10 @@
 	/* Extended supported rates */
 	pos = hostapd_eid_ext_supp_rates(hapd, pos);
 
-	/* RSN, MDIE */
-	if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
-	      (hapd->conf->osen && !hapd->conf->wpa)))
-		pos = hostapd_eid_wpa(hapd, pos, epos - pos);
-
+	pos = hostapd_get_rsne(hapd, pos, epos - pos);
 	pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
-
 	pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+	pos = hostapd_get_mde(hapd, pos, epos - pos);
 
 	/* eCSA IE */
 	csa_pos = hostapd_eid_ecsa(hapd, pos);
@@ -471,15 +531,8 @@
 	pos = csa_pos;
 
 	pos = hostapd_eid_supported_op_classes(hapd, pos);
-
-#ifdef CONFIG_IEEE80211N
-	/* Secondary Channel Offset element */
-	/* TODO: The standard doesn't specify a position for this element. */
-	pos = hostapd_eid_secondary_channel(hapd, pos);
-
 	pos = hostapd_eid_ht_capabilities(hapd, pos);
 	pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
 
 	pos = hostapd_eid_ext_capab(hapd, pos);
 
@@ -509,13 +562,14 @@
 #endif /* CONFIG_IEEE80211AC */
 
 	pos = hostapd_eid_fils_indic(hapd, pos, 0);
+	pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
 
 #ifdef CONFIG_IEEE80211AX
 	if (hapd->iconf->ieee80211ax) {
 		pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
 		pos = hostapd_eid_he_operation(hapd, pos);
-		pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
 		pos = hostapd_eid_spatial_reuse(hapd, pos);
+		pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
 	}
 #endif /* CONFIG_IEEE80211AX */
 
@@ -524,10 +578,9 @@
 		pos = hostapd_eid_vendor_vht(hapd, pos);
 #endif /* CONFIG_IEEE80211AC */
 
-	/* WPA */
-	if (hapd->conf->wpa == WPA_PROTO_WPA ||
-	    (hapd->conf->osen && !hapd->conf->wpa))
-		pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+	/* WPA / OSEN */
+	pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
+	pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
 
 	/* Wi-Fi Alliance WMM */
 	pos = hostapd_eid_wmm(hapd, pos);
@@ -560,6 +613,7 @@
 
 	pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
 	pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
+	pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos);
 
 	if (hapd->conf->vendor_elements) {
 		os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
@@ -581,7 +635,9 @@
 static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
 					 const u8 *ssid, size_t ssid_len,
 					 const u8 *ssid_list,
-					 size_t ssid_list_len)
+					 size_t ssid_list_len,
+					 const u8 *short_ssid_list,
+					 size_t short_ssid_list_len)
 {
 	const u8 *pos, *end;
 	int wildcard = 0;
@@ -592,20 +648,30 @@
 	    os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
 		return EXACT_SSID_MATCH;
 
-	if (ssid_list == NULL)
-		return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+	if (ssid_list) {
+		pos = ssid_list;
+		end = ssid_list + ssid_list_len;
+		while (end - pos >= 2) {
+			if (2 + pos[1] > end - pos)
+				break;
+			if (pos[1] == 0)
+				wildcard = 1;
+			if (pos[1] == hapd->conf->ssid.ssid_len &&
+			    os_memcmp(pos + 2, hapd->conf->ssid.ssid,
+				      pos[1]) == 0)
+				return EXACT_SSID_MATCH;
+			pos += 2 + pos[1];
+		}
+	}
 
-	pos = ssid_list;
-	end = ssid_list + ssid_list_len;
-	while (end - pos >= 2) {
-		if (2 + pos[1] > end - pos)
-			break;
-		if (pos[1] == 0)
-			wildcard = 1;
-		if (pos[1] == hapd->conf->ssid.ssid_len &&
-		    os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
-			return EXACT_SSID_MATCH;
-		pos += 2 + pos[1];
+	if (short_ssid_list) {
+		pos = short_ssid_list;
+		end = short_ssid_list + short_ssid_list_len;
+		while (end - pos >= 4) {
+			if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
+				return EXACT_SSID_MATCH;
+			pos += 4;
+		}
 	}
 
 	return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
@@ -743,11 +809,7 @@
 	int ret;
 	u16 csa_offs[2];
 	size_t csa_offs_len;
-	u32 session_timeout, acct_interim_interval;
-	struct vlan_description vlan_id;
-	struct hostapd_sta_wpa_psk_short *psk = NULL;
-	char *identity = NULL;
-	char *radius_cui = NULL;
+	struct radius_sta rad_info;
 
 	if (len < IEEE80211_HDRLEN)
 		return;
@@ -756,10 +818,8 @@
 		sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
 	ie_len = len - IEEE80211_HDRLEN;
 
-	ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
-					 &session_timeout,
-					 &acct_interim_interval, &vlan_id,
-					 &psk, &identity, &radius_cui, 1);
+	ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+				      &rad_info, 1);
 	if (ret == HOSTAPD_ACL_REJECT) {
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 			"Ignore Probe Request frame from " MACSTR
@@ -838,7 +898,7 @@
 #endif /* CONFIG_P2P */
 
 	if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
-	    elems.ssid_list_len == 0) {
+	    elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
 		wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
 			   "broadcast SSID ignored", MAC2STR(mgmt->sa));
 		return;
@@ -870,7 +930,8 @@
 #endif /* CONFIG_TAXONOMY */
 
 	res = ssid_match(hapd, elems.ssid, elems.ssid_len,
-			 elems.ssid_list, elems.ssid_list_len);
+			 elems.ssid_list, elems.ssid_list_len,
+			 elems.short_ssid_list, elems.short_ssid_list_len);
 	if (res == NO_SSID_MATCH) {
 		if (!(mgmt->da[0] & 0x01)) {
 			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
@@ -883,6 +944,12 @@
 		return;
 	}
 
+	if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
+		wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+			   "broadcast SSID ignored", MAC2STR(mgmt->sa));
+		return;
+	}
+
 #ifdef CONFIG_INTERWORKING
 	if (hapd->conf->interworking &&
 	    elems.interworking && elems.interworking_len >= 1) {
@@ -987,9 +1054,9 @@
 				hapd->cs_c_off_ecsa_proberesp;
 	}
 
-	ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
-					csa_offs_len ? csa_offs : NULL,
-					csa_offs_len);
+	ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
+				    csa_offs_len ? csa_offs : NULL,
+				    csa_offs_len, 0);
 
 	if (ret < 0)
 		wpa_printf(MSG_INFO, "handle_probe_req: send failed");
@@ -1060,7 +1127,7 @@
 	size_t resp_len = 0;
 #ifdef NEED_AP_MLME
 	u16 capab_info;
-	u8 *pos, *tailpos, *csa_pos;
+	u8 *pos, *tailpos, *tailend, *csa_pos;
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -1099,6 +1166,7 @@
 
 	tail_len += hostapd_mbo_ie_len(hapd);
 	tail_len += hostapd_eid_owe_trans_len(hapd);
+	tail_len += hostapd_eid_dpp_cc_len(hapd);
 
 	tailpos = tail = os_malloc(tail_len);
 	if (head == NULL || tail == NULL) {
@@ -1107,6 +1175,7 @@
 		os_free(tail);
 		return -1;
 	}
+	tailend = tail + tail_len;
 
 	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
 					   WLAN_FC_STYPE_BEACON);
@@ -1147,8 +1216,7 @@
 
 	head_len = pos - (u8 *) head;
 
-	tailpos = hostapd_eid_country(hapd, tailpos,
-				      tail + BEACON_TAIL_BUF_SIZE - tailpos);
+	tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
 
 	/* Power Constraint element */
 	tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
@@ -1165,19 +1233,11 @@
 	/* Extended supported rates */
 	tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
 
-	/* RSN, MDIE */
-	if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
-	      (hapd->conf->osen && !hapd->conf->wpa)))
-		tailpos = hostapd_eid_wpa(hapd, tailpos,
-					  tail + BEACON_TAIL_BUF_SIZE -
-					  tailpos);
-
+	tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
+	tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
 	tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
-					       tail + BEACON_TAIL_BUF_SIZE -
-					       tailpos);
-
-	tailpos = hostapd_eid_bss_load(hapd, tailpos,
-				       tail + BEACON_TAIL_BUF_SIZE - tailpos);
+					       tailend - tailpos);
+	tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
 
 	/* eCSA IE */
 	csa_pos = hostapd_eid_ecsa(hapd, tailpos);
@@ -1186,15 +1246,8 @@
 	tailpos = csa_pos;
 
 	tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
-
-#ifdef CONFIG_IEEE80211N
-	/* Secondary Channel Offset element */
-	/* TODO: The standard doesn't specify a position for this element. */
-	tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
-
 	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
 	tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-#endif /* CONFIG_IEEE80211N */
 
 	tailpos = hostapd_eid_ext_capab(hapd, tailpos);
 
@@ -1226,14 +1279,15 @@
 #endif /* CONFIG_IEEE80211AC */
 
 	tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+	tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
 
 #ifdef CONFIG_IEEE80211AX
 	if (hapd->iconf->ieee80211ax) {
 		tailpos = hostapd_eid_he_capab(hapd, tailpos,
 					       IEEE80211_MODE_AP);
 		tailpos = hostapd_eid_he_operation(hapd, tailpos);
-		tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
 		tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
+		tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
 	}
 #endif /* CONFIG_IEEE80211AX */
 
@@ -1242,12 +1296,9 @@
 		tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AC */
 
-	/* WPA */
-	if (hapd->conf->wpa == WPA_PROTO_WPA ||
-	    (hapd->conf->osen && !hapd->conf->wpa))
-		tailpos = hostapd_eid_wpa(hapd, tailpos,
-					  tail + BEACON_TAIL_BUF_SIZE -
-					  tailpos);
+	/* WPA / OSEN */
+	tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
+	tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
 
 	/* Wi-Fi Alliance WMM */
 	tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1280,6 +1331,7 @@
 	tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
 	tailpos = hostapd_eid_owe_trans(hapd, tailpos,
 					tail + tail_len - tailpos);
+	tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
 
 	if (hapd->conf->vendor_elements) {
 		os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
@@ -1318,10 +1370,13 @@
 	params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
 	params->auth_algs = hapd->conf->auth_algs;
 	params->wpa_version = hapd->conf->wpa;
-	params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+	params->privacy = hapd->conf->wpa;
+#ifdef CONFIG_WEP
+	params->privacy |= hapd->conf->ssid.wep.keys_set ||
 		(hapd->conf->ieee802_1x &&
 		 (hapd->conf->default_wep_key_len ||
 		  hapd->conf->individual_wep_key_len));
+#endif /* CONFIG_WEP */
 	switch (hapd->conf->ignore_broadcast_ssid) {
 	case 0:
 		params->hide_ssid = NO_SSID_HIDING;
@@ -1334,7 +1389,6 @@
 		break;
 	}
 	params->isolate = hapd->conf->isolate;
-	params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
 #ifdef NEED_AP_MLME
 	params->cts_protect = !!(ieee802_11_erp_info(hapd) &
 				ERP_INFO_USE_PROTECTION);
@@ -1430,6 +1484,13 @@
 		hapd->iface->conf->spr.srg_obss_pd_min_offset;
 	params.he_spr_srg_obss_pd_max_offset =
 		hapd->iface->conf->spr.srg_obss_pd_max_offset;
+	params.he_bss_color_disabled =
+		hapd->iface->conf->he_op.he_bss_color_disabled;
+	params.he_bss_color_partial =
+		hapd->iface->conf->he_op.he_bss_color_partial;
+	params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
+	params.twt_responder = hostapd_get_he_twt_responder(hapd,
+							    IEEE80211_MODE_AP);
 #endif /* CONFIG_IEEE80211AX */
 	hapd->reenable_beacon = 0;
 
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 9fd1b81..ef53a82 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -345,7 +345,6 @@
 	}
 #endif /* CONFIG_IEEE80211AC */
 
-#ifdef CONFIG_IEEE80211N
 	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
 		res = os_snprintf(buf + len, buflen - len,
 				  "ht_caps_info=0x%04x\n",
@@ -354,7 +353,6 @@
 		if (!os_snprintf_error(buflen - len, res))
 			len += res;
 	}
-#endif /* CONFIG_IEEE80211N */
 
 	if (sta->ext_capability &&
 	    buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
@@ -462,9 +460,6 @@
 	int ret;
 	u8 *pos;
 
-	if (!hapd->drv_priv || !hapd->driver->send_frame)
-		return -1;
-
 	mgmt = os_zalloc(sizeof(*mgmt) + 100);
 	if (mgmt == NULL)
 		return -1;
@@ -498,8 +493,8 @@
 	pos += 2;
 	*pos++ = minor_reason_code;
 
-	ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
-				       pos - (u8 *) mgmt, 1);
+	ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
+				    0);
 	os_free(mgmt);
 
 	return ret < 0 ? -1 : 0;
@@ -529,8 +524,7 @@
 	if (pos) {
 		struct ieee80211_mgmt mgmt;
 		int encrypt;
-		if (!hapd->drv_priv || !hapd->driver->send_frame)
-			return -1;
+
 		pos += 6;
 		encrypt = atoi(pos);
 		os_memset(&mgmt, 0, sizeof(mgmt));
@@ -540,10 +534,10 @@
 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
 		mgmt.u.deauth.reason_code = host_to_le16(reason);
-		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-					     IEEE80211_HDRLEN +
-					     sizeof(mgmt.u.deauth),
-					     encrypt) < 0)
+		if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+					  IEEE80211_HDRLEN +
+					  sizeof(mgmt.u.deauth),
+					  0, NULL, 0, !encrypt) < 0)
 			return -1;
 		return 0;
 	}
@@ -592,8 +586,7 @@
 	if (pos) {
 		struct ieee80211_mgmt mgmt;
 		int encrypt;
-		if (!hapd->drv_priv || !hapd->driver->send_frame)
-			return -1;
+
 		pos += 6;
 		encrypt = atoi(pos);
 		os_memset(&mgmt, 0, sizeof(mgmt));
@@ -603,10 +596,10 @@
 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
 		mgmt.u.disassoc.reason_code = host_to_le16(reason);
-		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-					     IEEE80211_HDRLEN +
-					     sizeof(mgmt.u.deauth),
-					     encrypt) < 0)
+		if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+					  IEEE80211_HDRLEN +
+					  sizeof(mgmt.u.deauth),
+					  0, NULL, 0, !encrypt) < 0)
 			return -1;
 		return 0;
 	}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index f70ecc9..3c078b9 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -144,30 +144,44 @@
 	int i;
 	u32 bw = num_chan_to_bw(num_chans);
 
-	if (first_chan_idx + num_chans > mode->num_channels)
+	if (first_chan_idx + num_chans > mode->num_channels) {
+		wpa_printf(MSG_DEBUG,
+			   "DFS: some channels in range not defined");
 		return 0;
+	}
 
 	first_chan = &mode->channels[first_chan_idx];
 
 	/* hostapd DFS implementation assumes the first channel as primary.
 	 * If it's not allowed to use the first channel as primary, decline the
 	 * whole channel range. */
-	if (!chan_pri_allowed(first_chan))
+	if (!chan_pri_allowed(first_chan)) {
+		wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
 		return 0;
+	}
 
 	for (i = 0; i < num_chans; i++) {
 		chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
 					 first_chan_idx);
-		if (!chan)
+		if (!chan) {
+			wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
+				   first_chan->freq + i * 20);
 			return 0;
+		}
 
 		/* HT 40 MHz secondary channel availability checked only for
 		 * primary channel */
-		if (!chan_bw_allowed(chan, bw, 1, !i))
+		if (!chan_bw_allowed(chan, bw, 1, !i)) {
+			wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
+				   first_chan->freq + i * 20);
 			return 0;
+		}
 
-		if (!dfs_channel_available(chan, skip_radar))
+		if (!dfs_channel_available(chan, skip_radar)) {
+			wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
+				   first_chan->freq + i * 20);
 			return 0;
+		}
 	}
 
 	return 1;
@@ -210,22 +224,36 @@
 		if (iface->conf->ieee80211n &&
 		    iface->conf->secondary_channel &&
 		    (!dfs_is_chan_allowed(chan, n_chans) ||
-		     !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
+		     !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
+			wpa_printf(MSG_DEBUG,
+				   "DFS: channel %d (%d) is incompatible",
+				   chan->freq, chan->chan);
 			continue;
+		}
 
 		/* Skip incompatible chandefs */
-		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
+		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
+			wpa_printf(MSG_DEBUG,
+				   "DFS: range not available for %d (%d)",
+				   chan->freq, chan->chan);
 			continue;
+		}
 
-		if (!is_in_chanlist(iface, chan))
+		if (!is_in_chanlist(iface, chan)) {
+			wpa_printf(MSG_DEBUG,
+				   "DFS: channel %d (%d) not in chanlist",
+				   chan->freq, chan->chan);
 			continue;
+		}
 
 		if (ret_chan && idx == channel_idx) {
-			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+			wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
+				   chan->freq, chan->chan);
 			*ret_chan = chan;
 			return idx;
 		}
-		wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+		wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
+			   chan->freq, chan->chan);
 		channel_idx++;
 	}
 	return channel_idx;
@@ -235,6 +263,7 @@
 static void dfs_adjust_center_freq(struct hostapd_iface *iface,
 				   struct hostapd_channel_data *chan,
 				   int secondary_channel,
+				   int sec_chan_idx_80p80,
 				   u8 *oper_centr_freq_seg0_idx,
 				   u8 *oper_centr_freq_seg1_idx)
 {
@@ -261,8 +290,14 @@
 	case CHANWIDTH_160MHZ:
 		*oper_centr_freq_seg0_idx = chan->chan + 14;
 		break;
+	case CHANWIDTH_80P80MHZ:
+		*oper_centr_freq_seg0_idx = chan->chan + 6;
+		*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
+		break;
+
 	default:
-		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
+		wpa_printf(MSG_INFO,
+			   "DFS: Unsupported channel width configuration");
 		*oper_centr_freq_seg0_idx = 0;
 		break;
 	}
@@ -441,8 +476,11 @@
 {
 	struct hostapd_hw_modes *mode;
 	struct hostapd_channel_data *chan = NULL;
+	struct hostapd_channel_data *chan2 = NULL;
 	int num_available_chandefs;
-	int chan_idx;
+	int chan_idx, chan_idx2;
+	int sec_chan_idx_80p80 = -1;
+	int i;
 	u32 _rand;
 
 	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
@@ -459,6 +497,8 @@
 
 	/* Get the count first */
 	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+	wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
+		   num_available_chandefs);
 	if (num_available_chandefs == 0)
 		return NULL;
 
@@ -466,6 +506,12 @@
 		return NULL;
 	chan_idx = _rand % num_available_chandefs;
 	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+	if (!chan) {
+		wpa_printf(MSG_DEBUG, "DFS: no random channel found");
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
+		   chan->freq, chan->chan);
 
 	/* dfs_find_channel() calculations assume HT40+ */
 	if (iface->conf->secondary_channel)
@@ -473,8 +519,45 @@
 	else
 		*secondary_channel = 0;
 
+	/* Get secondary channel for HT80P80 */
+	if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
+		if (num_available_chandefs <= 1) {
+			wpa_printf(MSG_ERROR,
+				   "only 1 valid chan, can't support 80+80");
+			return NULL;
+		}
+
+		/*
+		 * Loop all channels except channel1 to find a valid channel2
+		 * that is not adjacent to channel1.
+		 */
+		for (i = 0; i < num_available_chandefs - 1; i++) {
+			/* start from chan_idx + 1, end when chan_idx - 1 */
+			chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
+			dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
+			if (chan2 && abs(chan2->chan - chan->chan) > 12) {
+				/* two channels are not adjacent */
+				sec_chan_idx_80p80 = chan2->chan;
+				wpa_printf(MSG_DEBUG,
+					   "DFS: got second chan: %d (%d)",
+					   chan2->freq, chan2->chan);
+				break;
+			}
+		}
+
+		/* Check if we got a valid secondary channel which is not
+		 * adjacent to the first channel.
+		 */
+		if (sec_chan_idx_80p80 == -1) {
+			wpa_printf(MSG_INFO,
+				   "DFS: failed to get chan2 for 80+80");
+			return NULL;
+		}
+	}
+
 	dfs_adjust_center_freq(iface, chan,
 			       *secondary_channel,
+			       sec_chan_idx_80p80,
 			       oper_centr_freq_seg0_idx,
 			       oper_centr_freq_seg1_idx);
 
@@ -773,7 +856,7 @@
 }
 
 
-static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
 {
 	int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
 
@@ -821,7 +904,7 @@
 			 * another radio.
 			 */
 			if (iface->state != HAPD_IFACE_ENABLED &&
-			    hostapd_config_dfs_chan_available(iface)) {
+			    hostapd_is_dfs_chan_available(iface)) {
 				hostapd_setup_interface_complete(iface, 0);
 				iface->cac_started = 0;
 			}
@@ -851,6 +934,41 @@
 }
 
 
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+			u8 *oper_centr_freq_seg0_idx,
+			u8 *oper_centr_freq_seg1_idx, int *skip_radar)
+{
+	struct hostapd_channel_data *channel;
+
+	for (;;) {
+		channel = dfs_get_valid_channel(iface, secondary_channel,
+						oper_centr_freq_seg0_idx,
+						oper_centr_freq_seg1_idx,
+						*skip_radar);
+		if (channel) {
+			wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
+				   channel->chan);
+			return channel;
+		}
+
+		if (*skip_radar) {
+			*skip_radar = 0;
+		} else {
+			if (iface->conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+				break;
+			*skip_radar = 1;
+			iface->conf->vht_oper_chwidth--;
+		}
+	}
+
+	wpa_printf(MSG_INFO,
+		   "%s: no DFS channels left, waiting for NOP to finish",
+		   __func__);
+	return NULL;
+}
+
+
 static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
 {
 	struct hostapd_channel_data *channel;
@@ -868,8 +986,14 @@
 					skip_radar);
 
 	if (!channel) {
-		wpa_printf(MSG_ERROR, "No valid channel available");
-		return err;
+		channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+						  &oper_centr_freq_seg0_idx,
+						  &oper_centr_freq_seg1_idx,
+						  &skip_radar);
+		if (!channel) {
+			wpa_printf(MSG_ERROR, "No valid channel available");
+			return err;
+		}
 	}
 
 	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -898,11 +1022,13 @@
 	int secondary_channel;
 	u8 oper_centr_freq_seg0_idx;
 	u8 oper_centr_freq_seg1_idx;
+	u8 new_vht_oper_chwidth;
 	int skip_radar = 1;
 	struct csa_settings csa_settings;
 	unsigned int i;
 	int err = 1;
 	struct hostapd_hw_modes *cmode = iface->current_mode;
+	u8 current_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
 
 	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
 		   __func__, iface->cac_started ? "yes" : "no",
@@ -936,28 +1062,25 @@
 		 * requires to perform a CAC first.
 		 */
 		skip_radar = 0;
-		channel = dfs_get_valid_channel(iface, &secondary_channel,
-						&oper_centr_freq_seg0_idx,
-						&oper_centr_freq_seg1_idx,
-						skip_radar);
-		if (!channel) {
-			wpa_printf(MSG_INFO,
-				   "%s: no DFS channels left, waiting for NOP to finish",
-				   __func__);
+		channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+						  &oper_centr_freq_seg0_idx,
+						  &oper_centr_freq_seg1_idx,
+						  &skip_radar);
+		if (!channel)
 			return err;
+		if (!skip_radar) {
+			iface->freq = channel->freq;
+			iface->conf->channel = channel->chan;
+			iface->conf->secondary_channel = secondary_channel;
+			hostapd_set_oper_centr_freq_seg0_idx(
+				iface->conf, oper_centr_freq_seg0_idx);
+			hostapd_set_oper_centr_freq_seg1_idx(
+				iface->conf, oper_centr_freq_seg1_idx);
+
+			hostapd_disable_iface(iface);
+			hostapd_enable_iface(iface);
+			return 0;
 		}
-
-		iface->freq = channel->freq;
-		iface->conf->channel = channel->chan;
-		iface->conf->secondary_channel = secondary_channel;
-		hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
-						     oper_centr_freq_seg0_idx);
-		hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
-						     oper_centr_freq_seg1_idx);
-
-		hostapd_disable_iface(iface);
-		hostapd_enable_iface(iface);
-		return 0;
 	}
 
 	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -966,6 +1089,9 @@
 		"freq=%d chan=%d sec_chan=%d", channel->freq,
 		channel->chan, secondary_channel);
 
+	new_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
+	iface->conf->vht_oper_chwidth = current_vht_oper_chwidth;
+
 	/* Setup CSA request */
 	os_memset(&csa_settings, 0, sizeof(csa_settings));
 	csa_settings.cs_count = 5;
@@ -980,7 +1106,7 @@
 				      iface->conf->ieee80211ac,
 				      iface->conf->ieee80211ax,
 				      secondary_channel,
-				      hostapd_get_oper_chwidth(iface->conf),
+				      new_vht_oper_chwidth,
 				      oper_centr_freq_seg0_idx,
 				      oper_centr_freq_seg1_idx,
 				      cmode->vht_capab,
@@ -1004,6 +1130,7 @@
 		iface->freq = channel->freq;
 		iface->conf->channel = channel->chan;
 		iface->conf->secondary_channel = secondary_channel;
+		iface->conf->vht_oper_chwidth = new_vht_oper_chwidth;
 		hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
 						     oper_centr_freq_seg0_idx);
 		hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
@@ -1040,8 +1167,10 @@
 		return 0;
 
 	/* mark radar frequency as invalid */
-	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
-		      cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+	res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+			    cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+	if (!res)
+		return 0;
 
 	/* Skip if reported radar event not overlapped our channels */
 	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
@@ -1161,3 +1290,56 @@
 		   __func__, iface->freq);
 	return 2;
 }
+
+
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+			   int center_freq)
+{
+	struct hostapd_channel_data *chan;
+	struct hostapd_hw_modes *mode = iface->current_mode;
+	int half_width;
+	int res = 0;
+	int i;
+
+	if (!iface->conf->ieee80211h || !mode ||
+	    mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 0;
+
+	switch (width) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		half_width = 10;
+		break;
+	case CHAN_WIDTH_40:
+		half_width = 20;
+		break;
+	case CHAN_WIDTH_80:
+	case CHAN_WIDTH_80P80:
+		half_width = 40;
+		break;
+	case CHAN_WIDTH_160:
+		half_width = 80;
+		break;
+	default:
+		wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
+			   width);
+		return 0;
+	}
+
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
+
+		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+			continue;
+
+		if (center_freq - chan->freq < half_width &&
+		    chan->freq - center_freq < half_width)
+			res++;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
+		   center_freq - half_width, center_freq + half_width,
+		   res ? "yes" : "no");
+
+	return res;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index f0fa6f6..606c1b3 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -25,9 +25,12 @@
 			     int ht_enabled,
 			     int chan_offset, int chan_width, int cf1, int cf2);
 int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface);
 int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
 			  int ht_enabled, int chan_offset, int chan_width,
 			  int cf1, int cf2);
 int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+			   int center_freq);
 
 #endif /* DFS_H */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index ed37fc8..edc77da 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -39,22 +39,22 @@
 	const u8 *end, *pos;
 	int res, msgtype = 0, prefixlen = 32;
 	u32 subnet_mask = 0;
-	u16 tot_len;
+	u16 ip_len;
 
 	exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
 	if (exten_len < 4)
 		return;
 
 	b = (const struct bootp_pkt *) &buf[ETH_HLEN];
-	tot_len = ntohs(b->iph.tot_len);
-	if (tot_len > (unsigned int) (len - ETH_HLEN))
+	ip_len = ntohs(b->iph.ip_len);
+	if (ip_len > (unsigned int) (len - ETH_HLEN))
 		return;
 
 	if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
 		return;
 
 	/* Parse DHCP options */
-	end = (const u8 *) b + tot_len;
+	end = (const u8 *) b + ip_len;
 	pos = &b->exten[4];
 	while (pos < end && *pos != DHCP_OPT_END) {
 		const u8 *opt = pos++;
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 1a3a815..c86f01b 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1,7 +1,7 @@
 /*
  * hostapd / DPP integration
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -81,6 +81,71 @@
 }
 
 
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd)
+{
+	const char *pos;
+	struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+	pos = os_strstr(cmd, " own=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+	if (!own_bi)
+		return -1;
+
+	pos = os_strstr(cmd, " uri=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+	if (!peer_bi) {
+		wpa_printf(MSG_INFO,
+			   "DPP: Failed to parse URI from NFC Handover Request");
+		return -1;
+	}
+
+	if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+		return -1;
+
+	return peer_bi->id;
+}
+
+
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd)
+{
+	const char *pos;
+	struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+	pos = os_strstr(cmd, " own=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+	if (!own_bi)
+		return -1;
+
+	pos = os_strstr(cmd, " uri=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+	if (!peer_bi) {
+		wpa_printf(MSG_INFO,
+			   "DPP: Failed to parse URI from NFC Handover Select");
+		return -1;
+	}
+
+	if (peer_bi->curve != own_bi->curve) {
+		wpa_printf(MSG_INFO,
+			   "DPP: Peer (NFC Handover Selector) used different curve");
+		return -1;
+	}
+
+	return peer_bi->id;
+}
+
+
 static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
 						void *timeout_ctx)
 {
@@ -478,15 +543,15 @@
 		dpp_auth_deinit(hapd->dpp_auth);
 	}
 
-	hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
+	hapd->dpp_auth = dpp_auth_init(hapd->iface->interfaces->dpp,
+				       hapd->msg_ctx, peer_bi, own_bi,
 				       allowed_roles, neg_freq,
 				       hapd->iface->hw_features,
 				       hapd->iface->num_hw_features);
 	if (!hapd->dpp_auth)
 		goto fail;
 	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
-	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
-				 hapd->dpp_auth, cmd) < 0) {
+	if (dpp_set_configurator(hapd->dpp_auth, cmd) < 0) {
 		dpp_auth_deinit(hapd->dpp_auth);
 		hapd->dpp_auth = NULL;
 		goto fail;
@@ -598,7 +663,8 @@
 	}
 
 	hapd->dpp_auth_ok_on_ack = 0;
-	hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
+	hapd->dpp_auth = dpp_auth_req_rx(hapd->iface->interfaces->dpp,
+					 hapd->msg_ctx, hapd->dpp_allowed_roles,
 					 hapd->dpp_qr_mutual,
 					 peer_bi, own_bi, freq, hdr, buf, len);
 	if (!hapd->dpp_auth) {
@@ -606,8 +672,7 @@
 		return;
 	}
 	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
-	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
-				 hapd->dpp_auth,
+	if (dpp_set_configurator(hapd->dpp_auth,
 				 hapd->dpp_configurator_params) < 0) {
 		dpp_auth_deinit(hapd->dpp_auth);
 		hapd->dpp_auth = NULL;
@@ -643,7 +708,8 @@
 		 * message. */
 		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
 			conf->connector);
-	} else if (conf->passphrase[0]) {
+	}
+	if (conf->passphrase[0]) {
 		char hex[64 * 2 + 1];
 
 		wpa_snprintf_hex(hex, sizeof(hex),
@@ -697,6 +763,33 @@
 }
 
 
+static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd,
+				      struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+	int res;
+
+	if (!key)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+	while (key) {
+		res = dpp_configurator_from_backup(
+			hapd->iface->interfaces->dpp, key);
+		if (res < 0)
+			return -1;
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+			res);
+		key = key->next;
+	}
+#endif /* CONFIG_DPP2 */
+
+	return 0;
+}
+
+
 static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
 				    enum gas_query_ap_result result,
 				    const struct wpabuf *adv_proto,
@@ -741,6 +834,9 @@
 	}
 
 	hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
+	if (hostapd_dpp_handle_key_pkg(hapd, auth->conf_key_pkg) < 0)
+		goto fail;
+
 	status = DPP_STATUS_OK;
 #ifdef CONFIG_TESTING_OPTIONS
 	if (dpp_test == DPP_TEST_REJECT_CONFIG) {
@@ -1037,6 +1133,70 @@
 }
 
 
+static void
+hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
+				     const u8 *hdr, const u8 *buf, size_t len,
+				     unsigned int freq)
+{
+	const u8 *r_bootstrap;
+	u16 r_bootstrap_len;
+	struct dpp_bootstrap_info *peer_bi;
+	struct dpp_authentication *auth;
+
+	wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+		   MAC2STR(src));
+
+	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+				   &r_bootstrap_len);
+	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
+		return;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+		    r_bootstrap, r_bootstrap_len);
+	peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
+					   r_bootstrap);
+	if (!peer_bi) {
+		if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+					src, hdr, buf, len, freq, NULL,
+					r_bootstrap) == 0)
+			return;
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No matching bootstrapping information found");
+		return;
+	}
+
+	if (hapd->dpp_auth) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Ignore Presence Announcement during ongoing Authentication");
+		return;
+	}
+
+	auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+			     peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL,
+			     0);
+	if (!auth)
+		return;
+	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
+	if (dpp_set_configurator(hapd->dpp_auth,
+				 hapd->dpp_configurator_params) < 0) {
+		dpp_auth_deinit(auth);
+		return;
+	}
+
+	auth->neg_freq = freq;
+
+	if (!is_zero_ether_addr(peer_bi->mac_addr))
+		os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+	hapd->dpp_auth = auth;
+	if (hostapd_dpp_auth_init_next(hapd) < 0) {
+		dpp_auth_deinit(hapd->dpp_auth);
+		hapd->dpp_auth = NULL;
+	}
+}
+
 #endif /* CONFIG_DPP2 */
 
 
@@ -1486,6 +1646,10 @@
 	case DPP_PA_CONNECTION_STATUS_RESULT:
 		hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
 		break;
+	case DPP_PA_PRESENCE_ANNOUNCEMENT:
+		hostapd_dpp_rx_presence_announcement(hapd, src, hdr, buf, len,
+						     freq);
+		break;
 #endif /* CONFIG_DPP2 */
 	default:
 		wpa_printf(MSG_DEBUG,
@@ -1580,14 +1744,13 @@
 	int ret = -1;
 	char *curve = NULL;
 
-	auth = os_zalloc(sizeof(*auth));
+	auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx);
 	if (!auth)
 		return -1;
 
 	curve = get_param(cmd, " curve=");
 	hostapd_dpp_set_testing_options(hapd, auth);
-	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
-				 auth, cmd) == 0 &&
+	if (dpp_set_configurator(auth, cmd) == 0 &&
 	    dpp_configurator_own_config(auth, curve, 1) == 0) {
 		hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
 		ret = 0;
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index e151c2f..b1fa99e 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -1,7 +1,7 @@
 /*
  * hostapd / DPP integration
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -12,6 +12,8 @@
 
 int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
 void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 8a4b0ef..559bb87 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -109,7 +109,8 @@
 			const u8 *req_ies, size_t req_ies_len, int reassoc)
 {
 	struct sta_info *sta;
-	int new_assoc, res;
+	int new_assoc;
+	enum wpa_validate_result res;
 	struct ieee802_11_elems elems;
 	const u8 *ie;
 	size_t ielen;
@@ -220,7 +221,6 @@
 	}
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_IEEE80211N
 #ifdef NEED_AP_MLME
 	if (elems.ht_capabilities &&
 	    (hapd->iface->conf->ht_capab &
@@ -234,7 +234,6 @@
 			ht40_intolerant_add(hapd->iface, sta);
 	}
 #endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_INTERWORKING
 	if (elems.ext_capab && elems.ext_capab_len > 4) {
@@ -325,33 +324,67 @@
 					  elems.rsnxe ? elems.rsnxe_len + 2 : 0,
 					  elems.mdie, elems.mdie_len,
 					  elems.owe_dh, elems.owe_dh_len);
-		if (res != WPA_IE_OK) {
+		reason = WLAN_REASON_INVALID_IE;
+		status = WLAN_STATUS_INVALID_IE;
+		switch (res) {
+		case WPA_IE_OK:
+			reason = WLAN_REASON_UNSPECIFIED;
+			status = WLAN_STATUS_SUCCESS;
+			break;
+		case WPA_INVALID_IE:
+			reason = WLAN_REASON_INVALID_IE;
+			status = WLAN_STATUS_INVALID_IE;
+			break;
+		case WPA_INVALID_GROUP:
+			reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+			status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+			break;
+		case WPA_INVALID_PAIRWISE:
+			reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+			status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+			break;
+		case WPA_INVALID_AKMP:
+			reason = WLAN_REASON_AKMP_NOT_VALID;
+			status = WLAN_STATUS_AKMP_NOT_VALID;
+			break;
+		case WPA_NOT_ENABLED:
+			reason = WLAN_REASON_INVALID_IE;
+			status = WLAN_STATUS_INVALID_IE;
+			break;
+		case WPA_ALLOC_FAIL:
+			reason = WLAN_REASON_UNSPECIFIED;
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			break;
+		case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+			reason = WLAN_REASON_INVALID_IE;
+			status = WLAN_STATUS_INVALID_IE;
+			break;
+		case WPA_INVALID_MGMT_GROUP_CIPHER:
+			reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+			status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+			break;
+		case WPA_INVALID_MDIE:
+			reason = WLAN_REASON_INVALID_MDE;
+			status = WLAN_STATUS_INVALID_MDIE;
+			break;
+		case WPA_INVALID_PROTO:
+			reason = WLAN_REASON_INVALID_IE;
+			status = WLAN_STATUS_INVALID_IE;
+			break;
+		case WPA_INVALID_PMKID:
+			reason = WLAN_REASON_INVALID_PMKID;
+			status = WLAN_STATUS_INVALID_PMKID;
+			break;
+		case WPA_DENIED_OTHER_REASON:
+			reason = WLAN_REASON_UNSPECIFIED;
+			status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+			break;
+		}
+		if (status != WLAN_STATUS_SUCCESS) {
 			wpa_printf(MSG_DEBUG,
 				   "WPA/RSN information element rejected? (res %u)",
 				   res);
 			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
-			if (res == WPA_INVALID_GROUP) {
-				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
-				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
-			} else if (res == WPA_INVALID_PAIRWISE) {
-				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
-				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
-			} else if (res == WPA_INVALID_AKMP) {
-				reason = WLAN_REASON_AKMP_NOT_VALID;
-				status = WLAN_STATUS_AKMP_NOT_VALID;
-			} else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
-				reason = WLAN_REASON_INVALID_IE;
-				status = WLAN_STATUS_INVALID_IE;
-			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
-				reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
-				status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-			} else if (res == WPA_INVALID_PMKID) {
-				reason = WLAN_REASON_INVALID_PMKID;
-				status = WLAN_STATUS_INVALID_PMKID;
-			} else {
-				reason = WLAN_REASON_INVALID_IE;
-				status = WLAN_STATUS_INVALID_IE;
-			}
 			goto fail;
 		}
 
@@ -469,6 +502,9 @@
 			return WLAN_STATUS_INVALID_IE;
 #endif /* CONFIG_HS20 */
 	}
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
 
 #ifdef CONFIG_MBO
 	if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
@@ -480,13 +516,10 @@
 	}
 #endif /* CONFIG_MBO */
 
-#ifdef CONFIG_WPS
-skip_wpa_check:
-#endif /* CONFIG_WPS */
-
 #ifdef CONFIG_IEEE80211R_AP
 	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
-					sta->auth_alg, req_ies, req_ies_len);
+					sta->auth_alg, req_ies, req_ies_len,
+					!elems.rsnxe);
 	if (!p) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -577,18 +610,18 @@
 		npos = owe_assoc_req_process(hapd, sta,
 					     elems.owe_dh, elems.owe_dh_len,
 					     p, sizeof(buf) - (p - buf),
-					     &reason);
+					     &status);
 		if (npos)
 			p = npos;
+
 		if (!npos &&
-		    reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
-			status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+		    status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
 			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
 					  p - buf);
 			return 0;
 		}
 
-		if (!npos || reason != WLAN_STATUS_SUCCESS)
+		if (!npos || status != WLAN_STATUS_SUCCESS)
 			goto fail;
 	}
 #endif /* CONFIG_OWE */
@@ -625,6 +658,11 @@
 	pfs_fail:
 #endif /* CONFIG_DPP2 */
 
+	if (elems.rrm_enabled &&
+	    elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+	    os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+		      sizeof(sta->rrm_enabled_capa));
+
 #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
 	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
 
@@ -709,6 +747,7 @@
 
 	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	hostapd_set_sta_flags(hapd, sta);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -906,6 +945,12 @@
 	} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
 			"freq=%d dfs=%d", freq, is_dfs);
+	} else if (is_dfs &&
+		   hostapd_is_dfs_required(hapd->iface) &&
+		   !hostapd_is_dfs_chan_available(hapd->iface) &&
+		   !hapd->iface->cac_started) {
+		hostapd_disable_iface(hapd->iface);
+		hostapd_enable_iface(hapd->iface);
 	}
 
 	for (i = 0; i < hapd->iface->num_bss; i++)
@@ -1005,32 +1050,35 @@
 		goto out;
 	}
 
+	hapd->iconf->edmg_channel = acs_res->edmg_channel;
+
 	if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
 		/* 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);
-		if (acs_res->ch_width == 80) {
+		if (acs_res->ch_width == 40) {
+			if (is_6ghz_freq(acs_res->pri_freq))
+				hostapd_set_oper_centr_freq_seg0_idx(
+					hapd->iconf,
+					acs_res->vht_seg0_center_ch);
+		} else if (acs_res->ch_width == 80) {
 			hostapd_set_oper_centr_freq_seg0_idx(
 				hapd->iconf, acs_res->vht_seg0_center_ch);
-			hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
-		} else if (acs_res->ch_width == 160) {
 			if (acs_res->vht_seg1_center_ch == 0) {
-				hostapd_set_oper_centr_freq_seg0_idx(
-					hapd->iconf,
-					acs_res->vht_seg0_center_ch);
 				hostapd_set_oper_chwidth(hapd->iconf,
-							 CHANWIDTH_160MHZ);
+							 CHANWIDTH_80MHZ);
 			} else {
-				hostapd_set_oper_centr_freq_seg0_idx(
-					hapd->iconf,
-					acs_res->vht_seg0_center_ch);
+				hostapd_set_oper_chwidth(hapd->iconf,
+							 CHANWIDTH_80P80MHZ);
 				hostapd_set_oper_centr_freq_seg1_idx(
 					hapd->iconf,
 					acs_res->vht_seg1_center_ch);
-				hostapd_set_oper_chwidth(hapd->iconf,
-							 CHANWIDTH_80P80MHZ);
 			}
+		} else if (acs_res->ch_width == 160) {
+			hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
+			hostapd_set_oper_centr_freq_seg0_idx(
+				hapd->iconf, acs_res->vht_seg1_center_ch);
 		}
 	}
 
@@ -1426,15 +1474,33 @@
 #endif /* HOSTAPD */
 
 
+static struct hostapd_channel_data *
+hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
+{
+	int i;
+	struct hostapd_channel_data *chan;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
+		if ((unsigned int) chan->freq == freq)
+			return chan;
+	}
+
+	return NULL;
+}
+
+
 static struct hostapd_channel_data * hostapd_get_mode_channel(
 	struct hostapd_iface *iface, unsigned int freq)
 {
 	int i;
 	struct hostapd_channel_data *chan;
 
-	for (i = 0; i < iface->current_mode->num_channels; i++) {
-		chan = &iface->current_mode->channels[i];
-		if ((unsigned int) chan->freq == freq)
+	for (i = 0; i < iface->num_hw_features; i++) {
+		if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
+			continue;
+		chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
+		if (chan)
 			return chan;
 	}
 
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
index 6da514a..0310aab 100644
--- a/src/ap/fils_hlp.c
+++ b/src/ap/fils_hlp.c
@@ -158,7 +158,7 @@
 	ssize_t res;
 	u8 msgtype = 0;
 	int rapid_commit = 0;
-	struct iphdr *iph;
+	struct ip *iph;
 	struct udphdr *udph;
 	struct wpabuf *resp;
 	const u8 *rpos;
@@ -259,14 +259,14 @@
 	wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
 	wpabuf_put_be16(resp, ETH_P_IP);
 	iph = wpabuf_put(resp, sizeof(*iph));
-	iph->version = 4;
-	iph->ihl = sizeof(*iph) / 4;
-	iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
-	iph->ttl = 1;
-	iph->protocol = 17; /* UDP */
-	iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
-	iph->daddr = dhcp->client_ip;
-	iph->check = ip_checksum(iph, sizeof(*iph));
+	iph->ip_v = 4;
+	iph->ip_hl = sizeof(*iph) / 4;
+	iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+	iph->ip_ttl = 1;
+	iph->ip_p = 17; /* UDP */
+	iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+	iph->ip_dst.s_addr = dhcp->client_ip;
+	iph->ip_sum = ip_checksum(iph, sizeof(*iph));
 	udph = wpabuf_put(resp, sizeof(*udph));
 	udph->uh_sport = htons(DHCP_SERVER_PORT);
 	udph->uh_dport = htons(DHCP_CLIENT_PORT);
@@ -479,13 +479,13 @@
 				struct sta_info *sta, const u8 *dst,
 				const u8 *pos, size_t len)
 {
-	const struct iphdr *iph;
+	const struct ip *iph;
 	const struct udphdr *udph;
 	u16 sport, dport, ulen;
 
 	if (len < sizeof(*iph) + sizeof(*udph))
 		return 0;
-	iph = (const struct iphdr *) pos;
+	iph = (const struct ip *) pos;
 	udph = (const struct udphdr *) (iph + 1);
 	sport = ntohs(udph->uh_sport);
 	dport = ntohs(udph->uh_dport);
@@ -510,24 +510,24 @@
 			       struct sta_info *sta, const u8 *dst,
 			       const u8 *pos, size_t len)
 {
-	const struct iphdr *iph;
-	u16 tot_len;
+	const struct ip *iph;
+	uint16_t ip_len;
 
 	if (len < sizeof(*iph))
 		return 0;
-	iph = (const struct iphdr *) pos;
+	iph = (const struct ip *) pos;
 	if (ip_checksum(iph, sizeof(*iph)) != 0) {
 		wpa_printf(MSG_DEBUG,
 			   "FILS: HLP request IPv4 packet had invalid header checksum - dropped");
 		return 0;
 	}
-	tot_len = ntohs(iph->tot_len);
-	if (tot_len > len)
+	ip_len = ntohs(iph->ip_len);
+	if (ip_len > len)
 		return 0;
 	wpa_printf(MSG_DEBUG,
 		   "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
-		   iph->saddr, iph->daddr, iph->protocol);
-	switch (iph->protocol) {
+		   iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p);
+	switch (iph->ip_p) {
 	case 17:
 		return fils_process_hlp_udp(hapd, sta, dst, pos, len);
 	}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index e4950e3..f2e964a 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -13,6 +13,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "utils/crc32.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
 #include "common/hw_features_common.h"
@@ -57,8 +58,10 @@
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+#ifdef CONFIG_WEP
 static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
 static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+#endif /* CONFIG_WEP */
 static int setup_interface2(struct hostapd_iface *iface);
 static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
 static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
@@ -88,7 +91,9 @@
 		return;
 
 	hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
 	hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
 }
 
 
@@ -141,7 +146,9 @@
 		wpa_deinit(hapd->wpa_auth);
 		hapd->wpa_auth = NULL;
 		hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
 		hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
 		hostapd_set_generic_elem(hapd, (u8 *) "", 0);
 	}
 
@@ -169,7 +176,9 @@
 	for (j = 0; j < iface->num_bss; j++) {
 		hostapd_flush_old_stations(iface->bss[j],
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_WEP
 		hostapd_broadcast_wep_clear(iface->bss[j]);
+#endif /* CONFIG_WEP */
 
 #ifndef CONFIG_NO_RADIUS
 		/* TODO: update dynamic data based on changed configuration
@@ -283,6 +292,8 @@
 }
 
 
+#ifdef CONFIG_WEP
+
 static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
 					      const char *ifname)
 {
@@ -291,8 +302,8 @@
 	if (!ifname || !hapd->drv_priv)
 		return;
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
-					0, NULL, 0, NULL, 0)) {
+		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
+					0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
 			wpa_printf(MSG_DEBUG, "Failed to clear default "
 				   "encryption keys (ifname=%s keyidx=%d)",
 				   ifname, i);
@@ -301,8 +312,8 @@
 	if (hapd->conf->ieee80211w) {
 		for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
 			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
-						NULL, i, 0, NULL,
-						0, NULL, 0)) {
+						NULL, i, 0, 0, NULL,
+						0, NULL, 0, KEY_FLAG_GROUP)) {
 				wpa_printf(MSG_DEBUG, "Failed to clear "
 					   "default mgmt encryption keys "
 					   "(ifname=%s keyidx=%d)", ifname, i);
@@ -325,11 +336,12 @@
 	struct hostapd_ssid *ssid = &hapd->conf->ssid;
 
 	idx = ssid->wep.idx;
-	if (ssid->wep.default_len &&
+	if (ssid->wep.default_len && ssid->wep.key[idx] &&
 	    hostapd_drv_set_key(hapd->conf->iface,
-				hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+				hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
 				1, NULL, 0, ssid->wep.key[idx],
-				ssid->wep.len[idx])) {
+				ssid->wep.len[idx],
+				KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
 		wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
 		errors++;
 	}
@@ -337,6 +349,8 @@
 	return errors;
 }
 
+#endif /* CONFIG_WEP */
+
 
 static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 {
@@ -479,11 +493,9 @@
 static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 {
 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
-#ifdef CONFIG_IEEE80211N
 #ifdef NEED_AP_MLME
 	hostapd_stop_setup_timers(iface);
 #endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
 	if (iface->current_mode)
 		acs_cleanup(iface);
 	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
@@ -524,6 +536,8 @@
 }
 
 
+#ifdef CONFIG_WEP
+
 static void hostapd_clear_wep(struct hostapd_data *hapd)
 {
 	if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
@@ -552,10 +566,13 @@
 
 	for (i = 0; i < 4; i++) {
 		if (hapd->conf->ssid.wep.key[i] &&
-		    hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
+		    hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0,
 					i == hapd->conf->ssid.wep.idx, NULL, 0,
 					hapd->conf->ssid.wep.key[i],
-					hapd->conf->ssid.wep.len[i])) {
+					hapd->conf->ssid.wep.len[i],
+					i == hapd->conf->ssid.wep.idx ?
+					KEY_FLAG_GROUP_RX_TX_DEFAULT :
+					KEY_FLAG_GROUP_RX_TX)) {
 			wpa_printf(MSG_WARNING, "Could not set WEP "
 				   "encryption.");
 			return -1;
@@ -568,6 +585,8 @@
 	return 0;
 }
 
+#endif /* CONFIG_WEP */
+
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
 {
@@ -603,7 +622,9 @@
 {
 	hostapd_free_stas(hapd);
 	hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+#ifdef CONFIG_WEP
 	hostapd_clear_wep(hapd);
+#endif /* CONFIG_WEP */
 }
 
 
@@ -1158,9 +1179,11 @@
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 	hostapd_set_privacy(hapd, 0);
 
+#ifdef CONFIG_WEP
 	hostapd_broadcast_wep_clear(hapd);
 	if (hostapd_setup_encryption(conf->iface, hapd))
 		return -1;
+#endif /* CONFIG_WEP */
 
 	/*
 	 * Fetch the SSID from the system and use it or,
@@ -1190,8 +1213,14 @@
 		os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
 	}
 
+	/*
+	 * Short SSID calculation is identical to FCS and it is defined in
+	 * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
+	 */
+	conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
+
 	if (!hostapd_drv_none(hapd)) {
-		wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+		wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
 			   " and ssid \"%s\"",
 			   conf->iface, MAC2STR(hapd->own_addr),
 			   wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
@@ -2338,12 +2367,10 @@
 		hostapd_bss_deinit(iface->bss[j]);
 	}
 
-#ifdef CONFIG_IEEE80211N
 #ifdef NEED_AP_MLME
 	hostapd_stop_setup_timers(iface);
 	eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
 #endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
 }
 
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 016fe3b..439e727 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -38,6 +38,10 @@
 struct mesh_conf;
 #endif /* CONFIG_MESH */
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define CTRL_IFACE_COOKIE_LEN 8
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
 struct hostapd_iface;
 
 struct hapd_interfaces {
@@ -72,6 +76,11 @@
 #ifdef CONFIG_DPP
 	struct dpp_global *dpp;
 #endif /* CONFIG_DPP */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+       unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
 };
 
 enum hostapd_chan_status {
@@ -395,6 +404,10 @@
 #ifdef CONFIG_SQLITE
 	sqlite3 *rad_attr_db;
 #endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+       unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
 };
 
 
@@ -464,9 +477,6 @@
 
 	u64 drv_flags;
 
-	/* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
-	unsigned int smps_modes;
-
 	/*
 	 * A bitmap of supported protocols for probe response offload. See
 	 * struct wpa_driver_capa in driver.h
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index ba10752..f6e6903 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -224,7 +224,6 @@
 }
 
 
-#ifdef CONFIG_IEEE80211N
 static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
 {
 	int pri_freq, sec_freq;
@@ -561,26 +560,6 @@
 		return 0;
 	}
 
-	switch (conf & HT_CAP_INFO_SMPS_MASK) {
-	case HT_CAP_INFO_SMPS_STATIC:
-		if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
-			wpa_printf(MSG_ERROR,
-				   "Driver does not support configured HT capability [SMPS-STATIC]");
-			return 0;
-		}
-		break;
-	case HT_CAP_INFO_SMPS_DYNAMIC:
-		if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
-			wpa_printf(MSG_ERROR,
-				   "Driver does not support configured HT capability [SMPS-DYNAMIC]");
-			return 0;
-		}
-		break;
-	case HT_CAP_INFO_SMPS_DISABLED:
-	default:
-		break;
-	}
-
 	if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
 	    !(hw & HT_CAP_INFO_GREEN_FIELD)) {
 		wpa_printf(MSG_ERROR, "Driver does not support configured "
@@ -687,12 +666,9 @@
 }
 #endif /* CONFIG_IEEE80211AX */
 
-#endif /* CONFIG_IEEE80211N */
-
 
 int hostapd_check_ht_capab(struct hostapd_iface *iface)
 {
-#ifdef CONFIG_IEEE80211N
 	int ret;
 
 	if (is_6ghz_freq(iface->freq))
@@ -725,7 +701,6 @@
 		return ret;
 	if (!ieee80211n_allowed_ht40_channel_pair(iface))
 		return -1;
-#endif /* CONFIG_IEEE80211N */
 
 	return 0;
 }
@@ -810,7 +785,7 @@
 
 	/* 60 GHz channels 1..6 */
 	for (i = 0; i < 6; i++) {
-		int freq = 56160 + 2160 * i;
+		int freq = 56160 + 2160 * (i + 1);
 
 		if (edmg.channels & BIT(i)) {
 			contiguous++;
@@ -879,10 +854,11 @@
 	if (!iface->conf->secondary_channel)
 		return 1;
 
+	if (hostapd_is_usable_chan(iface, iface->freq +
+				   iface->conf->secondary_channel * 20, 0))
+		return 1;
 	if (!iface->conf->ht40_plus_minus_allowed)
-		return hostapd_is_usable_chan(
-			iface,
-			iface->freq + iface->conf->secondary_channel * 20, 0);
+		return 0;
 
 	/* Both HT40+ and HT40- are set, pick a valid secondary channel */
 	secondary_freq = iface->freq + 20;
@@ -903,10 +879,43 @@
 }
 
 
+static void hostapd_determine_mode(struct hostapd_iface *iface)
+{
+	int i;
+	enum hostapd_hw_mode target_mode;
+
+	if (iface->current_mode ||
+	    iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
+		return;
+
+	if (iface->freq < 4000)
+		target_mode = HOSTAPD_MODE_IEEE80211G;
+	else if (iface->freq > 50000)
+		target_mode = HOSTAPD_MODE_IEEE80211AD;
+	else
+		target_mode = HOSTAPD_MODE_IEEE80211A;
+
+	for (i = 0; i < iface->num_hw_features; i++) {
+		struct hostapd_hw_modes *mode;
+
+		mode = &iface->hw_features[i];
+		if (mode->mode == target_mode) {
+			iface->current_mode = mode;
+			iface->conf->hw_mode = mode->mode;
+			break;
+		}
+	}
+
+	if (!iface->current_mode)
+		wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
+}
+
+
 static enum hostapd_chan_status
 hostapd_check_chans(struct hostapd_iface *iface)
 {
 	if (iface->freq) {
+		hostapd_determine_mode(iface);
 		if (hostapd_is_usable_chans(iface))
 			return HOSTAPD_CHAN_VALID;
 		else
@@ -1032,9 +1041,15 @@
 	}
 
 	if (iface->current_mode == NULL) {
-		if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
-		    !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
-		{
+		if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+		    (iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) {
+			wpa_printf(MSG_DEBUG,
+				   "Using offloaded hw_mode=any ACS");
+		} else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+			   iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) {
+			wpa_printf(MSG_DEBUG,
+				   "Using internal ACS for hw_mode=any");
+		} else {
 			wpa_printf(MSG_ERROR,
 				   "Hardware does not support configured mode");
 			hostapd_logger(iface->bss[0], NULL,
@@ -1109,3 +1124,20 @@
 	}
 	return 0;
 }
+
+
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+			 struct hostapd_hw_modes *mode)
+{
+	int i;
+
+	if (iface->current_mode)
+		return mode != iface->current_mode;
+	if (mode->mode != HOSTAPD_MODE_IEEE80211B)
+		return 0;
+	for (i = 0; i < iface->num_hw_features; i++) {
+		if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G)
+			return 1;
+	}
+	return 0;
+}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 902a19f..dd24f95 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -25,6 +25,8 @@
 int hostapd_prepare_rates(struct hostapd_iface *iface,
 			  struct hostapd_hw_modes *mode);
 void hostapd_stop_setup_timers(struct hostapd_iface *iface);
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+			 struct hostapd_hw_modes *mode);
 #else /* NEED_AP_MLME */
 static inline void
 hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -49,7 +51,7 @@
 
 static inline const char * hostapd_hw_mode_txt(int mode)
 {
-	return NULL;
+	return "UNKNOWN";
 }
 
 static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
@@ -77,6 +79,12 @@
 {
 }
 
+static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+				       struct hostapd_hw_modes *mode)
+{
+	return 0;
+}
+
 #endif /* NEED_AP_MLME */
 
 #endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 5b70425..e54217c 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -88,6 +88,7 @@
 {
 	u8 *pos = eid;
 	int i, num, count;
+	int h2e_required;
 
 	if (hapd->iface->current_rates == NULL)
 		return eid;
@@ -98,8 +99,11 @@
 		num++;
 	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
 		num++;
-	if (hapd->conf->sae_pwe == 1 &&
-	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
+	h2e_required = (hapd->conf->sae_pwe == 1 ||
+			hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+		hapd->conf->sae_pwe != 3 &&
+		wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+	if (h2e_required)
 		num++;
 	if (num > 8) {
 		/* rest of the rates are encoded in Extended supported
@@ -127,9 +131,7 @@
 		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
 	}
 
-	if (hapd->conf->sae_pwe == 1 &&
-	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
-	    count < 8) {
+	if (h2e_required && count < 8) {
 		count++;
 		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
 	}
@@ -142,6 +144,7 @@
 {
 	u8 *pos = eid;
 	int i, num, count;
+	int h2e_required;
 
 	if (hapd->iface->current_rates == NULL)
 		return eid;
@@ -151,8 +154,11 @@
 		num++;
 	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
 		num++;
-	if (hapd->conf->sae_pwe == 1 &&
-	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
+	h2e_required = (hapd->conf->sae_pwe == 1 ||
+			hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+		hapd->conf->sae_pwe != 3 &&
+		wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+	if (h2e_required)
 		num++;
 	if (num <= 8)
 		return eid;
@@ -183,8 +189,7 @@
 			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
 	}
 
-	if (hapd->conf->sae_pwe == 1 &&
-	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
+	if (h2e_required) {
 		count++;
 		if (count > 8)
 			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
@@ -194,10 +199,31 @@
 }
 
 
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+				  size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+		if (hapd->conf->radio_measurements[i])
+			break;
+	}
+
+	if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
+		return eid;
+
+	*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+	*eid++ = RRM_CAPABILITIES_IE_LEN;
+	os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+	return eid + RRM_CAPABILITIES_IE_LEN;
+}
+
+
 u16 hostapd_own_capab_info(struct hostapd_data *hapd)
 {
 	int capab = WLAN_CAPABILITY_ESS;
-	int privacy;
+	int privacy = 0;
 	int dfs;
 	int i;
 
@@ -213,12 +239,14 @@
 	    hapd->iconf->preamble == SHORT_PREAMBLE)
 		capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
 
+#ifdef CONFIG_WEP
 	privacy = hapd->conf->ssid.wep.keys_set;
 
 	if (hapd->conf->ieee802_1x &&
 	    (hapd->conf->default_wep_key_len ||
 	     hapd->conf->individual_wep_key_len))
 		privacy = 1;
+#endif /* CONFIG_WEP */
 
 	if (hapd->conf->wpa)
 		privacy = 1;
@@ -258,6 +286,7 @@
 }
 
 
+#ifdef CONFIG_WEP
 #ifndef CONFIG_NO_RC4
 static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
 			   u16 auth_transaction, const u8 *challenge,
@@ -314,9 +343,10 @@
 	return 0;
 }
 #endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
 
 
-static int send_auth_reply(struct hostapd_data *hapd,
+static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
 			   const u8 *dst, const u8 *bssid,
 			   u16 auth_alg, u16 auth_transaction, u16 resp,
 			   const u8 *ies, size_t ies_len, const char *dbg)
@@ -349,7 +379,37 @@
 		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
 		   MAC2STR(dst), auth_alg, auth_transaction,
 		   resp, (unsigned long) ies_len, dbg);
-	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_SAE
+	if (hapd->conf->sae_confirm_immediate == 2 &&
+	    auth_alg == WLAN_AUTH_SAE) {
+		if (auth_transaction == 1 && sta &&
+		    (resp == WLAN_STATUS_SUCCESS ||
+		     resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
+			wpa_printf(MSG_DEBUG,
+				   "TESTING: Postpone SAE Commit transmission until Confirm is ready");
+			os_free(sta->sae_postponed_commit);
+			sta->sae_postponed_commit = buf;
+			sta->sae_postponed_commit_len = rlen;
+			return WLAN_STATUS_SUCCESS;
+		}
+
+		if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
+			wpa_printf(MSG_DEBUG,
+				   "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
+			if (hostapd_drv_send_mlme(hapd,
+						  sta->sae_postponed_commit,
+						  sta->sae_postponed_commit_len,
+						  0, NULL, 0, 0) < 0)
+				wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+			os_free(sta->sae_postponed_commit);
+			sta->sae_postponed_commit = NULL;
+			sta->sae_postponed_commit_len = 0;
+		}
+	}
+#endif /* CONFIG_SAE */
+#endif /* CONFIG_TESTING_OPTIONS */
+	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
 		wpa_printf(MSG_INFO, "send_auth_reply: send failed");
 	else
 		reply_res = WLAN_STATUS_SUCCESS;
@@ -369,7 +429,7 @@
 	struct sta_info *sta;
 	int reply_res;
 
-	reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+	reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
 				    auth_transaction, status, ies, ies_len,
 				    "auth-ft-finish");
 
@@ -423,7 +483,9 @@
 		use_pt = sta->sae->tmp->h2e;
 	}
 
-	if (status_code == WLAN_STATUS_SUCCESS)
+	if (rx_id && hapd->conf->sae_pwe != 3)
+		use_pt = 1;
+	else if (status_code == WLAN_STATUS_SUCCESS)
 		use_pt = 0;
 	else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
 		use_pt = 1;
@@ -474,10 +536,13 @@
 
 	buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
 			   (rx_id ? 3 + os_strlen(rx_id) : 0));
-	if (buf == NULL)
-		return NULL;
-	sae_write_commit(sta->sae, buf, sta->sae->tmp ?
-			 sta->sae->tmp->anti_clogging_token : NULL, rx_id);
+	if (buf &&
+	    sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+			     sta->sae->tmp->anti_clogging_token : NULL,
+			     rx_id) < 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
 
 	return buf;
 }
@@ -514,7 +579,8 @@
 
 	status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
 		WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
-	reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
+	reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+				    WLAN_AUTH_SAE, 1,
 				    status, wpabuf_head(data),
 				    wpabuf_len(data), "sae-send-commit");
 
@@ -535,7 +601,8 @@
 	if (data == NULL)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-	reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+	reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+				    WLAN_AUTH_SAE, 2,
 				    WLAN_STATUS_SUCCESS, wpabuf_head(data),
 				    wpabuf_len(data), "sae-send-confirm");
 
@@ -575,13 +642,15 @@
 }
 
 
-static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
 {
 	u8 hash[SHA256_MAC_LEN];
 
-	hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
-		    addr, ETH_ALEN, hash);
-	return hash[0];
+	if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+			addr, ETH_ALEN, hash) < 0)
+		return -1;
+	*idx = hash[0];
+	return 0;
 }
 
 
@@ -594,9 +663,8 @@
 	u16 token_idx;
 	u8 idx;
 
-	if (token_len != SHA256_MAC_LEN)
+	if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
 		return -1;
-	idx = sae_token_hash(hapd, addr);
 	token_idx = hapd->sae_pending_token_idx[idx];
 	if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
 		wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
@@ -621,7 +689,7 @@
 
 
 static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
-					    int group, const u8 *addr)
+					    int group, const u8 *addr, int h2e)
 {
 	struct wpabuf *buf;
 	u8 *token;
@@ -647,13 +715,23 @@
 			  sizeof(hapd->sae_pending_token_idx));
 	}
 
-	buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
+	buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
 	if (buf == NULL)
 		return NULL;
 
 	wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
 
-	p_idx = sae_token_hash(hapd, addr);
+	if (h2e) {
+		/* Encapsulate Anti-clogging Token field in a container IE */
+		wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+		wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
+		wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+	}
+
+	if (sae_token_hash(hapd, addr, &p_idx) < 0) {
+		wpabuf_free(buf);
+		return NULL;
+	}
 	token_idx = hapd->sae_pending_token_idx[p_idx];
 	if (!token_idx) {
 		hapd->sae_token_idx++;
@@ -795,6 +873,9 @@
 	mlme_authenticate_indication(hapd, sta);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
 	sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
+	crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
+	sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
+	sta->sae->peer_commit_scalar = NULL;
 	wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
 			       sta->sae->pmk, sta->sae->pmkid);
 	sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
@@ -1028,11 +1109,20 @@
 
 static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
 {
-	return (hapd->conf->sae_pwe == 0 &&
+	int sae_pwe = hapd->conf->sae_pwe;
+	int id_in_use;
+
+	id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+	if (id_in_use == 2 && sae_pwe != 3)
+		sae_pwe = 1;
+	else if (id_in_use == 1 && sae_pwe == 0)
+		sae_pwe = 2;
+
+	return ((sae_pwe == 0 || sae_pwe == 3) &&
 		status_code == WLAN_STATUS_SUCCESS) ||
-		(hapd->conf->sae_pwe == 1 &&
+		(sae_pwe == 1 &&
 		 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
-		(hapd->conf->sae_pwe == 2 &&
+		(sae_pwe == 2 &&
 		 (status_code == WLAN_STATUS_SUCCESS ||
 		  status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
 }
@@ -1103,7 +1193,7 @@
 		wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
 		pos = mgmt->u.auth.variable;
 		end = ((const u8 *) mgmt) + len;
-		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+		send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
 				auth_transaction, resp, pos, end - pos,
 				"auth-sae-reflection-attack");
 		goto remove_sta;
@@ -1111,7 +1201,7 @@
 
 	if (hapd->conf->sae_commit_override && auth_transaction == 1) {
 		wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
-		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+		send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
 				auth_transaction, resp,
 				wpabuf_head(hapd->conf->sae_commit_override),
 				wpabuf_len(hapd->conf->sae_commit_override),
@@ -1286,11 +1376,17 @@
 		}
 
 		if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
+			int h2e = 0;
+
 			wpa_printf(MSG_DEBUG,
 				   "SAE: Request anti-clogging token from "
 				   MACSTR, MAC2STR(sta->addr));
+			if (sta->sae->tmp)
+				h2e = sta->sae->tmp->h2e;
+			if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+				h2e = 1;
 			data = auth_build_token_req(hapd, sta->sae->group,
-						    sta->addr);
+						    sta->addr, h2e);
 			resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
 			if (hapd->conf->mesh & MESH_ENABLED)
 				sae_set_state(sta, SAE_NOTHING,
@@ -1365,7 +1461,7 @@
 			data = wpabuf_alloc_copy(pos, 2);
 
 		sae_sme_send_external_auth_status(hapd, sta, resp);
-		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+		send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
 				auth_transaction, resp,
 				data ? wpabuf_head(data) : (u8 *) "",
 				data ? wpabuf_len(data) : 0, "auth-sae");
@@ -1515,27 +1611,37 @@
 #endif /* CONFIG_SAE */
 
 
-static u16 wpa_res_to_status_code(int res)
+static u16 wpa_res_to_status_code(enum wpa_validate_result res)
 {
-	if (res == WPA_INVALID_GROUP)
-		return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
-	if (res == WPA_INVALID_PAIRWISE)
-		return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
-	if (res == WPA_INVALID_AKMP)
-		return WLAN_STATUS_AKMP_NOT_VALID;
-	if (res == WPA_ALLOC_FAIL)
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
-		return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
-	if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
-		return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-	if (res == WPA_INVALID_MDIE)
-		return WLAN_STATUS_INVALID_MDIE;
-	if (res == WPA_INVALID_PMKID)
-		return WLAN_STATUS_INVALID_PMKID;
-	if (res != WPA_IE_OK)
+	switch (res) {
+	case WPA_IE_OK:
+		return WLAN_STATUS_SUCCESS;
+	case WPA_INVALID_IE:
 		return WLAN_STATUS_INVALID_IE;
-	return WLAN_STATUS_SUCCESS;
+	case WPA_INVALID_GROUP:
+		return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+	case WPA_INVALID_PAIRWISE:
+		return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+	case WPA_INVALID_AKMP:
+		return WLAN_STATUS_AKMP_NOT_VALID;
+	case WPA_NOT_ENABLED:
+		return WLAN_STATUS_INVALID_IE;
+	case WPA_ALLOC_FAIL:
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+		return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+	case WPA_INVALID_MGMT_GROUP_CIPHER:
+		return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+	case WPA_INVALID_MDIE:
+		return WLAN_STATUS_INVALID_MDIE;
+	case WPA_INVALID_PROTO:
+		return WLAN_STATUS_INVALID_IE;
+	case WPA_INVALID_PMKID:
+		return WLAN_STATUS_INVALID_PMKID;
+	case WPA_DENIED_OTHER_REASON:
+		return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+	}
+	return WLAN_STATUS_INVALID_IE;
 }
 
 
@@ -1555,7 +1661,7 @@
 	u16 resp = WLAN_STATUS_SUCCESS;
 	const u8 *end;
 	struct ieee802_11_elems elems;
-	int res;
+	enum wpa_validate_result res;
 	struct wpa_ie_data rsn;
 	struct rsn_pmksa_cache_entry *pmksa = NULL;
 
@@ -1731,11 +1837,11 @@
 		    FILS_SESSION_LEN);
 	os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
 
-	/* FILS Wrapped Data */
-	if (elems.fils_wrapped_data) {
+	/* Wrapped Data */
+	if (elems.wrapped_data) {
 		wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
-			    elems.fils_wrapped_data,
-			    elems.fils_wrapped_data_len);
+			    elems.wrapped_data,
+			    elems.wrapped_data_len);
 		if (!pmksa) {
 #ifndef CONFIG_NO_RADIUS
 			if (!sta->eapol_sm) {
@@ -1745,8 +1851,8 @@
 			wpa_printf(MSG_DEBUG,
 				   "FILS: Forward EAP-Initiate/Re-auth to authentication server");
 			ieee802_1x_encapsulate_radius(
-				hapd, sta, elems.fils_wrapped_data,
-				elems.fils_wrapped_data_len);
+				hapd, sta, elems.wrapped_data,
+				elems.wrapped_data_len);
 			sta->fils_pending_cb = cb;
 			wpa_printf(MSG_DEBUG,
 				   "FILS: Will send Authentication frame once the response from authentication server is available");
@@ -1755,8 +1861,8 @@
 			 * to maintain a copy of the EAP-Initiate/Reauth
 			 * message. */
 			if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
-					   elems.fils_wrapped_data,
-					   elems.fils_wrapped_data_len,
+					   elems.wrapped_data,
+					   elems.wrapped_data_len,
 					   sta->fils_erp_pmkid) == 0)
 				sta->fils_erp_pmkid_set = 1;
 			return;
@@ -1899,12 +2005,12 @@
 	wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
 	wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
 
-	/* FILS Wrapped Data */
+	/* Wrapped Data */
 	if (!pmksa && erp_resp) {
 		wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
 		wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
 		/* Element ID Extension */
-		wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+		wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
 		wpabuf_put_buf(data, erp_resp);
 
 		if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
@@ -2006,7 +2112,7 @@
 	auth_alg = (pub ||
 		    resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
 		WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
-	send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+	send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
 			data ? wpabuf_head(data) : (u8 *) "",
 			data ? wpabuf_len(data) : 0, "auth-fils-finish");
 	wpabuf_free(data);
@@ -2050,28 +2156,18 @@
 #endif /* CONFIG_FILS */
 
 
-int
-ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *msg, size_t len, u32 *session_timeout,
-			   u32 *acct_interim_interval,
-			   struct vlan_description *vlan_id,
-			   struct hostapd_sta_wpa_psk_short **psk,
-			   char **identity, char **radius_cui, int is_probe_req)
+static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+				      const u8 *msg, size_t len,
+				      struct radius_sta *info)
 {
 	int res;
 
-	os_memset(vlan_id, 0, sizeof(*vlan_id));
-	res = hostapd_allowed_address(hapd, addr, msg, len,
-				      session_timeout, acct_interim_interval,
-				      vlan_id, psk, identity, radius_cui,
-				      is_probe_req);
+	res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
 
 	if (res == HOSTAPD_ACL_REJECT) {
-		if (!is_probe_req)
-			wpa_printf(MSG_DEBUG,
-				   "Station " MACSTR
-				   " not allowed to authenticate",
-				   MAC2STR(addr));
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+			   " not allowed to authenticate",
+			   MAC2STR(addr));
 		return HOSTAPD_ACL_REJECT;
 	}
 
@@ -2091,12 +2187,15 @@
 
 static int
 ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
-			   int res, u32 session_timeout,
-			   u32 acct_interim_interval,
-			   struct vlan_description *vlan_id,
-			   struct hostapd_sta_wpa_psk_short **psk,
-			   char **identity, char **radius_cui)
+			   int res, struct radius_sta *info)
 {
+	u32 session_timeout = info->session_timeout;
+	u32 acct_interim_interval = info->acct_interim_interval;
+	struct vlan_description *vlan_id = &info->vlan_id;
+	struct hostapd_sta_wpa_psk_short *psk = info->psk;
+	char *identity = info->identity;
+	char *radius_cui = info->radius_cui;
+
 	if (vlan_id->notempty &&
 	    !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
@@ -2113,20 +2212,22 @@
 			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 
 	hostapd_free_psk_list(sta->psk);
-	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
-		sta->psk = *psk;
-		*psk = NULL;
-	} else {
+	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+		hostapd_copy_psk_list(&sta->psk, psk);
+	else
 		sta->psk = NULL;
-	}
 
 	os_free(sta->identity);
-	sta->identity = *identity;
-	*identity = NULL;
+	if (identity)
+		sta->identity = os_strdup(identity);
+	else
+		sta->identity = NULL;
 
 	os_free(sta->radius_cui);
-	sta->radius_cui = *radius_cui;
-	*radius_cui = NULL;
+	if (radius_cui)
+		sta->radius_cui = os_strdup(radius_cui);
+	else
+		sta->radius_cui = NULL;
 
 	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
 		sta->acct_interim_interval = acct_interim_interval;
@@ -2154,14 +2255,10 @@
 	int res, reply_res;
 	u16 fc;
 	const u8 *challenge = NULL;
-	u32 session_timeout, acct_interim_interval;
-	struct vlan_description vlan_id;
-	struct hostapd_sta_wpa_psk_short *psk = NULL;
 	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
 	size_t resp_ies_len = 0;
-	char *identity = NULL;
-	char *radius_cui = NULL;
 	u16 seq_ctrl;
+	struct radius_sta rad_info;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
 		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2312,10 +2409,8 @@
 		}
 	}
 
-	res = ieee802_11_allowed_address(
-		hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
-		&acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
-		0);
+	res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+					 &rad_info);
 	if (res == HOSTAPD_ACL_REJECT) {
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 			"Ignore Authentication frame from " MACSTR
@@ -2398,9 +2493,7 @@
 	sta->auth_rssi = rssi;
 #endif /* CONFIG_MBO */
 
-	res = ieee802_11_set_radius_info(
-		hapd, sta, res, session_timeout, acct_interim_interval,
-		&vlan_id, &psk, &identity, &radius_cui);
+	res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
 	if (res) {
 		wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2471,6 +2564,7 @@
 		sta->auth_alg = WLAN_AUTH_OPEN;
 		mlme_authenticate_indication(hapd, sta);
 		break;
+#ifdef CONFIG_WEP
 #ifndef CONFIG_NO_RC4
 	case WLAN_AUTH_SHARED_KEY:
 		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@@ -2489,6 +2583,7 @@
 		}
 		break;
 #endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
 #ifdef CONFIG_IEEE80211R_AP
 	case WLAN_AUTH_FT:
 		sta->auth_alg = WLAN_AUTH_FT;
@@ -2542,11 +2637,7 @@
 	}
 
  fail:
-	os_free(identity);
-	os_free(radius_cui);
-	hostapd_free_psk_list(psk);
-
-	reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+	reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
 				    auth_transaction + 1, resp, resp_ies,
 				    resp_ies_len, "handle-auth");
 
@@ -2963,7 +3054,7 @@
 	u16 status;
 	u8 *owe_buf, ie[256 * 2];
 	size_t ie_len = 0;
-	int res;
+	enum wpa_validate_result res;
 
 	if (!rsn_ie || rsn_ie_len < 2) {
 		wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
@@ -3068,7 +3159,6 @@
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
 
-#ifdef CONFIG_IEEE80211N
 	resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
 	if (resp != WLAN_STATUS_SUCCESS)
 		return resp;
@@ -3079,7 +3169,6 @@
 			       "mandatory HT PHY - reject association");
 		return WLAN_STATUS_ASSOC_DENIED_NO_HT;
 	}
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
 	if (hapd->iconf->ieee80211ac) {
@@ -3176,7 +3265,8 @@
 	}
 
 	if (hapd->conf->wpa && wpa_ie) {
-		int res;
+		enum wpa_validate_result res;
+
 		wpa_ie -= 2;
 		wpa_ie_len += 2;
 		if (sta->wpa_sm == NULL)
@@ -3324,7 +3414,6 @@
 	pfs_fail:
 #endif /* CONFIG_DPP2 */
 
-#ifdef CONFIG_IEEE80211N
 		if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
 		    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
 			hostapd_logger(hapd, sta->addr,
@@ -3334,7 +3423,6 @@
 				       "association");
 			return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
 		}
-#endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_HS20
 	} else if (hapd->conf->osen) {
 		if (elems.osen == NULL) {
@@ -3479,7 +3567,7 @@
 	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
 	reply.u.deauth.reason_code = host_to_le16(reason_code);
 
-	if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+	if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
 		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
 			   strerror(errno));
 }
@@ -3535,10 +3623,8 @@
 		sta->ft_over_ds = 0;
 	}
 
-#ifdef CONFIG_IEEE80211N
 	if (sta->flags & WLAN_STA_HT)
 		hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
-#endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_IEEE80211AC
 	if (sta->flags & WLAN_STA_VHT)
 		hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
@@ -3586,7 +3672,8 @@
 
 static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 			   const u8 *addr, u16 status_code, int reassoc,
-			   const u8 *ies, size_t ies_len, int rssi)
+			   const u8 *ies, size_t ies_len, int rssi,
+			   int omit_rsnxe)
 {
 	int send_len;
 	u8 *buf;
@@ -3637,6 +3724,9 @@
 	/* Extended supported rates */
 	p = hostapd_eid_ext_supp_rates(hapd, p);
 
+	/* Radio measurement capabilities */
+	p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
+
 #ifdef CONFIG_MBO
 	if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
 	    rssi != 0) {
@@ -3653,7 +3743,8 @@
 		 * Transition Information, RSN, [RIC Response] */
 		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
 						buf + buflen - p,
-						sta->auth_alg, ies, ies_len);
+						sta->auth_alg, ies, ies_len,
+						omit_rsnxe);
 		if (!p) {
 			wpa_printf(MSG_DEBUG,
 				   "FT: Failed to write AssocResp IEs");
@@ -3683,10 +3774,8 @@
 	if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
 		p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
 
-#ifdef CONFIG_IEEE80211N
 	p = hostapd_eid_ht_capabilities(hapd, p);
 	p = hostapd_eid_ht_operation(hapd, p);
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
 	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
@@ -3734,7 +3823,23 @@
 	}
 #endif /* CONFIG_FST */
 
-	p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->conf->rsnxe_override_ft &&
+	    buf + buflen - p >=
+	    (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
+	    sta && sta->auth_alg == WLAN_AUTH_FT) {
+		wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
+		os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
+			  wpabuf_len(hapd->conf->rsnxe_override_ft));
+		p += wpabuf_len(hapd->conf->rsnxe_override_ft);
+		goto rsnxe_done;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+	if (!omit_rsnxe)
+		p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+rsnxe_done:
+#endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_OWE
 	if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
@@ -3865,7 +3970,7 @@
 	}
 #endif /* CONFIG_FILS */
 
-	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
+	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
 		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
 			   strerror(errno));
 		res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3880,12 +3985,12 @@
 #ifdef CONFIG_OWE
 u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
 			   const u8 *owe_dh, u8 owe_dh_len,
-			   u8 *owe_buf, size_t owe_buf_len, u16 *reason)
+			   u8 *owe_buf, size_t owe_buf_len, u16 *status)
 {
 #ifdef CONFIG_TESTING_OPTIONS
 	if (hapd->conf->own_ie_override) {
 		wpa_printf(MSG_DEBUG, "OWE: Using IE override");
-		*reason = WLAN_STATUS_SUCCESS;
+		*status = WLAN_STATUS_SUCCESS;
 		return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
 						     owe_buf_len, NULL, 0);
 	}
@@ -3895,18 +4000,18 @@
 		wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
 		owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
 							owe_buf_len, NULL, 0);
-		*reason = WLAN_STATUS_SUCCESS;
+		*status = WLAN_STATUS_SUCCESS;
 		return owe_buf;
 	}
 
 	if (sta->owe_pmk && sta->external_dh_updated) {
 		wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
-		*reason = WLAN_STATUS_SUCCESS;
+		*status = WLAN_STATUS_SUCCESS;
 		return owe_buf;
 	}
 
-	*reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
-	if (*reason != WLAN_STATUS_SUCCESS)
+	*status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+	if (*status != WLAN_STATUS_SUCCESS)
 		return NULL;
 
 	owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
@@ -3917,7 +4022,7 @@
 
 		pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
 		if (!pub) {
-			*reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			*status = WLAN_STATUS_UNSPECIFIED_FAILURE;
 			return owe_buf;
 		}
 
@@ -3952,7 +4057,7 @@
 	reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
 				    sta->fils_pending_assoc_is_reassoc,
 				    sta->fils_pending_assoc_req,
-				    sta->fils_pending_assoc_req_len, 0);
+				    sta->fils_pending_assoc_req_len, 0, 0);
 	os_free(sta->fils_pending_assoc_req);
 	sta->fils_pending_assoc_req = NULL;
 	sta->fils_pending_assoc_req_len = 0;
@@ -3997,12 +4102,10 @@
 	int left, i;
 	struct sta_info *sta;
 	u8 *tmp = NULL;
-	struct hostapd_sta_wpa_psk_short *psk = NULL;
-	char *identity = NULL;
-	char *radius_cui = NULL;
 #ifdef CONFIG_FILS
 	int delay_assoc = 0;
 #endif /* CONFIG_FILS */
+	int omit_rsnxe = 0;
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
 				      sizeof(mgmt->u.assoc_req))) {
@@ -4079,13 +4182,11 @@
 		    hapd->iface->current_mode->mode ==
 			HOSTAPD_MODE_IEEE80211AD) {
 			int acl_res;
-			u32 session_timeout, acct_interim_interval;
-			struct vlan_description vlan_id;
+			struct radius_sta info;
 
-			acl_res = ieee802_11_allowed_address(
-				hapd, mgmt->sa, (const u8 *) mgmt, len,
-				&session_timeout, &acct_interim_interval,
-				&vlan_id, &psk, &identity, &radius_cui, 0);
+			acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
+							     (const u8 *) mgmt,
+							     len, &info);
 			if (acl_res == HOSTAPD_ACL_REJECT) {
 				wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 					"Ignore Association Request frame from "
@@ -4110,9 +4211,7 @@
 			}
 
 			acl_res = ieee802_11_set_radius_info(
-				hapd, sta, acl_res, session_timeout,
-				acct_interim_interval, &vlan_id, &psk,
-				&identity, &radius_cui);
+				hapd, sta, acl_res, &info);
 			if (acl_res) {
 				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 				goto fail;
@@ -4219,6 +4318,7 @@
 	resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
 	if (resp != WLAN_STATUS_SUCCESS)
 		goto fail;
+	omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
 
 	if (hostapd_get_aid(hapd, sta) < 0) {
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -4271,9 +4371,7 @@
 			ieee802_11_set_beacons(hapd->iface);
 	}
 
-#ifdef CONFIG_IEEE80211N
 	update_ht_state(hapd, sta);
-#endif /* CONFIG_IEEE80211N */
 
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG,
@@ -4313,9 +4411,6 @@
 #endif /* CONFIG_FILS */
 
  fail:
-	os_free(identity);
-	os_free(radius_cui);
-	hostapd_free_psk_list(psk);
 
 	/*
 	 * In case of a successful response, add the station to the driver.
@@ -4377,7 +4472,7 @@
 #endif /* CONFIG_FILS */
 
 	reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
-				    left, rssi);
+				    left, rssi, omit_rsnxe);
 	os_free(tmp);
 
 	/*
@@ -4418,6 +4513,7 @@
 	ap_sta_set_authorized(hapd, sta, 0);
 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+	hostapd_set_sta_flags(hapd, sta);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "disassociated");
@@ -4484,6 +4580,7 @@
 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
 			WLAN_STA_ASSOC_REQ_OK);
+	hostapd_set_sta_flags(hapd, sta);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -4615,14 +4712,12 @@
 #endif /* CONFIG_FST */
 	case WLAN_ACTION_PUBLIC:
 	case WLAN_ACTION_PROTECTED_DUAL:
-#ifdef CONFIG_IEEE80211N
 		if (len >= IEEE80211_HDRLEN + 2 &&
 		    mgmt->u.action.u.public_action.action ==
 		    WLAN_PA_20_40_BSS_COEX) {
 			hostapd_2040_coex_action(hapd, mgmt, len);
 			return 1;
 		}
-#endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_DPP
 		if (len >= IEEE80211_HDRLEN + 6 &&
 		    mgmt->u.action.u.vs_public_action.action ==
@@ -4705,7 +4800,7 @@
 		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
 		resp->u.action.category |= 0x80;
 
-		if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+		if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
 			wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
 				   "Action frame");
 		}
@@ -4903,6 +4998,7 @@
 				       struct sta_info *sta,
 				       char *ifname_wds)
 {
+#ifdef CONFIG_WEP
 	int i;
 	struct hostapd_ssid *ssid = &hapd->conf->ssid;
 
@@ -4912,14 +5008,18 @@
 	for (i = 0; i < 4; i++) {
 		if (ssid->wep.key[i] &&
 		    hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
-					i == ssid->wep.idx, NULL, 0,
-					ssid->wep.key[i], ssid->wep.len[i])) {
+					0, i == ssid->wep.idx, NULL, 0,
+					ssid->wep.key[i], ssid->wep.len[i],
+					i == ssid->wep.idx ?
+					KEY_FLAG_GROUP_RX_TX_DEFAULT :
+					KEY_FLAG_GROUP_RX_TX)) {
 			wpa_printf(MSG_WARNING,
 				   "Could not set WEP keys for WDS interface; %s",
 				   ifname_wds);
 			break;
 		}
 	}
+#endif /* CONFIG_WEP */
 }
 
 
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index f592da5..c7bdb4b 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -16,8 +16,7 @@
 struct ieee80211_ht_capabilities;
 struct ieee80211_vht_capabilities;
 struct ieee80211_mgmt;
-struct vlan_description;
-struct hostapd_sta_wpa_psk_short;
+struct radius_sta;
 enum ieee80211_op_mode;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@@ -50,9 +49,10 @@
 u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+				  size_t len);
 u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
@@ -95,6 +95,8 @@
 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
 		      enum ieee80211_op_mode opmode, const u8 *he_capab,
 		      size_t he_capab_len);
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+				 enum ieee80211_op_mode mode);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 		       const u8 *buf, size_t len, int ack);
 void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -162,7 +164,7 @@
 				 const u8 *msk, size_t msk_len);
 u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
 			   const u8 *owe_dh, u8 owe_dh_len,
-			   u8 *owe_buf, size_t owe_buf_len, u16 *reason);
+			   u8 *owe_buf, size_t owe_buf_len, u16 *status);
 u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *rsn_ie, size_t rsn_ie_len,
 		       const u8 *owe_dh, size_t owe_dh_len);
@@ -180,13 +182,9 @@
 
 size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
 u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
-int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			       const u8 *msg, size_t len, u32 *session_timeout,
-			       u32 *acct_interim_interval,
-			       struct vlan_description *vlan_id,
-			       struct hostapd_sta_wpa_psk_short **psk,
-			       char **identity, char **radius_cui,
-			       int is_probe_req);
+
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len);
 
 int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
 		      int ap_seg1_idx, int *bandwidth, int *seg1_idx);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 931d4d0..783ee6d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -32,12 +32,7 @@
 	macaddr addr;
 	int accepted; /* HOSTAPD_ACL_* */
 	struct hostapd_cached_radius_acl *next;
-	u32 session_timeout;
-	u32 acct_interim_interval;
-	struct vlan_description vlan_id;
-	struct hostapd_sta_wpa_psk_short *psk;
-	char *identity;
-	char *radius_cui;
+	struct radius_sta info;
 };
 
 
@@ -54,9 +49,9 @@
 #ifndef CONFIG_NO_RADIUS
 static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
 {
-	os_free(e->identity);
-	os_free(e->radius_cui);
-	hostapd_free_psk_list(e->psk);
+	os_free(e->info.identity);
+	os_free(e->info.radius_cui);
+	hostapd_free_psk_list(e->info.psk);
 	os_free(e);
 }
 
@@ -73,25 +68,8 @@
 }
 
 
-static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
-			  struct hostapd_sta_wpa_psk_short *src)
-{
-	if (!psk)
-		return;
-
-	if (src)
-		src->ref++;
-
-	*psk = src;
-}
-
-
 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
-				 u32 *session_timeout,
-				 u32 *acct_interim_interval,
-				 struct vlan_description *vlan_id,
-				 struct hostapd_sta_wpa_psk_short **psk,
-				 char **identity, char **radius_cui)
+				 struct radius_sta *out)
 {
 	struct hostapd_cached_radius_acl *entry;
 	struct os_reltime now;
@@ -105,27 +83,8 @@
 		if (os_reltime_expired(&now, &entry->timestamp,
 				       RADIUS_ACL_TIMEOUT))
 			return -1; /* entry has expired */
-		if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
-			if (session_timeout)
-				*session_timeout = entry->session_timeout;
-		if (acct_interim_interval)
-			*acct_interim_interval =
-				entry->acct_interim_interval;
-		if (vlan_id)
-			*vlan_id = entry->vlan_id;
-		copy_psk_list(psk, entry->psk);
-		if (identity) {
-			if (entry->identity)
-				*identity = os_strdup(entry->identity);
-			else
-				*identity = NULL;
-		}
-		if (radius_cui) {
-			if (entry->radius_cui)
-				*radius_cui = os_strdup(entry->radius_cui);
-			else
-				*radius_cui = NULL;
-		}
+		*out = entry->info;
+
 		return entry->accepted;
 	}
 
@@ -238,42 +197,28 @@
  * @addr: MAC address of the STA
  * @msg: Authentication message
  * @len: Length of msg in octets
- * @session_timeout: Buffer for returning session timeout (from RADIUS)
- * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
- * @vlan_id: Buffer for returning VLAN ID
- * @psk: Linked list buffer for returning WPA PSK
- * @identity: Buffer for returning identity (from RADIUS)
- * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @out.session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @out.acct_interim_interval: Buffer for returning account interval (from
+ *	RADIUS)
+ * @out.vlan_id: Buffer for returning VLAN ID
+ * @out.psk: Linked list buffer for returning WPA PSK
+ * @out.identity: Buffer for returning identity (from RADIUS)
+ * @out.radius_cui: Buffer for returning CUI (from RADIUS)
  * @is_probe_req: Whether this query for a Probe Request frame
  * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
  *
- * The caller is responsible for freeing the returned *identity and *radius_cui
- * values with os_free().
+ * The caller is responsible for properly cloning the returned out->identity and
+ * out->radius_cui and out->psk values.
  */
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval,
-			    struct vlan_description *vlan_id,
-			    struct hostapd_sta_wpa_psk_short **psk,
-			    char **identity, char **radius_cui,
+			    const u8 *msg, size_t len, struct radius_sta *out,
 			    int is_probe_req)
 {
 	int res;
 
-	if (session_timeout)
-		*session_timeout = 0;
-	if (acct_interim_interval)
-		*acct_interim_interval = 0;
-	if (vlan_id)
-		os_memset(vlan_id, 0, sizeof(*vlan_id));
-	if (psk)
-		*psk = NULL;
-	if (identity)
-		*identity = NULL;
-	if (radius_cui)
-		*radius_cui = NULL;
+	os_memset(out, 0, sizeof(*out));
 
-	res = hostapd_check_acl(hapd, addr, vlan_id);
+	res = hostapd_check_acl(hapd, addr, &out->vlan_id);
 	if (res != HOSTAPD_ACL_PENDING)
 		return res;
 
@@ -290,12 +235,10 @@
 		};
 
 		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-			vlan_id = NULL;
+			os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
 
 		/* Check whether ACL cache has an entry for this station */
-		res = hostapd_acl_cache_get(hapd, addr, session_timeout,
-					    acct_interim_interval, vlan_id, psk,
-					    identity, radius_cui);
+		res = hostapd_acl_cache_get(hapd, addr, out);
 		if (res == HOSTAPD_ACL_ACCEPT ||
 		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 			return res;
@@ -307,14 +250,6 @@
 			if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
 				/* pending query in RADIUS retransmit queue;
 				 * do not generate a new one */
-				if (identity) {
-					os_free(*identity);
-					*identity = NULL;
-				}
-				if (radius_cui) {
-					os_free(*radius_cui);
-					*radius_cui = NULL;
-				}
 				return HOSTAPD_ACL_PENDING;
 			}
 			query = query->next;
@@ -488,8 +423,8 @@
 					  passphraselen);
 				psk->is_passphrase = 1;
 			}
-			psk->next = cache->psk;
-			cache->psk = psk;
+			psk->next = cache->info.psk;
+			cache->info.psk = psk;
 			psk = NULL;
 		}
 skip:
@@ -518,6 +453,7 @@
 	struct hostapd_data *hapd = data;
 	struct hostapd_acl_query_data *query, *prev;
 	struct hostapd_cached_radius_acl *cache;
+	struct radius_sta *info;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
 
 	query = hapd->acl_queries;
@@ -555,65 +491,66 @@
 	}
 	os_get_reltime(&cache->timestamp);
 	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+	info = &cache->info;
 	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
 		u8 *buf;
 		size_t len;
 
 		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
-					      &cache->session_timeout) == 0)
+					      &info->session_timeout) == 0)
 			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
 		else
 			cache->accepted = HOSTAPD_ACL_ACCEPT;
 
 		if (radius_msg_get_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
-			    &cache->acct_interim_interval) == 0 &&
-		    cache->acct_interim_interval < 60) {
+			    &info->acct_interim_interval) == 0 &&
+		    info->acct_interim_interval < 60) {
 			wpa_printf(MSG_DEBUG, "Ignored too small "
 				   "Acct-Interim-Interval %d for STA " MACSTR,
-				   cache->acct_interim_interval,
+				   info->acct_interim_interval,
 				   MAC2STR(query->addr));
-			cache->acct_interim_interval = 0;
+			info->acct_interim_interval = 0;
 		}
 
 		if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
-			cache->vlan_id.notempty = !!radius_msg_get_vlanid(
-				msg, &cache->vlan_id.untagged,
-				MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
+			info->vlan_id.notempty = !!radius_msg_get_vlanid(
+				msg, &info->vlan_id.untagged,
+				MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
 
 		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
 					msg, req, cache);
 
 		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
 					    &buf, &len, NULL) == 0) {
-			cache->identity = os_zalloc(len + 1);
-			if (cache->identity)
-				os_memcpy(cache->identity, buf, len);
+			info->identity = os_zalloc(len + 1);
+			if (info->identity)
+				os_memcpy(info->identity, buf, len);
 		}
 		if (radius_msg_get_attr_ptr(
 			    msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
 			    &buf, &len, NULL) == 0) {
-			cache->radius_cui = os_zalloc(len + 1);
-			if (cache->radius_cui)
-				os_memcpy(cache->radius_cui, buf, len);
+			info->radius_cui = os_zalloc(len + 1);
+			if (info->radius_cui)
+				os_memcpy(info->radius_cui, buf, len);
 		}
 
 		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
-		    !cache->psk)
+		    !info->psk)
 			cache->accepted = HOSTAPD_ACL_REJECT;
 
-		if (cache->vlan_id.notempty &&
-		    !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
+		if (info->vlan_id.notempty &&
+		    !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
 			hostapd_logger(hapd, query->addr,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
 				       "Invalid VLAN %d%s received from RADIUS server",
-				       cache->vlan_id.untagged,
-				       cache->vlan_id.tagged[0] ? "+" : "");
-			os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
+				       info->vlan_id.untagged,
+				       info->vlan_id.tagged[0] ? "+" : "");
+			os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
 		}
 		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
-		    !cache->vlan_id.notempty)
+		    !info->vlan_id.notempty)
 			cache->accepted = HOSTAPD_ACL_REJECT;
 	} else
 		cache->accepted = HOSTAPD_ACL_REJECT;
@@ -622,7 +559,7 @@
 
 #ifdef CONFIG_DRIVER_RADIUS_ACL
 	hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
-					cache->session_timeout);
+					info->session_timeout);
 #else /* CONFIG_DRIVER_RADIUS_ACL */
 #ifdef NEED_AP_MLME
 	/* Re-send original authentication frame for 802.11 processing */
@@ -685,6 +622,19 @@
 }
 
 
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+			   struct hostapd_sta_wpa_psk_short *src)
+{
+	if (!psk)
+		return;
+
+	if (src)
+		src->ref++;
+
+	*psk = src;
+}
+
+
 void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
 {
 	if (psk && psk->ref) {
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 5aece51..9410f55 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -16,18 +16,25 @@
 	HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
 };
 
+struct radius_sta {
+	u32 session_timeout;
+	u32 acct_interim_interval;
+	struct vlan_description vlan_id;
+	struct hostapd_sta_wpa_psk_short *psk;
+	char *identity;
+	char *radius_cui;
+};
+
 int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
 		      struct vlan_description *vlan_id);
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
-			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval,
-			    struct vlan_description *vlan_id,
-			    struct hostapd_sta_wpa_psk_short **psk,
-			    char **identity, char **radius_cui,
+			    const u8 *msg, size_t len, struct radius_sta *out,
 			    int is_probe_req);
 int hostapd_acl_init(struct hostapd_data *hapd);
 void hostapd_acl_deinit(struct hostapd_data *hapd);
 void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
 void hostapd_acl_expire(struct hostapd_data *hapd);
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+			   struct hostapd_sta_wpa_psk_short *src);
 
 #endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index abd3940..57c6b18 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -192,9 +192,12 @@
 		params |= (hapd->iface->conf->he_op.he_rts_threshold <<
 			   HE_OPERATION_RTS_THRESHOLD_OFFSET);
 
-	if (hapd->iface->conf->he_op.he_bss_color)
-		params |= (hapd->iface->conf->he_op.he_bss_color <<
-			   HE_OPERATION_BSS_COLOR_OFFSET);
+	if (hapd->iface->conf->he_op.he_bss_color_disabled)
+		params |= HE_OPERATION_BSS_COLOR_DISABLED;
+	if (hapd->iface->conf->he_op.he_bss_color_partial)
+		params |= HE_OPERATION_BSS_COLOR_PARTIAL;
+	params |= hapd->iface->conf->he_op.he_bss_color <<
+		HE_OPERATION_BSS_COLOR_OFFSET;
 
 	/* HE minimum required basic MCS and NSS for STAs */
 	oper->he_mcs_nss_set =
@@ -206,17 +209,25 @@
 
 	if (is_6ghz_op_class(hapd->iconf->op_class)) {
 		u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+		u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
 
 		if (!seg0)
 			seg0 = hapd->iconf->channel;
 
 		params |= HE_OPERATION_6GHZ_OPER_INFO;
+
+		/* 6 GHz Operation Information field */
 		*pos++ = hapd->iconf->channel; /* Primary Channel */
-		*pos++ = center_idx_to_bw_6ghz(seg0); /* Control: Channel Width
-						       */
-		/* Channel Center Freq Seg0/Seg0 */
+
+		/* Control: Channel Width */
+		if (seg1)
+			*pos++ = 3;
+		else
+			*pos++ = center_idx_to_bw_6ghz(seg0);
+
+		/* Channel Center Freq Seg0/Seg1 */
 		*pos++ = seg0;
-		*pos++ = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+		*pos++ = seg1;
 		/* Minimum Rate */
 		*pos++ = 6; /* TODO: what should be set here? */
 	}
@@ -402,3 +413,18 @@
 
 	return WLAN_STATUS_SUCCESS;
 }
+
+
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+				 enum ieee80211_op_mode mode)
+{
+	u8 *mac_cap;
+
+	if (!hapd->iface->current_mode ||
+	    !hapd->iface->current_mode->he_capab[mode].he_supported)
+		return 0;
+
+	mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
+
+	return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER);
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 6db9365..59ecbdc 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -109,33 +109,9 @@
 }
 
 
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
-{
-	u8 sec_ch;
-
-	if (!hapd->cs_freq_params.channel ||
-	    !hapd->cs_freq_params.sec_channel_offset ||
-	    is_6ghz_op_class(hapd->iconf->op_class))
-		return eid;
-
-	if (hapd->cs_freq_params.sec_channel_offset == -1)
-		sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
-	else if (hapd->cs_freq_params.sec_channel_offset == 1)
-		sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
-	else
-		return eid;
-
-	*eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
-	*eid++ = 1;
-	*eid++ = sec_ch;
-
-	return eid;
-}
-
-
 /*
 op_mode
-Set to 0 (HT pure) under the followign conditions
+Set to 0 (HT pure) under the following conditions
 	- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
 	- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
 Set to 1 (HT non-member protection) if there may be non-HT STAs
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 1e1cc38..113b4ef 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -112,7 +112,8 @@
 		end += oci_ie_len;
 	}
 #endif /* CONFIG_OCV */
-	if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
+	if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0)
+	    < 0)
 		wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
 
 	os_free(mgmt);
@@ -193,7 +194,8 @@
 		end += oci_ie_len;
 	}
 #endif /* CONFIG_OCV */
-	if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
+	if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0)
+	    < 0)
 		wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
 
 	os_free(resp);
@@ -375,6 +377,11 @@
 		    wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
 			*pos |= 0x01;
 #endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+		if (hapd->iconf->ieee80211ax &&
+		    hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+			*pos |= 0x40; /* Bit 78 - TWT responder */
+#endif /* CONFIG_IEEE80211AX */
 		break;
 	case 10: /* Bits 80-87 */
 #ifdef CONFIG_SAE
@@ -390,6 +397,8 @@
 					       * Identifiers Used Exclusively */
 		}
 #endif /* CONFIG_SAE */
+		if (hapd->conf->beacon_prot)
+			*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
 		break;
 	}
 }
@@ -438,12 +447,19 @@
 	     !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
 		len = 10;
 #endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+	if (len < 10 && hapd->iconf->ieee80211ax &&
+	    hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+		len = 10;
+#endif /* CONFIG_IEEE80211AX */
 #ifdef CONFIG_SAE
 	if (len < 11 && hapd->conf->wpa &&
 	    wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
 	    hostapd_sae_pw_id_in_use(hapd->conf))
 		len = 11;
 #endif /* CONFIG_SAE */
+	if (len < 11 && hapd->conf->beacon_prot)
+		len = 11;
 	if (len < hapd->iface->extended_capa_len)
 		len = hapd->iface->extended_capa_len;
 	if (len == 0)
@@ -858,6 +874,36 @@
 }
 
 
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_DPP2
+	if (hapd->conf->dpp_configurator_connectivity)
+		return 6;
+#endif /* CONFIG_DPP2 */
+	return 0;
+}
+
+
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+#ifdef CONFIG_DPP2
+	u8 *pos = eid;
+
+	if (!hapd->conf->dpp_configurator_connectivity || len < 6)
+		return pos;
+
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = 4;
+	WPA_PUT_BE24(pos, OUI_WFA);
+	pos += 3;
+	*pos++ = DPP_CC_OUI_TYPE;
+
+	return pos;
+#endif /* CONFIG_DPP2 */
+	return eid;
+}
+
+
 void ap_copy_sta_supp_op_classes(struct sta_info *sta,
 				 const u8 *supp_op_classes,
 				 size_t supp_op_classes_len)
@@ -1012,7 +1058,9 @@
 
 	if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
 	    !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
-	    (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2) ||
+	    (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
+	     !hostapd_sae_pw_id_in_use(hapd->conf)) ||
+	    hapd->conf->sae_pwe == 3 ||
 	    len < 3)
 		return pos;
 
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d081031..6d4d435 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -137,6 +137,7 @@
 }
 
 
+#ifdef CONFIG_WEP
 #ifndef CONFIG_FIPS
 #ifndef CONFIG_NO_RC4
 
@@ -284,8 +285,9 @@
 		/* TODO: set encryption in TX callback, i.e., only after STA
 		 * has ACKed EAPOL-Key frame */
 		if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
-					sta->addr, 0, 1, NULL, 0, ikey,
-					hapd->conf->individual_wep_key_len)) {
+					sta->addr, 0, 0, 1, NULL, 0, ikey,
+					hapd->conf->individual_wep_key_len,
+					KEY_FLAG_PAIRWISE_RX_TX)) {
 			wpa_printf(MSG_ERROR,
 				   "Could not set individual WEP encryption");
 		}
@@ -296,6 +298,7 @@
 
 #endif /* CONFIG_NO_RC4 */
 #endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
 
 
 const char *radius_mode_txt(struct hostapd_data *hapd)
@@ -2113,6 +2116,8 @@
 }
 
 
+#ifdef CONFIG_WEP
+
 static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
 {
 	struct eapol_authenticator *eapol = hapd->eapol_auth;
@@ -2177,9 +2182,10 @@
 	 * after new broadcast key has been sent to all stations. */
 	if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
 				broadcast_ether_addr,
-				eapol->default_wep_key_idx, 1, NULL, 0,
+				eapol->default_wep_key_idx, 0, 1, NULL, 0,
 				eapol->default_wep_key,
-				hapd->conf->default_wep_key_len)) {
+				hapd->conf->default_wep_key_len,
+				KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_WARNING,
 			       "failed to configure a new broadcast key");
@@ -2196,6 +2202,8 @@
 	}
 }
 
+#endif /* CONFIG_WEP */
+
 
 static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
 				  const u8 *data, size_t datalen)
@@ -2359,6 +2367,7 @@
 }
 
 
+#ifdef CONFIG_WEP
 static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
 {
 #ifndef CONFIG_FIPS
@@ -2370,6 +2379,7 @@
 #endif /* CONFIG_NO_RC4 */
 #endif /* CONFIG_FIPS */
 }
+#endif /* CONFIG_WEP */
 
 
 static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
@@ -2420,7 +2430,6 @@
 
 int ieee802_1x_init(struct hostapd_data *hapd)
 {
-	int i;
 	struct eapol_auth_config conf;
 	struct eapol_auth_cb cb;
 
@@ -2431,7 +2440,9 @@
 	conf.ctx = hapd;
 	conf.eap_reauth_period = hapd->conf->eap_reauth_period;
 	conf.wpa = hapd->conf->wpa;
+#ifdef CONFIG_WEP
 	conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
+#endif /* CONFIG_WEP */
 	conf.eap_req_id_text = hapd->conf->eap_req_id_text;
 	conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
 	conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
@@ -2446,7 +2457,9 @@
 	cb.logger = ieee802_1x_logger;
 	cb.set_port_authorized = ieee802_1x_set_port_authorized;
 	cb.abort_auth = _ieee802_1x_abort_auth;
+#ifdef CONFIG_WEP
 	cb.tx_key = _ieee802_1x_tx_key;
+#endif /* CONFIG_WEP */
 	cb.eapol_event = ieee802_1x_eapol_event;
 #ifdef CONFIG_ERP
 	cb.erp_get_key = ieee802_1x_erp_get_key;
@@ -2467,17 +2480,21 @@
 		return -1;
 #endif /* CONFIG_NO_RADIUS */
 
+#ifdef CONFIG_WEP
 	if (hapd->conf->default_wep_key_len) {
+		int i;
+
 		for (i = 0; i < 4; i++)
 			hostapd_drv_set_key(hapd->conf->iface, hapd,
-					    WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-					    NULL, 0);
+					    WPA_ALG_NONE, NULL, i, 0, 0, NULL,
+					    0, NULL, 0, KEY_FLAG_GROUP);
 
 		ieee802_1x_rekey(hapd, NULL);
 
 		if (!hapd->eapol_auth->default_wep_key)
 			return -1;
 	}
+#endif /* CONFIG_WEP */
 
 	return 0;
 }
@@ -2497,7 +2514,9 @@
 
 void ieee802_1x_deinit(struct hostapd_data *hapd)
 {
+#ifdef CONFIG_WEP
 	eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+#endif /* CONFIG_WEP */
 
 	if (hapd->driver && hapd->drv_priv &&
 	    (hapd->conf->ieee802_1x || hapd->conf->wpa))
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 4012ae4..01bf886 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -256,6 +256,8 @@
 		/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
 		if (vht)
 			bssid_info |= NEI_REP_BSSID_INFO_VHT;
+		if (he)
+			bssid_info |= NEI_REP_BSSID_INFO_HE;
 	}
 
 	/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 15e2c49..fe5f817 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -516,6 +516,11 @@
 	for (entry = pmksa->pmksa; entry; entry = entry->next) {
 		if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
 			continue;
+		if (wpa_key_mgmt_sae(entry->akmp)) {
+			if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
+				return entry;
+			continue;
+		}
 		rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
 			  entry->akmp);
 		if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index cbb8752..903be28 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -164,6 +164,7 @@
 
 	/* just in case */
 	ap_sta_set_authorized(hapd, sta, 0);
+	hostapd_set_sta_flags(hapd, sta);
 
 	if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
 		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
@@ -233,9 +234,7 @@
 	sta->assoc_ie_taxonomy = NULL;
 #endif /* CONFIG_TAXONOMY */
 
-#ifdef CONFIG_IEEE80211N
 	ht40_intolerant_remove(hapd->iface, sta);
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_P2P
 	if (sta->no_p2p_set) {
@@ -246,10 +245,10 @@
 	}
 #endif /* CONFIG_P2P */
 
-#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
+#ifdef NEED_AP_MLME
 	if (hostapd_ht_operation_update(hapd->iface) > 0)
 		set_beacon++;
-#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+#endif /* NEED_AP_MLME */
 
 #ifdef CONFIG_MESH
 	if (hapd->mesh_sta_free_cb)
@@ -373,6 +372,10 @@
 
 	os_free(sta->ifname_wds);
 
+#ifdef CONFIG_TESTING_OPTIONS
+	os_free(sta->sae_postponed_commit);
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	os_free(sta);
 }
 
@@ -542,6 +545,7 @@
 	case STA_DISASSOC_FROM_CLI:
 		ap_sta_set_authorized(hapd, sta, 0);
 		sta->flags &= ~WLAN_STA_ASSOC;
+		hostapd_set_sta_flags(hapd, sta);
 		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 		if (!sta->acct_terminate_cause)
 			sta->acct_terminate_cause =
@@ -586,7 +590,8 @@
 
 	wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
-	if (!(sta->flags & WLAN_STA_AUTH)) {
+	if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
+			    WLAN_STA_AUTHORIZED))) {
 		if (sta->flags & WLAN_STA_GAS) {
 			wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
 				   "entry " MACSTR, MAC2STR(sta->addr));
@@ -809,6 +814,7 @@
 		sta->timeout_next = STA_DEAUTH;
 	}
 	ap_sta_set_authorized(hapd, sta, 0);
+	hostapd_set_sta_flags(hapd, sta);
 	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
 		   "for " MACSTR " (%d seconds - "
 		   "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -859,6 +865,7 @@
 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
 	ap_sta_set_authorized(hapd, sta, 0);
+	hostapd_set_sta_flags(hapd, sta);
 	sta->timeout_next = STA_REMOVE;
 	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
 		   "for " MACSTR " (%d seconds - "
@@ -1024,6 +1031,13 @@
 	int ret;
 	int old_vlanid = sta->vlan_id_bound;
 
+	if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "Do not override WDS VLAN assignment for STA "
+			   MACSTR, MAC2STR(sta->addr));
+		return 0;
+	}
+
 	iface = hapd->conf->iface;
 	if (hapd->conf->ssid.vlan[0])
 		iface = hapd->conf->ssid.vlan;
@@ -1045,7 +1059,8 @@
 	if (sta->vlan_id == old_vlanid)
 		goto skip_counting;
 
-	if (sta->vlan_id > 0 && vlan == NULL) {
+	if (sta->vlan_id > 0 && !vlan &&
+	    !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
 			       "binding station to (vlan_id=%d)",
@@ -1129,6 +1144,8 @@
 	if (sta->sa_query_count > 0 &&
 	    ap_check_sa_query_timeout(hapd, sta))
 		return;
+	if (sta->sa_query_count >= 1000)
+		return;
 
 	nbuf = os_realloc_array(sta->sa_query_trans_id,
 				sta->sa_query_count + 1,
@@ -1316,9 +1333,10 @@
 	if (sta == NULL)
 		return;
 	ap_sta_set_authorized(hapd, sta, 0);
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	hostapd_set_sta_flags(hapd, sta);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
-	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
 	wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
 		   "for " MACSTR " (%d seconds - "
 		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index de806b4..8ff6ac6 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -276,6 +276,8 @@
 	int last_tk_key_idx;
 	u8 last_tk[WPA_TK_MAX_LEN];
 	size_t last_tk_len;
+	u8 *sae_postponed_commit;
+	size_t sae_postponed_commit_len;
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_AIRTIME_POLICY
 	unsigned int airtime_weight;
diff --git a/src/ap/utils.c b/src/ap/utils.c
index fcb371b..bedad6e 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -56,6 +56,10 @@
 		ohapd = iface->bss[j];
 		if (ohapd == data->hapd)
 			continue;
+#ifdef CONFIG_TESTING_OPTIONS
+		if (ohapd->conf->skip_prune_assoc)
+			continue;
+#endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_FST
 		/* Don't prune STAs belong to same FST */
 		if (ohapd->iface->fst &&
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index e293a00..53eacfb 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -22,7 +22,9 @@
 static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
 		       int existsok)
 {
-	int ret, i;
+	int ret;
+#ifdef CONFIG_WEP
+	int i;
 
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
 		if (!hapd->conf->ssid.wep.key[i])
@@ -32,6 +34,7 @@
 			   vlan->ifname);
 		return -1;
 	}
+#endif /* CONFIG_WEP */
 
 	if (!iface_exists(vlan->ifname))
 		ret = hostapd_vlan_if_add(hapd, vlan->ifname);
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 9f52dee..9ebb01e 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -111,9 +111,11 @@
 	u8 *pos = eid;
 	struct wmm_parameter_element *wmm =
 		(struct wmm_parameter_element *) (pos + 2);
-	struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 };
+	struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM];
 	int e;
 
+	os_memset(wmmp, 0, sizeof(wmmp));
+
 	if (!hapd->conf->wmm_enabled)
 		return eid;
 	wmm_calc_regulatory_limit(hapd, wmmp);
@@ -209,7 +211,7 @@
 	os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
 	len = ((u8 *) (t + 1)) - buf;
 
-	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
+	if (hostapd_drv_send_mlme(hapd, m, len, 0, NULL, 0, 0) < 0)
 		wpa_printf(MSG_INFO, "wmm_send_action: send failed");
 }
 
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index e4dcfe9..67281b3 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -54,6 +54,7 @@
 	size_t len;
 	size_t gtk_elem_len = 0;
 	size_t igtk_elem_len = 0;
+	size_t bigtk_elem_len = 0;
 	struct wnm_sleep_element wnmsleep_ie;
 	u8 *wnmtfs_ie, *oci_ie;
 	u8 wnmsleep_ie_len, oci_ie_len;
@@ -122,8 +123,10 @@
 
 #define MAX_GTK_SUBELEM_LEN 45
 #define MAX_IGTK_SUBELEM_LEN 26
+#define MAX_BIGTK_SUBELEM_LEN 26
 	mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
 			 MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+			 MAX_BIGTK_SUBELEM_LEN +
 			 oci_ie_len);
 	if (mgmt == NULL) {
 		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
@@ -157,10 +160,19 @@
 		pos += igtk_elem_len;
 		wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
 			   (int) igtk_elem_len);
+		if (hapd->conf->beacon_prot) {
+			res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
+			if (res < 0)
+				goto fail;
+			bigtk_elem_len = res;
+			pos += bigtk_elem_len;
+			wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
+				   (int) bigtk_elem_len);
+		}
 
 		WPA_PUT_LE16((u8 *)
 			     &mgmt->u.action.u.wnm_sleep_resp.keydata_len,
-			     gtk_elem_len + igtk_elem_len);
+			     gtk_elem_len + igtk_elem_len + bigtk_elem_len);
 	}
 	os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
 	/* copy TFS IE here */
@@ -176,7 +188,8 @@
 #endif /* CONFIG_OCV */
 
 	len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
-		igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
+		igtk_elem_len + bigtk_elem_len +
+		wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
 
 	/* In driver, response frame should be forced to sent when STA is in
 	 * PS mode */
@@ -189,8 +202,8 @@
 
 		/* when entering wnmsleep
 		 * 1. pause the node in driver
-		 * 2. mark the node so that AP won't update GTK/IGTK during
-		 * WNM Sleep
+		 * 2. mark the node so that AP won't update GTK/IGTK/BIGTK
+		 * during WNM Sleep
 		 */
 		if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
 		    wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
@@ -201,7 +214,7 @@
 		}
 		/* when exiting wnmsleep
 		 * 1. unmark the node
-		 * 2. start GTK/IGTK update if MFP is not used
+		 * 2. start GTK/IGTK/BIGTK update if MFP is not used
 		 * 3. unpause the node in driver
 		 */
 		if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -221,6 +234,7 @@
 
 #undef MAX_GTK_SUBELEM_LEN
 #undef MAX_IGTK_SUBELEM_LEN
+#undef MAX_BIGTK_SUBELEM_LEN
 fail:
 	os_free(wnmtfs_ie);
 	os_free(oci_ie);
@@ -508,6 +522,30 @@
 }
 
 
+static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
+					  const u8 *addr)
+{
+	struct sta_info *sta;
+
+	if (!hapd->conf->beacon_prot)
+		return;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+			   " not found for received WNM-Notification Request",
+			   MAC2STR(addr));
+		return;
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO,
+		       "Beacon protection failure reported");
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter="
+		MACSTR, MAC2STR(addr));
+}
+
+
 static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
 					       const u8 *addr, const u8 *buf,
 					       size_t len)
@@ -526,8 +564,14 @@
 		   MAC2STR(addr), dialog_token, type);
 	wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
 		    buf, len);
-	if (type == WLAN_EID_VENDOR_SPECIFIC)
+	switch (type) {
+	case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE:
+		wnm_beacon_protection_failure(hapd, addr);
+		break;
+	case WNM_NOTIF_TYPE_VENDOR_SPECIFIC:
 		mbo_ap_wnm_notification_req(hapd, addr, buf, len);
+		break;
+	}
 }
 
 
@@ -641,7 +685,7 @@
 
 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
 		   MACSTR, disassoc_timer, MAC2STR(sta->addr));
-	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
 		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
 			   "Management Request frame");
 		return -1;
@@ -714,7 +758,7 @@
 	os_memcpy(pos, url, url_len);
 	pos += url_len;
 
-	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
 		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
 			   "Management Request frame");
 		return -1;
@@ -790,7 +834,7 @@
 				  mbo_len);
 	}
 
-	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "Failed to send BSS Transition Management Request frame");
 		os_free(buf);
@@ -834,7 +878,7 @@
 	wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
 		   MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
 		   MAC2STR(sta->addr), dialog_token, auto_report, timeout);
-	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "WNM: Failed to send Collocated Interference Request frame");
 		return -1;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 6611b0e..e0ffb27 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -56,13 +56,14 @@
 				       struct wpa_group *group);
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
 			  const u8 *pmk, unsigned int pmk_len,
-			  struct wpa_ptk *ptk);
+			  struct wpa_ptk *ptk, int force_sha256);
 static void wpa_group_free(struct wpa_authenticator *wpa_auth,
 			   struct wpa_group *group);
 static void wpa_group_get(struct wpa_authenticator *wpa_auth,
 			  struct wpa_group *group);
 static void wpa_group_put(struct wpa_authenticator *wpa_auth,
 			  struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
 
 static const u32 eapol_key_timeout_first = 100; /* ms */
@@ -105,7 +106,7 @@
 static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
 				     const u8 *addr, wpa_eapol_variable var)
 {
-	if (wpa_auth->cb->get_eapol == NULL)
+	if (!wpa_auth->cb->get_eapol)
 		return -1;
 	return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
 }
@@ -117,7 +118,7 @@
 					  const u8 *prev_psk, size_t *psk_len,
 					  int *vlan_id)
 {
-	if (wpa_auth->cb->get_psk == NULL)
+	if (!wpa_auth->cb->get_psk)
 		return NULL;
 	return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
 				     prev_psk, psk_len, vlan_id);
@@ -127,7 +128,7 @@
 static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
 				   const u8 *addr, u8 *msk, size_t *len)
 {
-	if (wpa_auth->cb->get_msk == NULL)
+	if (!wpa_auth->cb->get_msk)
 		return -1;
 	return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
 }
@@ -136,21 +137,46 @@
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
+				   u8 *key, size_t key_len,
+				   enum key_flag key_flag)
 {
-	if (wpa_auth->cb->set_key == NULL)
+	if (!wpa_auth->cb->set_key)
 		return -1;
 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-				     key, key_len);
+				     key, key_len, key_flag);
 }
 
 
 static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
 				      const u8 *addr, int idx, u8 *seq)
 {
-	if (wpa_auth->cb->get_seqnum == NULL)
+	int res;
+
+	if (!wpa_auth->cb->get_seqnum)
 		return -1;
-	return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+	res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) {
+		wpa_printf(MSG_DEBUG,
+			   "TESTING: Override GTK RSC %016llx --> %016llx",
+			   (long long unsigned) WPA_GET_LE64(seq),
+			   (long long unsigned)
+			   WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override));
+		os_memcpy(seq, wpa_auth->conf.gtk_rsc_override,
+			  WPA_KEY_RSC_LEN);
+	}
+	if (!addr && idx >= 4 && idx <= 5 &&
+	    wpa_auth->conf.igtk_rsc_override_set) {
+		wpa_printf(MSG_DEBUG,
+			   "TESTING: Override IGTK RSC %016llx --> %016llx",
+			   (long long unsigned) WPA_GET_LE64(seq),
+			   (long long unsigned)
+			   WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override));
+		os_memcpy(seq, wpa_auth->conf.igtk_rsc_override,
+			  WPA_KEY_RSC_LEN);
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+	return res;
 }
 
 
@@ -158,7 +184,7 @@
 wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
 		    const u8 *data, size_t data_len, int encrypt)
 {
-	if (wpa_auth->cb->send_eapol == NULL)
+	if (!wpa_auth->cb->send_eapol)
 		return -1;
 	return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
 					encrypt);
@@ -169,7 +195,7 @@
 static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
 				      const u8 *addr)
 {
-	if (wpa_auth->cb->start_ampe == NULL)
+	if (!wpa_auth->cb->start_ampe)
 		return -1;
 	return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
 }
@@ -180,7 +206,7 @@
 			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
 			  void *cb_ctx)
 {
-	if (wpa_auth->cb->for_each_sta == NULL)
+	if (!wpa_auth->cb->for_each_sta)
 		return 0;
 	return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
 }
@@ -190,7 +216,7 @@
 			   int (*cb)(struct wpa_authenticator *a, void *ctx),
 			   void *cb_ctx)
 {
-	if (wpa_auth->cb->for_each_auth == NULL)
+	if (!wpa_auth->cb->for_each_auth)
 		return 0;
 	return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
 }
@@ -199,7 +225,7 @@
 void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
 		     logger_level level, const char *txt)
 {
-	if (wpa_auth->cb->logger == NULL)
+	if (!wpa_auth->cb->logger)
 		return;
 	wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
 }
@@ -212,7 +238,7 @@
 	int maxlen;
 	va_list ap;
 
-	if (wpa_auth->cb->logger == NULL)
+	if (!wpa_auth->cb->logger)
 		return;
 
 	maxlen = os_strlen(fmt) + 100;
@@ -233,7 +259,7 @@
 static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
 			       const u8 *addr, u16 reason)
 {
-	if (wpa_auth->cb->disconnect == NULL)
+	if (!wpa_auth->cb->disconnect)
 		return;
 	wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
 		   MAC2STR(addr), reason);
@@ -266,8 +292,8 @@
 	struct wpa_authenticator *wpa_auth = eloop_ctx;
 
 	if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
-		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
-			   "initialization.");
+		wpa_printf(MSG_ERROR,
+			   "Failed to get random data for WPA initialization.");
 	} else {
 		wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
 		wpa_hexdump_key(MSG_DEBUG, "GMK",
@@ -391,7 +417,7 @@
 	struct wpa_group *group;
 
 	group = os_zalloc(sizeof(struct wpa_group));
-	if (group == NULL)
+	if (!group)
 		return NULL;
 
 	group->GTKAuthenticator = TRUE;
@@ -399,9 +425,8 @@
 	group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
 
 	if (random_pool_ready() != 1) {
-		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
-			   "for secure operations - update keys later when "
-			   "the first station connects");
+		wpa_printf(MSG_INFO,
+			   "WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects");
 	}
 
 	/*
@@ -411,16 +436,16 @@
 	 * on embedded devices.
 	 */
 	if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
-			   "initialization.");
+		wpa_printf(MSG_ERROR,
+			   "Failed to get random data for WPA initialization.");
 		os_free(group);
 		return NULL;
 	}
 
 	group->GInit = TRUE;
 	if (delay_init) {
-		wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
-			   "until Beacon frames have been configured");
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Delay group state machine start until Beacon frames have been configured");
 		/* Initialization is completed in wpa_init_keys(). */
 	} else {
 		wpa_group_sm_step(wpa_auth, group);
@@ -447,7 +472,7 @@
 	struct wpa_authenticator *wpa_auth;
 
 	wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
-	if (wpa_auth == NULL)
+	if (!wpa_auth)
 		return NULL;
 	os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
 	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -461,7 +486,7 @@
 	}
 
 	wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
-	if (wpa_auth->group == NULL) {
+	if (!wpa_auth->group) {
 		os_free(wpa_auth->wpa_ie);
 		os_free(wpa_auth);
 		return NULL;
@@ -469,7 +494,7 @@
 
 	wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
 						wpa_auth);
-	if (wpa_auth->pmksa == NULL) {
+	if (!wpa_auth->pmksa) {
 		wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
 		os_free(wpa_auth->group);
 		os_free(wpa_auth->wpa_ie);
@@ -479,7 +504,7 @@
 
 #ifdef CONFIG_IEEE80211R_AP
 	wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
-	if (wpa_auth->ft_pmk_cache == NULL) {
+	if (!wpa_auth->ft_pmk_cache) {
 		wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
 		os_free(wpa_auth->group);
 		os_free(wpa_auth->wpa_ie);
@@ -518,8 +543,8 @@
 {
 	struct wpa_group *group = wpa_auth->group;
 
-	wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
-		   "keys");
+	wpa_printf(MSG_DEBUG,
+		   "WPA: Start group state machine to set initial keys");
 	wpa_group_sm_step(wpa_auth, group);
 	group->GInit = FALSE;
 	wpa_group_sm_step(wpa_auth, group);
@@ -575,7 +600,8 @@
 		 struct wpa_auth_config *conf)
 {
 	struct wpa_group *group;
-	if (wpa_auth == NULL)
+
+	if (!wpa_auth)
 		return 0;
 
 	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -609,7 +635,7 @@
 		return NULL;
 
 	sm = os_zalloc(sizeof(struct wpa_state_machine));
-	if (sm == NULL)
+	if (!sm)
 		return NULL;
 	os_memcpy(sm->addr, addr, ETH_ALEN);
 	if (p2p_dev_addr)
@@ -626,14 +652,13 @@
 int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
 			    struct wpa_state_machine *sm)
 {
-	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+	if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
 		return -1;
 
 #ifdef CONFIG_IEEE80211R_AP
 	if (sm->ft_completed) {
 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
-				"FT authentication already completed - do not "
-				"start 4-way handshake");
+				"FT authentication already completed - do not start 4-way handshake");
 		/* Go to PTKINITDONE state to allow GTK rekeying */
 		sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
 		sm->Pair = TRUE;
@@ -676,7 +701,7 @@
 	/* WPA/RSN was not used - clear WPA state. This is needed if the STA
 	 * reassociates back to the same AP while the previous entry for the
 	 * STA has not yet been removed. */
-	if (sm == NULL)
+	if (!sm)
 		return;
 
 	sm->wpa_key_mgmt = 0;
@@ -688,8 +713,9 @@
 #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,
+		wpa_printf(MSG_DEBUG,
+			   "P2P: Free assigned IP address %u.%u.%u.%u from "
+			   MACSTR,
 			   sm->ip_addr[0], sm->ip_addr[1],
 			   sm->ip_addr[2], sm->ip_addr[3],
 			   MAC2STR(sm->addr));
@@ -719,31 +745,34 @@
 
 void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	struct wpa_authenticator *wpa_auth;
+
+	if (!sm)
 		return;
 
-	if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
-		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"strict rekeying - force GTK rekey since STA "
-				"is leaving");
+	wpa_auth = sm->wpa_auth;
+	if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				"strict rekeying - force GTK rekey since STA is leaving");
 		if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
-					  sm->wpa_auth, NULL) == -1)
-			eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
-					       NULL);
+					  wpa_auth, NULL) == -1)
+			eloop_register_timeout(0, 500000, wpa_rekey_gtk,
+					       wpa_auth, NULL);
 	}
 
-	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+	eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
 	sm->pending_1_of_4_timeout = 0;
 	eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
-	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+	eloop_cancel_timeout(wpa_rekey_ptk, wpa_auth, sm);
 #ifdef CONFIG_IEEE80211R_AP
 	wpa_ft_sta_deinit(sm);
 #endif /* CONFIG_IEEE80211R_AP */
 	if (sm->in_step_loop) {
 		/* Must not free state machine while wpa_sm_step() is running.
 		 * Freeing will be completed in the end of wpa_sm_step(). */
-		wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
-			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Registering pending STA state machine deinit for "
+			   MACSTR, MAC2STR(sm->addr));
 		sm->pending_deinit = 1;
 	} else
 		wpa_free_sta_sm(sm);
@@ -752,11 +781,23 @@
 
 static void wpa_request_new_ptk(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	if (!sm)
 		return;
 
-	sm->PTKRequest = TRUE;
-	sm->PTK_valid = 0;
+	if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+		wpa_printf(MSG_INFO,
+			   "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+			   MAC2STR(sm->addr));
+		sm->Disconnect = TRUE;
+		/* Try to encourage the STA to reconnect */
+		sm->disconnect_reason =
+			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+	} else {
+		if (sm->use_ext_key_id)
+			sm->keyidx_active ^= 1; /* flip Key ID */
+		sm->PTKRequest = TRUE;
+		sm->PTK_valid = 0;
+	}
 }
 
 
@@ -781,7 +822,7 @@
 	int i;
 	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
 		if (ctr[i].valid &&
-		    (replay_counter == NULL ||
+		    (!replay_counter ||
 		     os_memcmp(replay_counter, ctr[i].counter,
 			       WPA_REPLAY_COUNTER_LEN) == 0))
 			ctr[i].valid = FALSE;
@@ -798,9 +839,9 @@
 	struct rsn_mdie *mdie;
 
 	if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
-	    ie.num_pmkid != 1 || ie.pmkid == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
-			   "FT 4-way handshake message 2/4");
+	    ie.num_pmkid != 1 || !ie.pmkid) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: No PMKR1Name in FT 4-way handshake message 2/4");
 		return -1;
 	}
 
@@ -809,8 +850,9 @@
 		    sm->sup_pmk_r1_name, PMKID_LEN);
 
 	if (!kde->mdie || !kde->ftie) {
-		wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
-			   "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+		wpa_printf(MSG_DEBUG,
+			   "FT: No %s in FT 4-way handshake message 2/4",
+			   kde->mdie ? "FTIE" : "MDIE");
 		return -1;
 	}
 
@@ -844,18 +886,15 @@
 {
 	/* Supplicant reported a Michael MIC error */
 	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-			 "received EAPOL-Key Error Request "
-			 "(STA detected Michael MIC failure (group=%d))",
+			 "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))",
 			 group);
 
 	if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-				"ignore Michael MIC failure report since "
-				"group cipher is not TKIP");
+				"ignore Michael MIC failure report since group cipher is not TKIP");
 	} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-				"ignore Michael MIC failure report since "
-				"pairwise cipher is not TKIP");
+				"ignore Michael MIC failure report since pairwise cipher is not TKIP");
 	} else {
 		if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
 			return 1; /* STA entry was removed */
@@ -888,7 +927,7 @@
 			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
 					       sm->p2p_dev_addr, pmk, &pmk_len,
 					       &vlan_id);
-			if (pmk == NULL)
+			if (!pmk)
 				break;
 #ifdef CONFIG_IEEE80211R_AP
 			if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -901,7 +940,8 @@
 			pmk_len = sm->pmk_len;
 		}
 
-		if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+		if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+		    0)
 			break;
 
 		if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -956,7 +996,7 @@
 	size_t keyhdrlen, mic_len;
 	u8 *mic;
 
-	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+	if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
 		return;
 	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
 
@@ -975,20 +1015,19 @@
 	key_data = mic + mic_len + 2;
 	key_data_length = WPA_GET_BE16(mic + mic_len);
 	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
-		   " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
+		   " key_info=0x%x type=%u mic_len=%zu key_data_length=%u",
 		   MAC2STR(sm->addr), key_info, key->type,
-		   (unsigned int) mic_len, key_data_length);
+		   mic_len, key_data_length);
 	wpa_hexdump(MSG_MSGDUMP,
 		    "WPA: EAPOL-Key header (ending before Key MIC)",
 		    key, sizeof(*key));
 	wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
 		    mic, mic_len);
 	if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
-		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
-			   "key_data overflow (%d > %lu)",
+		wpa_printf(MSG_INFO,
+			   "WPA: Invalid EAPOL-Key frame - key_data overflow (%d > %zu)",
 			   key_data_length,
-			   (unsigned long) (data_len - sizeof(*hdr) -
-					    keyhdrlen));
+			   data_len - sizeof(*hdr) - keyhdrlen);
 		return;
 	}
 
@@ -998,18 +1037,18 @@
 			 * Some deployed station implementations seem to send
 			 * msg 4/4 with incorrect type value in WPA2 mode.
 			 */
-			wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
-				   "with unexpected WPA type in RSN mode");
+			wpa_printf(MSG_DEBUG,
+				   "Workaround: Allow EAPOL-Key with unexpected WPA type in RSN mode");
 		} else if (key->type != EAPOL_KEY_TYPE_RSN) {
-			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
-				   "unexpected type %d in RSN mode",
+			wpa_printf(MSG_DEBUG,
+				   "Ignore EAPOL-Key with unexpected type %d in RSN mode",
 				   key->type);
 			return;
 		}
 	} else {
 		if (key->type != EAPOL_KEY_TYPE_WPA) {
-			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
-				   "unexpected type %d in WPA mode",
+			wpa_printf(MSG_DEBUG,
+				   "Ignore EAPOL-Key with unexpected type %d in WPA mode",
 				   key->type);
 			return;
 		}
@@ -1054,9 +1093,7 @@
 			    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
 				wpa_auth_logger(wpa_auth, sm->addr,
 						LOGGER_WARNING,
-						"advertised support for "
-						"AES-128-CMAC, but did not "
-						"use it");
+						"advertised support for AES-128-CMAC, but did not use it");
 				return;
 			}
 
@@ -1065,8 +1102,7 @@
 			    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 				wpa_auth_logger(wpa_auth, sm->addr,
 						LOGGER_WARNING,
-						"did not use HMAC-SHA1-AES "
-						"with CCMP/GCMP");
+						"did not use HMAC-SHA1-AES with CCMP/GCMP");
 				return;
 			}
 		}
@@ -1084,8 +1120,7 @@
 		    os_memcmp(key->replay_counter, sm->req_replay_counter,
 			      WPA_REPLAY_COUNTER_LEN) <= 0) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
-					"received EAPOL-Key request with "
-					"replayed counter");
+					"received EAPOL-Key request with replayed counter");
 			return;
 		}
 	}
@@ -1108,9 +1143,7 @@
 			 * even if we have already sent out EAPOL-Key 3/4.
 			 */
 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-					 "Process SNonce update from STA "
-					 "based on retransmitted EAPOL-Key "
-					 "1/4");
+					 "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
 			sm->update_snonce = 1;
 			os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
 			sm->alt_snonce_valid = TRUE;
@@ -1139,12 +1172,12 @@
 					     key->replay_counter) &&
 		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-					 "ignore retransmitted EAPOL-Key %s - "
-					 "SNonce did not change", msgtxt);
+					 "ignore retransmitted EAPOL-Key %s - SNonce did not change",
+					 msgtxt);
 		} else {
 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-					 "received EAPOL-Key %s with "
-					 "unexpected replay counter", msgtxt);
+					 "received EAPOL-Key %s with unexpected replay counter",
+					 msgtxt);
 		}
 		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
 			if (!sm->key_replay[i].valid)
@@ -1175,8 +1208,7 @@
 		    (!sm->update_snonce ||
 		     sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-					 "received EAPOL-Key msg 2/4 in "
-					 "invalid state (%d) - dropped",
+					 "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped",
 					 sm->wpa_ptk_state);
 			return;
 		}
@@ -1191,9 +1223,8 @@
 			 * Counter update and the station will be allowed to
 			 * continue.
 			 */
-			wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
-				   "collect more entropy for random number "
-				   "generation");
+			wpa_printf(MSG_DEBUG,
+				   "WPA: Reject 4-way handshake to collect more entropy for random number generation");
 			random_mark_pool_ready();
 			wpa_sta_disconnect(wpa_auth, sm->addr,
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1204,8 +1235,7 @@
 		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
 		    !sm->PTK_valid) {
 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-					 "received EAPOL-Key msg 4/4 in "
-					 "invalid state (%d) - dropped",
+					 "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped",
 					 sm->wpa_ptk_state);
 			return;
 		}
@@ -1214,8 +1244,7 @@
 		if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
 		    || !sm->PTK_valid) {
 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-					 "received EAPOL-Key msg 2/2 in "
-					 "invalid state (%d) - dropped",
+					 "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped",
 					 sm->wpa_ptk_group_state);
 			return;
 		}
@@ -1294,8 +1323,7 @@
 				  WPA_REPLAY_COUNTER_LEN);
 		} else {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key request with "
-					"invalid MIC");
+					"received EAPOL-Key request with invalid MIC");
 			return;
 		}
 
@@ -1311,8 +1339,7 @@
 				return; /* STA entry was removed */
 		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Request for new "
-					"4-Way Handshake");
+					"received EAPOL-Key Request for new 4-Way Handshake");
 			wpa_request_new_ptk(sm);
 		} else if (key_data_length > 0 &&
 			   wpa_parse_kde_ies(key_data, key_data_length,
@@ -1320,8 +1347,7 @@
 			   kde.mac_addr) {
 		} else {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Request for GTK "
-					"rekeying");
+					"received EAPOL-Key Request for GTK rekeying");
 			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
 			wpa_rekey_gtk(wpa_auth, NULL);
 		}
@@ -1354,7 +1380,7 @@
 
 	os_free(sm->last_rx_eapol_key);
 	sm->last_rx_eapol_key = os_memdup(data, data_len);
-	if (sm->last_rx_eapol_key == NULL)
+	if (!sm->last_rx_eapol_key)
 		return;
 	sm->last_rx_eapol_key_len = data_len;
 
@@ -1433,6 +1459,7 @@
 		      const u8 *kde, size_t kde_len,
 		      int keyidx, int encr, int force_version)
 {
+	struct wpa_auth_config *conf = &wpa_auth->conf;
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
 	size_t len, mic_len, keyhdrlen;
@@ -1461,15 +1488,14 @@
 
 	pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
 
-	wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
-		   "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
-		   "encr=%d)",
+	wpa_printf(MSG_DEBUG,
+		   "WPA: Send EAPOL(version=%d secure=%d mic=%d ack=%d install=%d pairwise=%d kde_len=%zu keyidx=%d encr=%d)",
 		   version,
 		   (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
 		   (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
 		   (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
 		   (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
-		   pairwise, (unsigned long) kde_len, keyidx, encr);
+		   pairwise, kde_len, keyidx, encr);
 
 	key_data_len = kde_len;
 
@@ -1487,9 +1513,9 @@
 		len += AES_BLOCK_SIZE;
 
 	hdr = os_zalloc(len);
-	if (hdr == NULL)
+	if (!hdr)
 		return;
-	hdr->version = wpa_auth->conf.eapol_version;
+	hdr->version = conf->eapol_version;
 	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
 	hdr->length = host_to_be16(len  - sizeof(*hdr));
 	key = (struct wpa_eapol_key *) (hdr + 1);
@@ -1505,7 +1531,7 @@
 		key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
 	WPA_PUT_BE16(key->key_info, key_info);
 
-	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+	alg = pairwise ? sm->pairwise : conf->wpa_group;
 	if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
 		WPA_PUT_BE16(key->key_length, 0);
 	else
@@ -1559,7 +1585,7 @@
 #endif /* CONFIG_FILS */
 	} else if (encr && kde) {
 		buf = os_zalloc(key_data_len);
-		if (buf == NULL) {
+		if (!buf) {
 			os_free(hdr);
 			return;
 		}
@@ -1576,8 +1602,8 @@
 		    wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
 		    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
 			wpa_printf(MSG_DEBUG,
-				   "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",
-				   (unsigned int) sm->PTK.kek_len);
+				   "WPA: Encrypt Key Data using AES-WRAP (KEK length %zu)",
+				   sm->PTK.kek_len);
 			if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
 				     (key_data_len - 8) / 8, buf, key_data)) {
 				os_free(hdr);
@@ -1611,8 +1637,7 @@
 	if (key_info & WPA_KEY_INFO_MIC) {
 		if (!sm->PTK_valid || !mic_len) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
-					"PTK not valid when sending EAPOL-Key "
-					"frame");
+					"PTK not valid when sending EAPOL-Key frame");
 			os_free(hdr);
 			return;
 		}
@@ -1625,9 +1650,8 @@
 		}
 #ifdef CONFIG_TESTING_OPTIONS
 		if (!pairwise &&
-		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
-		    drand48() <
-		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+		    conf->corrupt_gtk_rekey_mic_probability > 0.0 &&
+		    drand48() < conf->corrupt_gtk_rekey_mic_probability) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"Corrupting group EAPOL-Key Key MIC");
 			key_mic[0]++;
@@ -1635,8 +1659,7 @@
 #endif /* CONFIG_TESTING_OPTIONS */
 	}
 
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
-			   1);
+	wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
 	wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
 			    sm->pairwise_set);
 	os_free(hdr);
@@ -1653,7 +1676,7 @@
 	int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
 	u32 ctr;
 
-	if (sm == NULL)
+	if (!sm)
 		return;
 
 	__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
@@ -1673,8 +1696,9 @@
 #ifdef TEST_FUZZ
 	timeout_ms = 1;
 #endif /* TEST_FUZZ */
-	wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
-		   "counter %u)", timeout_ms, ctr);
+	wpa_printf(MSG_DEBUG,
+		   "WPA: Use EAPOL-Key timeout of %u ms (retry counter %u)",
+		   timeout_ms, ctr);
 	eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
 			       wpa_send_eapol_timeout, wpa_auth, sm);
 }
@@ -1714,9 +1738,14 @@
 	sm->PTK_valid = FALSE;
 	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
 	if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
-			     0))
+			     0, KEY_FLAG_PAIRWISE))
 		wpa_printf(MSG_DEBUG,
 			   "RSN: PTK removal from the driver failed");
+	if (sm->use_ext_key_id &&
+	    wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL,
+			     0, KEY_FLAG_PAIRWISE))
+		wpa_printf(MSG_DEBUG,
+			   "RSN: PTK Key ID 1 removal from the driver failed");
 	sm->pairwise_set = FALSE;
 	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
 }
@@ -1726,7 +1755,7 @@
 {
 	int remove_ptk = 1;
 
-	if (sm == NULL)
+	if (!sm)
 		return -1;
 
 	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -1766,8 +1795,8 @@
 			 * sure that the WPA state machines gets initialized
 			 * properly at this point.
 			 */
-			wpa_printf(MSG_DEBUG, "WPA state machine had not been "
-				   "started - initialize now");
+			wpa_printf(MSG_DEBUG,
+				   "WPA state machine had not been started - initialize now");
 			sm->started = 1;
 			sm->Init = TRUE;
 			if (wpa_sm_step(sm) == 1)
@@ -1776,6 +1805,22 @@
 			sm->AuthenticationRequest = TRUE;
 			break;
 		}
+
+		if (!sm->use_ext_key_id &&
+		    sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+			wpa_printf(MSG_INFO,
+				   "WPA: PTK0 rekey not allowed, disconnect "
+				   MACSTR, MAC2STR(sm->addr));
+			sm->Disconnect = TRUE;
+			/* Try to encourage the STA to reconnect */
+			sm->disconnect_reason =
+				WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+			break;
+		}
+
+		if (sm->use_ext_key_id)
+			sm->keyidx_active ^= 1; /* flip Key ID */
+
 		if (sm->GUpdateStationKeys) {
 			/*
 			 * Reauthentication cancels the pending group key
@@ -1789,8 +1834,8 @@
 		break;
 	case WPA_ASSOC_FT:
 #ifdef CONFIG_IEEE80211R_AP
-		wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
-			   "after association");
+		wpa_printf(MSG_DEBUG,
+			   "FT: Retry PTK configuration after association");
 		wpa_ft_install_ptk(sm);
 
 		/* Using FT protocol, not WPA auth state machine */
@@ -1923,11 +1968,11 @@
 	 * GMK and Counter here to improve their strength if there was not
 	 * enough entropy available immediately after system startup.
 	 */
-	wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
-		   "station");
+	wpa_printf(MSG_DEBUG,
+		   "WPA: Re-initialize GMK/Counter on first station");
 	if (random_pool_ready() != 1) {
-		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
-			   "to proceed - reject first 4-way handshake");
+		wpa_printf(MSG_INFO,
+			   "WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake");
 		group->reject_4way_hs_for_entropy = TRUE;
 	} else {
 		group->first_sta_seen = TRUE;
@@ -1961,8 +2006,8 @@
 	 * stronger protection against potential precomputation attacks.
 	 */
 	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
-		wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
-			   "ANonce.");
+		wpa_printf(MSG_ERROR,
+			   "WPA: Failed to get random data for ANonce.");
 		sm->Disconnect = TRUE;
 		return;
 	}
@@ -2019,13 +2064,13 @@
 			pmk_len = PMK_LEN_SUITE_B_192;
 		else
 			pmk_len = PMK_LEN;
-		wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
-			   "(MSK len=%lu PMK len=%u)", (unsigned long) len,
-			   pmk_len);
+		wpa_printf(MSG_DEBUG,
+			   "WPA: PMK from EAPOL state machine (MSK len=%zu PMK len=%u)",
+			   len, pmk_len);
 		if (len < pmk_len) {
 			wpa_printf(MSG_DEBUG,
-				   "WPA: MSK not long enough (%u) to create PMK (%u)",
-				   (unsigned int) len, (unsigned int) pmk_len);
+				   "WPA: MSK not long enough (%zu) to create PMK (%u)",
+				   len, pmk_len);
 			sm->Disconnect = TRUE;
 			return;
 		}
@@ -2208,10 +2253,11 @@
 
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
 			  const u8 *pmk, unsigned int pmk_len,
-			  struct wpa_ptk *ptk)
+			  struct wpa_ptk *ptk, int force_sha256)
 {
 	const u8 *z = NULL;
 	size_t z_len = 0;
+	int akmp;
 
 #ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -2237,9 +2283,12 @@
 	}
 #endif /* CONFIG_DPP2 */
 
+	akmp = sm->wpa_key_mgmt;
+	if (force_sha256)
+		akmp |= WPA_KEY_MGMT_PSK_SHA256;
 	return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
 			      sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
-			      ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
+			      ptk, akmp, sm->pairwise, z, z_len);
 }
 
 
@@ -2453,9 +2502,9 @@
 
 	if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
 		wpa_printf(MSG_DEBUG,
-			   "FILS: Unexpected Key-Auth length %d (expected %d)",
+			   "FILS: Unexpected Key-Auth length %d (expected %zu)",
 			   elems.fils_key_confirm_len,
-			   (int) sm->fils_key_auth_len);
+			   sm->fils_key_auth_len);
 		return -1;
 	}
 
@@ -2648,8 +2697,13 @@
 	u8 *gtk, dummy_gtk[32];
 	size_t gtk_len;
 	struct wpa_group *gsm;
+	size_t plain_len;
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
 
-	plain = wpabuf_alloc(1000);
+	plain_len = 1000 + ieee80211w_kde_len(sm);
+	if (conf->transition_disable)
+		plain_len += 2 + RSN_SELECTOR_LEN + 1;
+	plain = wpabuf_alloc(plain_len);
 	if (!plain)
 		return NULL;
 
@@ -2678,8 +2732,7 @@
 	/* GTK KDE */
 	gtk = gsm->GTK[gsm->GN - 1];
 	gtk_len = gsm->GTK_len;
-	if (sm->wpa_auth->conf.disable_gtk ||
-	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+	if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
 		/*
 		 * Provide unique random GTK to each STA to prevent use
 		 * of GTK in the BSS.
@@ -2697,11 +2750,18 @@
 			   gtk, gtk_len);
 	wpabuf_put(plain, tmp2 - tmp);
 
-	/* IGTK KDE */
+	/* IGTK KDE and BIGTK KDE */
 	tmp = wpabuf_put(plain, 0);
 	tmp2 = ieee80211w_kde_add(sm, tmp);
 	wpabuf_put(plain, tmp2 - tmp);
 
+	if (conf->transition_disable) {
+		tmp = wpabuf_put(plain, 0);
+		tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE,
+				   &conf->transition_disable, 1, NULL, 0);
+		wpabuf_put(plain, tmp2 - tmp);
+	}
+
 	*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
 
 #ifdef CONFIG_OCV
@@ -2747,7 +2807,7 @@
 
 	wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk, klen)) {
+			     sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
 		wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
 		return -1;
 	}
@@ -2779,8 +2839,8 @@
 	os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
 	pos += wpabuf_len(plain);
 
-	wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
-		   (unsigned int) wpabuf_len(plain));
+	wpa_printf(MSG_DEBUG, "%s: plain buf_len: %zu", __func__,
+		   wpabuf_len(plain));
 	wpabuf_clear_free(plain);
 	sm->fils_completed = 1;
 	return pos;
@@ -2819,6 +2879,7 @@
 	struct wpa_eapol_key *key;
 	struct wpa_eapol_ie_parse kde;
 	int vlan_id = 0;
+	int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
 
 	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
 	sm->EAPOLKeyReceived = FALSE;
@@ -2836,7 +2897,7 @@
 			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
 					       sm->p2p_dev_addr, pmk, &pmk_len,
 					       &vlan_id);
-			if (pmk == NULL)
+			if (!pmk)
 				break;
 			psk_found = 1;
 #ifdef CONFIG_IEEE80211R_AP
@@ -2856,7 +2917,8 @@
 			pmk_len = sm->pmksa->pmk_len;
 		}
 
-		if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+		if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+				   owe_ptk_workaround == 2) < 0)
 			break;
 
 		if (mic_len &&
@@ -2880,6 +2942,16 @@
 		}
 #endif /* CONFIG_FILS */
 
+#ifdef CONFIG_OWE
+		if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+		    owe_ptk_workaround == 1) {
+			wpa_printf(MSG_DEBUG,
+				   "OWE: Try PTK derivation workaround with SHA256");
+			owe_ptk_workaround = 2;
+			continue;
+		}
+#endif /* CONFIG_OWE */
+
 		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
 		    wpa_key_mgmt_sae(sm->wpa_key_mgmt))
 			break;
@@ -2922,7 +2994,7 @@
 		eapol_key_ie_len = kde.wpa_ie_len;
 	}
 	ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
-	if (sm->wpa_ie == NULL ||
+	if (!sm->wpa_ie ||
 	    wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
 			       eapol_key_ie, eapol_key_ie_len)) {
 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -3016,10 +3088,9 @@
 		if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
 				    WPA_PMK_NAME_LEN) != 0) {
 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-					"PMKR1Name mismatch in FT 4-way "
-					"handshake");
-			wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
-				    "Supplicant",
+					"PMKR1Name mismatch in FT 4-way handshake");
+			wpa_hexdump(MSG_DEBUG,
+				    "FT: PMKR1Name from Supplicant",
 				    sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
 			wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
 				    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
@@ -3063,22 +3134,29 @@
 
 static int ieee80211w_kde_len(struct wpa_state_machine *sm)
 {
+	size_t len = 0;
+
 	if (sm->mgmt_frame_prot) {
-		size_t len;
-		len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
-		return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
+		len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+		len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+	}
+	if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
+		len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
+		len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
 	}
 
-	return 0;
+	return len;
 }
 
 
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
 {
 	struct wpa_igtk_kde igtk;
+	struct wpa_bigtk_kde bigtk;
 	struct wpa_group *gsm = sm->group;
 	u8 rsc[WPA_KEY_RSC_LEN];
-	size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+	size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
 
 	if (!sm->mgmt_frame_prot)
 		return pos;
@@ -3091,8 +3169,7 @@
 	else
 		os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
 	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
-	if (sm->wpa_auth->conf.disable_gtk ||
-	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+	if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
 		/*
 		 * Provide unique random IGTK to each STA to prevent use of
 		 * IGTK in the BSS.
@@ -3104,6 +3181,21 @@
 			  (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
 			  NULL, 0);
 
+	if (!conf->beacon_prot)
+		return pos;
+
+	bigtk.keyid[0] = gsm->GN_bigtk;
+	bigtk.keyid[1] = 0;
+	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+		os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+	else
+		os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+	os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+			  (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+			  NULL, 0);
+
 	return pos;
 }
 
@@ -3138,41 +3230,73 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
+		       const u8 *ie, size_t ie_len)
+{
+	const u8 *elem;
+	u8 *buf;
+
+	wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name);
+	wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override",
+		    old_buf, *len);
+	buf = os_malloc(*len + ie_len);
+	if (!buf)
+		return NULL;
+	os_memcpy(buf, old_buf, *len);
+	elem = get_ie(buf, *len, eid);
+	if (elem) {
+		u8 elem_len = 2 + elem[1];
+
+		os_memmove((void *) elem, elem + elem_len,
+			   *len - (elem - buf) - elem_len);
+		*len -= elem_len;
+	}
+	os_memcpy(buf + *len, ie, ie_len);
+	*len += ie_len;
+	wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override",
+		    buf, *len);
+
+	return buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 {
 	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
-	size_t gtk_len, kde_len;
+	size_t gtk_len, kde_len, wpa_ie_len;
 	struct wpa_group *gsm = sm->group;
 	u8 *wpa_ie;
-	int wpa_ie_len, secure, gtkidx, encr = 0;
-	u8 *wpa_ie_buf = NULL;
+	int secure, gtkidx, encr = 0;
+	u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+	u8 hdr[2];
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
 
 	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
 	sm->TimeoutEvt = FALSE;
 
 	sm->TimeoutCtr++;
-	if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
-	    sm->TimeoutCtr > 1) {
+	if (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1) {
 		/* Do not allow retransmission of EAPOL-Key msg 3/4 */
 		return;
 	}
-	if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
+	if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
 		/* No point in sending the EAPOL-Key - we will disconnect
 		 * immediately following this. */
 		return;
 	}
 
 	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
-	   GTK[GN], IGTK, [FTIE], [TIE * 2])
+	   GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
 	 */
 	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
 	/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
 	wpa_ie = sm->wpa_auth->wpa_ie;
 	wpa_ie_len = sm->wpa_auth->wpa_ie_len;
-	if (sm->wpa == WPA_VERSION_WPA &&
-	    (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
-	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+	if (sm->wpa == WPA_VERSION_WPA && (conf->wpa & WPA_PROTO_RSN) &&
+	    wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
 		/* WPA-only STA, remove RSN IE and possible MDIE */
 		wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
@@ -3180,42 +3304,45 @@
 		wpa_ie_len = wpa_ie[1] + 2;
 	}
 #ifdef CONFIG_TESTING_OPTIONS
-	if (sm->wpa_auth->conf.rsnxe_override_eapol_len) {
-		u8 *obuf = sm->wpa_auth->conf.rsnxe_override_eapol;
-		size_t olen = sm->wpa_auth->conf.rsnxe_override_eapol_len;
-		const u8 *rsnxe;
-
-		wpa_hexdump(MSG_DEBUG,
-			    "TESTING: wpa_ie before RSNXE EAPOL override",
-			    wpa_ie, wpa_ie_len);
-		wpa_ie_buf = os_malloc(wpa_ie_len + olen);
+	if (conf->rsne_override_eapol_set) {
+		wpa_ie_buf2 = replace_ie(
+			"RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN,
+			conf->rsne_override_eapol,
+			conf->rsne_override_eapol_len);
+		if (!wpa_ie_buf2)
+			goto done;
+		wpa_ie = wpa_ie_buf2;
+	}
+	if (conf->rsnxe_override_eapol_set) {
+		wpa_ie_buf = replace_ie(
+			"RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX,
+			conf->rsnxe_override_eapol,
+			conf->rsnxe_override_eapol_len);
 		if (!wpa_ie_buf)
-			return;
-		os_memcpy(wpa_ie_buf, wpa_ie, wpa_ie_len);
+			goto done;
 		wpa_ie = wpa_ie_buf;
-		rsnxe = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_RSNX);
-		if (rsnxe) {
-			u8 rsnxe_len = 2 + rsnxe[1];
-
-			os_memmove((void *) rsnxe, rsnxe + rsnxe_len,
-				   wpa_ie_len - (rsnxe - wpa_ie) - rsnxe_len);
-			wpa_ie_len -= rsnxe_len;
-		}
-		os_memcpy(wpa_ie + wpa_ie_len, obuf, olen);
-		wpa_ie_len += olen;
-		wpa_hexdump(MSG_DEBUG,
-			    "TESTING: wpa_ie after RSNXE EAPOL override",
-			    wpa_ie, wpa_ie_len);
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
 			"sending 3/4 msg of 4-Way Handshake");
 	if (sm->wpa == WPA_VERSION_WPA2) {
+		if (sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
+		    wpa_auth_set_key(sm->wpa_auth, 0,
+				     wpa_cipher_to_alg(sm->pairwise),
+				     sm->addr,
+				     sm->keyidx_active, sm->PTK.tk,
+				     wpa_cipher_key_len(sm->pairwise),
+				     KEY_FLAG_PAIRWISE_RX)) {
+			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+					   WLAN_REASON_PREV_AUTH_NOT_VALID);
+			return;
+		}
+
 		/* WPA2 send GTK in the 4-way handshake */
 		secure = 1;
 		gtk = gsm->GTK[gsm->GN - 1];
 		gtk_len = gsm->GTK_len;
-		if (sm->wpa_auth->conf.disable_gtk ||
+		if (conf->disable_gtk ||
 		    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
 			/*
 			 * Provide unique random GTK to each STA to prevent use
@@ -3244,13 +3371,16 @@
 			 * WPA if the supplicant used it first.
 			 */
 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-					"STA used Secure bit in WPA msg 2/4 - "
-					"set Secure for 3/4 as workaround");
+					"STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
 			secure = 1;
 		}
 	}
 
 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+	if (sm->use_ext_key_id)
+		kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
 	if (gtk)
 		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
 #ifdef CONFIG_IEEE80211R_AP
@@ -3263,8 +3393,12 @@
 	if (WPA_GET_BE32(sm->ip_addr) > 0)
 		kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
 #endif /* CONFIG_P2P */
+
+	if (conf->transition_disable)
+		kde_len += 2 + RSN_SELECTOR_LEN + 1;
+
 	kde = os_malloc(kde_len);
-	if (kde == NULL)
+	if (!kde)
 		goto done;
 
 	pos = kde;
@@ -3278,18 +3412,23 @@
 		elen = pos - kde;
 		res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
 		if (res < 0) {
-			wpa_printf(MSG_ERROR, "FT: Failed to insert "
-				   "PMKR1Name into RSN IE in EAPOL-Key data");
+			wpa_printf(MSG_ERROR,
+				   "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
 			goto done;
 		}
 		pos -= wpa_ie_len;
 		pos += elen;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
+	hdr[1] = 0;
+
+	if (sm->use_ext_key_id) {
+		hdr[0] = sm->keyidx_active & 0x01;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+	}
+
 	if (gtk) {
-		u8 hdr[2];
 		hdr[0] = gtkidx & 0x03;
-		hdr[1] = 0;
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gtk_len);
 	}
@@ -3300,9 +3439,7 @@
 #ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
 		int res;
-		struct wpa_auth_config *conf;
 
-		conf = &sm->wpa_auth->conf;
 		if (sm->assoc_resp_ftie &&
 		    kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
 			os_memcpy(pos, sm->assoc_resp_ftie,
@@ -3316,11 +3453,11 @@
 					     conf->r0_key_holder_len,
 					     NULL, NULL, pos,
 					     kde + kde_len - pos,
-					     NULL, 0);
+					     NULL, 0, 0);
 		}
 		if (res < 0) {
-			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
-				   "into EAPOL-Key Key Data");
+			wpa_printf(MSG_ERROR,
+				   "FT: Failed to insert FTIE into EAPOL-Key Key Data");
 			goto done;
 		}
 		pos += res;
@@ -3344,13 +3481,17 @@
 	if (WPA_GET_BE32(sm->ip_addr) > 0) {
 		u8 addr[3 * 4];
 		os_memcpy(addr, sm->ip_addr, 4);
-		os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
-		os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+		os_memcpy(addr + 4, conf->ip_addr_mask, 4);
+		os_memcpy(addr + 8, conf->ip_addr_go, 4);
 		pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
 				  addr, sizeof(addr), NULL, 0);
 	}
 #endif /* CONFIG_P2P */
 
+	if (conf->transition_disable)
+		pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE,
+				  &conf->transition_disable, 1, NULL, 0);
+
 	wpa_send_eapol(sm->wpa_auth, sm,
 		       (secure ? WPA_KEY_INFO_SECURE : 0) |
 		       (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
@@ -3361,6 +3502,7 @@
 done:
 	os_free(kde);
 	os_free(wpa_ie_buf);
+	os_free(wpa_ie_buf2);
 }
 
 
@@ -3371,8 +3513,17 @@
 	if (sm->Pair) {
 		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
 		int klen = wpa_cipher_key_len(sm->pairwise);
-		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-				     sm->PTK.tk, klen)) {
+		int res;
+
+		if (sm->use_ext_key_id)
+			res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+					       sm->keyidx_active, NULL, 0,
+					       KEY_FLAG_PAIRWISE_RX_TX_MODIFY);
+		else
+			res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr,
+					       0, sm->PTK.tk, klen,
+					       KEY_FLAG_PAIRWISE_RX_TX);
+		if (res) {
 			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 			return;
@@ -3419,6 +3570,7 @@
 SM_STEP(WPA_PTK)
 {
 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+	struct wpa_auth_config *conf = &wpa_auth->conf;
 
 	if (sm->Init)
 		SM_ENTER(WPA_PTK, INITIALIZE);
@@ -3453,7 +3605,7 @@
 		break;
 	case WPA_PTK_AUTHENTICATION2:
 		if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
-		    wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+		    wpa_auth_get_eapol(wpa_auth, sm->addr,
 				       WPA_EAPOL_keyRun) > 0)
 			SM_ENTER(WPA_PTK, INITPMK);
 		else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
@@ -3464,7 +3616,7 @@
 			SM_ENTER(WPA_PTK, INITPMK);
 		break;
 	case WPA_PTK_INITPMK:
-		if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+		if (wpa_auth_get_eapol(wpa_auth, sm->addr,
 				       WPA_EAPOL_keyAvailable) > 0) {
 			SM_ENTER(WPA_PTK, PTKSTART);
 #ifdef CONFIG_DPP
@@ -3473,13 +3625,13 @@
 #endif /* CONFIG_DPP */
 		} else {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"INITPMK - keyAvailable = false");
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		}
 		break;
 	case WPA_PTK_INITPSK:
-		if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
+		if (wpa_auth_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
 				     NULL, NULL, NULL)) {
 			SM_ENTER(WPA_PTK, PTKSTART);
 #ifdef CONFIG_SAE
@@ -3487,7 +3639,7 @@
 			SM_ENTER(WPA_PTK, PTKSTART);
 #endif /* CONFIG_SAE */
 		} else {
-			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"no PSK configured for the STA");
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
 			SM_ENTER(WPA_PTK, DISCONNECT);
@@ -3497,13 +3649,11 @@
 		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
 		    sm->EAPOLKeyPairwise)
 			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
-		else if (sm->TimeoutCtr >
-			 sm->wpa_auth->conf.wpa_pairwise_update_count) {
+		else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			wpa_auth_vlogger(
-				sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"PTKSTART: Retry limit %u reached",
-				sm->wpa_auth->conf.wpa_pairwise_update_count);
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "PTKSTART: Retry limit %u reached",
+					 conf->wpa_pairwise_update_count);
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		} else if (sm->TimeoutEvt)
 			SM_ENTER(WPA_PTK, PTKSTART);
@@ -3527,14 +3677,13 @@
 			 sm->EAPOLKeyPairwise && sm->MICVerified)
 			SM_ENTER(WPA_PTK, PTKINITDONE);
 		else if (sm->TimeoutCtr >
-			 sm->wpa_auth->conf.wpa_pairwise_update_count ||
-			 (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+			 conf->wpa_pairwise_update_count ||
+			 (conf->wpa_disable_eapol_key_retries &&
 			  sm->TimeoutCtr > 1)) {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			wpa_auth_vlogger(
-				sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"PTKINITNEGOTIATING: Retry limit %u reached",
-				sm->wpa_auth->conf.wpa_pairwise_update_count);
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "PTKINITNEGOTIATING: Retry limit %u reached",
+					 conf->wpa_pairwise_update_count);
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		} else if (sm->TimeoutEvt)
 			SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -3565,16 +3714,16 @@
 	u8 *kde_buf = NULL, *pos, hdr[2];
 	size_t kde_len;
 	u8 *gtk, dummy_gtk[32];
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
 
 	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
 
 	sm->GTimeoutCtr++;
-	if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
-	    sm->GTimeoutCtr > 1) {
+	if (conf->wpa_disable_eapol_key_retries && sm->GTimeoutCtr > 1) {
 		/* Do not allow retransmission of EAPOL-Key group msg 1/2 */
 		return;
 	}
-	if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
+	if (sm->GTimeoutCtr > conf->wpa_group_update_count) {
 		/* No point in sending the EAPOL-Key - we will disconnect
 		 * immediately following this. */
 		return;
@@ -3591,8 +3740,7 @@
 			"sending 1/2 msg of Group Key Handshake");
 
 	gtk = gsm->GTK[gsm->GN - 1];
-	if (sm->wpa_auth->conf.disable_gtk ||
-	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+	if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
 		/*
 		 * Provide unique random GTK to each STA to prevent use
 		 * of GTK in the BSS.
@@ -3605,7 +3753,7 @@
 		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
 			ieee80211w_kde_len(sm) + ocv_oci_len(sm);
 		kde_buf = os_malloc(kde_len);
-		if (kde_buf == NULL)
+		if (!kde_buf)
 			return;
 
 		kde = pos = kde_buf;
@@ -3638,8 +3786,8 @@
 
 SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
 {
-#ifdef CONFIG_OCV
 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+#ifdef CONFIG_OCV
 	const u8 *key_data, *mic;
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
@@ -3704,7 +3852,7 @@
 	sm->GUpdateStationKeys = FALSE;
 	sm->GTimeoutCtr = 0;
 	/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
-	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
 			 "group key handshake completed (%s)",
 			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
 	sm->has_GTK = TRUE;
@@ -3761,7 +3909,9 @@
 static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
 			  struct wpa_group *group)
 {
+	struct wpa_auth_config *conf = &wpa_auth->conf;
 	int ret = 0;
+	size_t len;
 
 	os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
 	inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -3772,9 +3922,8 @@
 	wpa_hexdump_key(MSG_DEBUG, "GTK",
 			group->GTK[group->GN - 1], group->GTK_len);
 
-	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-		size_t len;
-		len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		len = wpa_cipher_key_len(conf->group_mgmt_cipher);
 		os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
 		inc_byte_array(group->Counter, WPA_NONCE_LEN);
 		if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
@@ -3785,6 +3934,19 @@
 				group->IGTK[group->GN_igtk - 4], len);
 	}
 
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+	    conf->beacon_prot) {
+		len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+		os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+		inc_byte_array(group->Counter, WPA_NONCE_LEN);
+		if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
+				   wpa_auth->addr, group->GNonce,
+				   group->BIGTK[group->GN_bigtk - 6], len) < 0)
+			ret = -1;
+		wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+				group->BIGTK[group->GN_bigtk - 6], len);
+	}
+
 	return ret;
 }
 
@@ -3792,8 +3954,9 @@
 static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
 			       struct wpa_group *group)
 {
-	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
-		   "GTK_INIT (VLAN-ID %d)", group->vlan_id);
+	wpa_printf(MSG_DEBUG,
+		   "WPA: group state machine entering state GTK_INIT (VLAN-ID %d)",
+		   group->vlan_id);
 	group->changed = FALSE; /* GInit is not cleared here; avoid loop */
 	group->wpa_group_state = WPA_GROUP_GTK_INIT;
 
@@ -3803,6 +3966,8 @@
 	group->GM = 2;
 	group->GN_igtk = 4;
 	group->GM_igtk = 5;
+	group->GN_bigtk = 6;
+	group->GM_bigtk = 7;
 	/* GTK[GN] = CalcGTK() */
 	wpa_gtk_update(wpa_auth, group);
 }
@@ -3826,8 +3991,7 @@
 		 * station needs to be counted here anyway.
 		 */
 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"GUpdateStationKeys was already set when "
-				"marking station for GTK rekeying");
+				"GUpdateStationKeys was already set when marking station for GTK rekeying");
 	}
 
 	/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
@@ -3846,7 +4010,7 @@
 /* update GTK when exiting WNM-Sleep Mode */
 void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
 {
-	if (sm == NULL || sm->is_wnmsleep)
+	if (!sm || sm->is_wnmsleep)
 		return;
 
 	wpa_group_update_sta(sm, NULL);
@@ -3920,6 +4084,36 @@
 	return pos - start;
 }
 
+
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_group *gsm = sm->group;
+	u8 *start = pos;
+	size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+	/*
+	 * BIGTK subelement:
+	 * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+	 */
+	*pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+	*pos++ = 2 + 6 + len;
+	WPA_PUT_LE16(pos, gsm->GN_bigtk);
+	pos += 2;
+	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+		return 0;
+	pos += 6;
+
+	os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+	pos += len;
+
+	wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
+		   gsm->GN_bigtk);
+	wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
+			gsm->IGTK[gsm->GN_bigtk - 6], len);
+
+	return pos - start;
+}
+
 #endif /* CONFIG_WNM_AP */
 
 
@@ -3928,8 +4122,9 @@
 {
 	int tmp;
 
-	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
-		   "SETKEYS (VLAN-ID %d)", group->vlan_id);
+	wpa_printf(MSG_DEBUG,
+		   "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+		   group->vlan_id);
 	group->changed = TRUE;
 	group->wpa_group_state = WPA_GROUP_SETKEYS;
 	group->GTKReKey = FALSE;
@@ -3939,14 +4134,17 @@
 	tmp = group->GM_igtk;
 	group->GM_igtk = group->GN_igtk;
 	group->GN_igtk = tmp;
+	tmp = group->GM_bigtk;
+	group->GM_bigtk = group->GN_bigtk;
+	group->GN_bigtk = tmp;
 	/* "GKeyDoneStations = GNoStations" is done in more robust way by
 	 * counting the STAs that are marked with GUpdateStationKeys instead of
 	 * including all STAs that could be in not-yet-completed state. */
 	wpa_gtk_update(wpa_auth, group);
 
 	if (group->GKeyDoneStations) {
-		wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
-			   "GKeyDoneStations=%d when starting new GTK rekey",
+		wpa_printf(MSG_DEBUG,
+			   "wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey",
 			   group->GKeyDoneStations);
 		group->GKeyDoneStations = 0;
 	}
@@ -3959,25 +4157,35 @@
 static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
 				       struct wpa_group *group)
 {
+	struct wpa_auth_config *conf = &wpa_auth->conf;
 	int ret = 0;
 
 	if (wpa_auth_set_key(wpa_auth, group->vlan_id,
-			     wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
+			     wpa_cipher_to_alg(conf->wpa_group),
 			     broadcast_ether_addr, group->GN,
-			     group->GTK[group->GN - 1], group->GTK_len) < 0)
+			     group->GTK[group->GN - 1], group->GTK_len,
+			     KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 		ret = -1;
 
-	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
 		enum wpa_alg alg;
 		size_t len;
 
-		alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
-		len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+		alg = wpa_cipher_to_alg(conf->group_mgmt_cipher);
+		len = wpa_cipher_key_len(conf->group_mgmt_cipher);
 
 		if (ret == 0 &&
 		    wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
 				     broadcast_ether_addr, group->GN_igtk,
-				     group->IGTK[group->GN_igtk - 4], len) < 0)
+				     group->IGTK[group->GN_igtk - 4], len,
+				     KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+			ret = -1;
+
+		if (ret == 0 && conf->beacon_prot &&
+		    wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+				     broadcast_ether_addr, group->GN_bigtk,
+				     group->BIGTK[group->GN_bigtk - 6], len,
+				     KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 			ret = -1;
 	}
 
@@ -3989,7 +4197,7 @@
 {
 	if (sm->group == ctx) {
 		wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
-			   " for discconnection due to fatal failure",
+			   " for disconnection due to fatal failure",
 			   MAC2STR(sm->addr));
 		sm->Disconnect = TRUE;
 	}
@@ -4001,7 +4209,8 @@
 static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
 				    struct wpa_group *group)
 {
-	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
+	wpa_printf(MSG_DEBUG,
+		   "WPA: group state machine entering state FATAL_FAILURE");
 	group->changed = TRUE;
 	group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
 	wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
@@ -4011,8 +4220,9 @@
 static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
 				 struct wpa_group *group)
 {
-	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
-		   "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
+	wpa_printf(MSG_DEBUG,
+		   "WPA: group state machine entering state SETKEYSDONE (VLAN-ID %d)",
+		   group->vlan_id);
 	group->changed = TRUE;
 	group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
 
@@ -4049,7 +4259,7 @@
 
 static int wpa_sm_step(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	if (!sm)
 		return 0;
 
 	if (sm->in_step_loop) {
@@ -4079,8 +4289,9 @@
 	sm->in_step_loop = 0;
 
 	if (sm->pending_deinit) {
-		wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
-			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Completing pending STA state machine deinit for "
+			   MACSTR, MAC2STR(sm->addr));
 		wpa_free_sta_sm(sm);
 		return 1;
 	}
@@ -4097,7 +4308,7 @@
 
 void wpa_auth_sm_notify(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	if (!sm)
 		return;
 	eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
 }
@@ -4108,7 +4319,7 @@
 	int tmp, i;
 	struct wpa_group *group;
 
-	if (wpa_auth == NULL)
+	if (!wpa_auth)
 		return;
 
 	group = wpa_auth->group;
@@ -4120,6 +4331,9 @@
 		tmp = group->GM_igtk;
 		group->GM_igtk = group->GN_igtk;
 		group->GN_igtk = tmp;
+		tmp = group->GM_bigtk;
+		group->GM_bigtk = group->GN_bigtk;
+		group->GN_bigtk = tmp;
 		wpa_gtk_update(wpa_auth, group);
 		wpa_group_config_group_keys(wpa_auth, group);
 	}
@@ -4138,6 +4352,7 @@
 
 int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
 {
+	struct wpa_auth_config *conf;
 	int len = 0, ret;
 	char pmkid_txt[PMKID_LEN * 2 + 1];
 #ifdef CONFIG_RSN_PREAUTH
@@ -4146,8 +4361,9 @@
 	const int preauth = 0;
 #endif /* CONFIG_RSN_PREAUTH */
 
-	if (wpa_auth == NULL)
+	if (!wpa_auth)
 		return len;
+	conf = &wpa_auth->conf;
 
 	ret = os_snprintf(buf + len, buflen - len,
 			  "dot11RSNAOptionImplemented=TRUE\n"
@@ -4155,8 +4371,8 @@
 			  "dot11RSNAEnabled=%s\n"
 			  "dot11RSNAPreauthenticationEnabled=%s\n",
 			  wpa_bool_txt(preauth),
-			  wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
-			  wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+			  wpa_bool_txt(conf->wpa & WPA_PROTO_RSN),
+			  wpa_bool_txt(conf->rsn_preauth));
 	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
@@ -4191,10 +4407,10 @@
 		"dot11RSNA4WayHandshakeFailures=%u\n"
 		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
 		RSN_VERSION,
-		!!wpa_auth->conf.wpa_strict_rekey,
-		wpa_auth->conf.wpa_group_update_count,
-		wpa_auth->conf.wpa_pairwise_update_count,
-		wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
+		!!conf->wpa_strict_rekey,
+		conf->wpa_group_update_count,
+		conf->wpa_pairwise_update_count,
+		wpa_cipher_key_len(conf->wpa_group) * 8,
 		dot11RSNAConfigPMKLifetime,
 		dot11RSNAConfigPMKReauthThreshold,
 		dot11RSNAConfigSATimeout,
@@ -4230,7 +4446,7 @@
 	int len = 0, ret;
 	u32 pairwise = 0;
 
-	if (sm == NULL)
+	if (!sm)
 		return 0;
 
 	/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
@@ -4311,7 +4527,7 @@
 
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	if (!sm)
 		return -1;
 	return sm->wpa_key_mgmt;
 }
@@ -4319,7 +4535,7 @@
 
 int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	if (!sm)
 		return 0;
 	return sm->wpa;
 }
@@ -4344,7 +4560,7 @@
 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
 			     struct rsn_pmksa_cache_entry *entry)
 {
-	if (sm == NULL || sm->pmksa != entry)
+	if (!sm || sm->pmksa != entry)
 		return -1;
 	sm->pmksa = NULL;
 	return 0;
@@ -4367,7 +4583,7 @@
 
 const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
 {
-	if (wpa_auth == NULL)
+	if (!wpa_auth)
 		return NULL;
 	*len = wpa_auth->wpa_ie_len;
 	return wpa_auth->wpa_ie;
@@ -4378,7 +4594,7 @@
 		       unsigned int pmk_len,
 		       int session_timeout, struct eapol_state_machine *eapol)
 {
-	if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
+	if (!sm || sm->wpa != WPA_VERSION_WPA2 ||
 	    sm->wpa_auth->conf.disable_pmksa_caching)
 		return -1;
 
@@ -4414,7 +4630,7 @@
 			       int session_timeout,
 			       struct eapol_state_machine *eapol)
 {
-	if (wpa_auth == NULL)
+	if (!wpa_auth)
 		return -1;
 
 	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
@@ -4475,7 +4691,7 @@
 {
 	struct rsn_pmksa_cache_entry *pmksa;
 
-	if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+	if (!wpa_auth || !wpa_auth->pmksa)
 		return;
 	pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
 	if (pmksa) {
@@ -4641,13 +4857,13 @@
 {
 	struct wpa_group *group;
 
-	if (wpa_auth == NULL || wpa_auth->group == NULL)
+	if (!wpa_auth || !wpa_auth->group)
 		return NULL;
 
 	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
 		   vlan_id);
 	group = wpa_group_init(wpa_auth, vlan_id, 0);
-	if (group == NULL)
+	if (!group)
 		return NULL;
 
 	group->next = wpa_auth->group->next;
@@ -4667,7 +4883,7 @@
 {
 	struct wpa_group *group;
 
-	if (wpa_auth == NULL)
+	if (!wpa_auth)
 		return 0;
 
 	group = wpa_auth->group;
@@ -4677,9 +4893,9 @@
 		group = group->next;
 	}
 
-	if (group == NULL) {
+	if (!group) {
 		group = wpa_auth_add_group(wpa_auth, vlan_id);
-		if (group == NULL)
+		if (!group)
 			return -1;
 	}
 
@@ -4708,7 +4924,7 @@
 	struct wpa_group *group;
 	int ret = 0;
 
-	if (wpa_auth == NULL)
+	if (!wpa_auth)
 		return 0;
 
 	group = wpa_auth->group;
@@ -4718,7 +4934,7 @@
 		group = group->next;
 	}
 
-	if (group == NULL)
+	if (!group)
 		return -1;
 
 	wpa_printf(MSG_DEBUG,
@@ -4753,7 +4969,7 @@
 {
 	struct wpa_group *group;
 
-	if (sm == NULL || sm->wpa_auth == NULL)
+	if (!sm || !sm->wpa_auth)
 		return 0;
 
 	group = sm->wpa_auth->group;
@@ -4763,9 +4979,9 @@
 		group = group->next;
 	}
 
-	if (group == NULL) {
+	if (!group) {
 		group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
-		if (group == NULL)
+		if (!group)
 			return -1;
 	}
 
@@ -4775,8 +4991,9 @@
 	if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
-		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR
+		   " to use group state machine for VLAN ID %d",
+		   MAC2STR(sm->addr), vlan_id);
 
 	wpa_group_get(sm->wpa_auth, group);
 	wpa_group_put(sm->wpa_auth, sm->group);
@@ -4789,7 +5006,7 @@
 void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
 				  struct wpa_state_machine *sm, int ack)
 {
-	if (wpa_auth == NULL || sm == NULL)
+	if (!wpa_auth || !sm)
 		return;
 	wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
 		   " ack=%d", MAC2STR(sm->addr), ack);
@@ -4805,8 +5022,8 @@
 		 * the station has received the frame.
 		 */
 		int timeout_ms = eapol_key_timeout_subseq;
-		wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
-			   "timeout by %u ms because of acknowledged frame",
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Increase initial EAPOL-Key 1/4 timeout by %u ms because of acknowledged frame",
 			   timeout_ms);
 		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
 		eloop_register_timeout(timeout_ms / 1000,
@@ -4826,7 +5043,7 @@
 
 int wpa_auth_uses_sae(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	if (!sm)
 		return 0;
 	return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
 }
@@ -4834,7 +5051,7 @@
 
 int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
 {
-	if (sm == NULL)
+	if (!sm)
 		return 0;
 	return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
 }
@@ -4843,7 +5060,7 @@
 #ifdef CONFIG_P2P
 int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
 {
-	if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+	if (!sm || WPA_GET_BE32(sm->ip_addr) == 0)
 		return -1;
 	os_memcpy(addr, sm->ip_addr, 4);
 	return 0;
@@ -4919,7 +5136,7 @@
 
 	return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
 			      conf->r0_key_holder_len,
-			      NULL, NULL, buf, len, NULL, 0);
+			      NULL, NULL, buf, len, NULL, 0, 0);
 }
 #endif /* CONFIG_IEEE80211R_AP */
 
@@ -4999,9 +5216,10 @@
 	struct wpa_group *gsm = sm->group;
 	u8 *wpa_ie;
 	int wpa_ie_len, secure, gtkidx, encr = 0;
+	u8 hdr[2];
 
 	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
-	   GTK[GN], IGTK, [FTIE], [TIE * 2])
+	   GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
 	 */
 
 	/* Use 0 RSC */
@@ -5044,13 +5262,16 @@
 			 * WPA if the supplicant used it first.
 			 */
 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-					"STA used Secure bit in WPA msg 2/4 - "
-					"set Secure for 3/4 as workaround");
+					"STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
 			secure = 1;
 		}
 	}
 
 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+	if (sm->use_ext_key_id)
+		kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
 	if (gtk)
 		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
 #ifdef CONFIG_IEEE80211R_AP
@@ -5060,7 +5281,7 @@
 	}
 #endif /* CONFIG_IEEE80211R_AP */
 	kde = os_malloc(kde_len);
-	if (kde == NULL)
+	if (!kde)
 		return -1;
 
 	pos = kde;
@@ -5074,8 +5295,8 @@
 		elen = pos - kde;
 		res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
 		if (res < 0) {
-			wpa_printf(MSG_ERROR, "FT: Failed to insert "
-				   "PMKR1Name into RSN IE in EAPOL-Key data");
+			wpa_printf(MSG_ERROR,
+				   "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
 			os_free(kde);
 			return -1;
 		}
@@ -5083,10 +5304,15 @@
 		pos += elen;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
+	hdr[1] = 0;
+
+	if (sm->use_ext_key_id) {
+		hdr[0] = sm->keyidx_active & 0x01;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+	}
+
 	if (gtk) {
-		u8 hdr[2];
 		hdr[0] = gtkidx & 0x03;
-		hdr[1] = 0;
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gtk_len);
 	}
@@ -5121,11 +5347,11 @@
 					     conf->r0_key_holder_len,
 					     NULL, NULL, pos,
 					     kde + kde_len - pos,
-					     NULL, 0);
+					     NULL, 0, 0);
 		}
 		if (res < 0) {
-			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
-				   "into EAPOL-Key Key Data");
+			wpa_printf(MSG_ERROR,
+				   "FT: Failed to insert FTIE into EAPOL-Key Key Data");
 			os_free(kde);
 			return -1;
 		}
@@ -5182,7 +5408,7 @@
 		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
 			ieee80211w_kde_len(sm) + ocv_oci_len(sm);
 		kde_buf = os_malloc(kde_len);
-		if (kde_buf == NULL)
+		if (!kde_buf)
 			return -1;
 
 		kde = pos = kde_buf;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 933a4b8..868aaa1 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -169,6 +169,7 @@
 
 struct wpa_auth_config {
 	int wpa;
+	int extended_key_id;
 	int wpa_key_mgmt;
 	int wpa_pairwise;
 	int wpa_group;
@@ -176,6 +177,7 @@
 	int wpa_strict_rekey;
 	int wpa_gmk_rekey;
 	int wpa_ptk_rekey;
+	int wpa_deny_ptk0_rekey;
 	u32 wpa_group_update_count;
 	u32 wpa_pairwise_update_count;
 	int wpa_disable_eapol_key_retries;
@@ -188,6 +190,7 @@
 	int okc;
 	int tx_status;
 	enum mfp_options ieee80211w;
+	int beacon_prot;
 	int group_mgmt_cipher;
 	int sae_require_mfp;
 #ifdef CONFIG_OCV
@@ -219,8 +222,22 @@
 	double corrupt_gtk_rekey_mic_probability;
 	u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
 	size_t own_ie_override_len;
+	u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
+	size_t rsne_override_eapol_len;
 	u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
 	size_t rsnxe_override_eapol_len;
+	u8 rsne_override_ft[MAX_OWN_IE_OVERRIDE];
+	size_t rsne_override_ft_len;
+	u8 rsnxe_override_ft[MAX_OWN_IE_OVERRIDE];
+	size_t rsnxe_override_ft_len;
+	u8 gtk_rsc_override[WPA_KEY_RSC_LEN];
+	u8 igtk_rsc_override[WPA_KEY_RSC_LEN];
+	unsigned int rsne_override_eapol_set:1;
+	unsigned int rsnxe_override_eapol_set:1;
+	unsigned int rsne_override_ft_set:1;
+	unsigned int rsnxe_override_ft_set:1;
+	unsigned int gtk_rsc_override_set:1;
+	unsigned int igtk_rsc_override_set:1;
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_P2P
 	u8 ip_addr_go[4];
@@ -233,6 +250,11 @@
 	u8 fils_cache_id[FILS_CACHE_ID_LEN];
 #endif /* CONFIG_FILS */
 	int sae_pwe;
+	int owe_ptk_workaround;
+	u8 transition_disable;
+#ifdef CONFIG_DPP2
+	int dpp_pfs;
+#endif /* CONFIG_DPP2 */
 };
 
 typedef enum {
@@ -259,7 +281,8 @@
 			      int *vlan_id);
 	int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
 	int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
-		       const u8 *addr, int idx, u8 *key, size_t key_len);
+		       const u8 *addr, int idx, u8 *key, size_t key_len,
+		       enum key_flag key_flag);
 	int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
 	int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
 			  size_t data_len, int encrypt);
@@ -311,19 +334,21 @@
 int wpa_reconfig(struct wpa_authenticator *wpa_auth,
 		 struct wpa_auth_config *conf);
 
-enum {
+enum wpa_validate_result {
 	WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
 	WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
 	WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
-	WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
+	WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID,
+	WPA_DENIED_OTHER_REASON
 };
 
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
-			struct wpa_state_machine *sm, int freq,
-			const u8 *wpa_ie, size_t wpa_ie_len,
-			const u8 *rsnxe, size_t rsnxe_len,
-			const u8 *mdie, size_t mdie_len,
-			const u8 *owe_dh, size_t owe_dh_len);
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+		    struct wpa_state_machine *sm, int freq,
+		    const u8 *wpa_ie, size_t wpa_ie_len,
+		    const u8 *rsnxe, size_t rsnxe_len,
+		    const u8 *mdie, size_t mdie_len,
+		    const u8 *owe_dh, size_t owe_dh_len);
 int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
 		      struct wpa_state_machine *sm,
 		      const u8 *osen_ie, size_t osen_ie_len);
@@ -407,7 +432,8 @@
 #ifdef CONFIG_IEEE80211R_AP
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 				 size_t max_len, int auth_alg,
-				 const u8 *req_ies, size_t req_ies_len);
+				 const u8 *req_ies, size_t req_ies_len,
+				 int omit_rsnxe);
 void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
 			 u16 auth_transaction, const u8 *ies, size_t ies_len,
 			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
@@ -431,6 +457,7 @@
 void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
 int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
 int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
 
 int wpa_auth_uses_sae(struct wpa_state_machine *sm);
 int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index a599be2..476a2be 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -808,7 +808,7 @@
 		   const u8 *r0kh_id, size_t r0kh_id_len,
 		   const u8 *anonce, const u8 *snonce,
 		   u8 *buf, size_t len, const u8 *subelem,
-		   size_t subelem_len)
+		   size_t subelem_len, int rsnxe_used)
 {
 	u8 *pos = buf, *ielen;
 	size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
@@ -826,7 +826,7 @@
 
 		os_memset(hdr, 0, sizeof(*hdr));
 		pos += sizeof(*hdr);
-		WPA_PUT_LE16(hdr->mic_control, 0);
+		WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
 		if (anonce)
 			os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
 		if (snonce)
@@ -836,7 +836,7 @@
 
 		os_memset(hdr, 0, sizeof(*hdr));
 		pos += sizeof(*hdr);
-		WPA_PUT_LE16(hdr->mic_control, 0);
+		WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
 		if (anonce)
 			os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
 		if (snonce)
@@ -951,8 +951,9 @@
 		goto err;
 	}
 
-	wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
-		   MAC2STR(src_addr));
+	wpa_printf(MSG_DEBUG, "FT: Send sequence number request from " MACSTR
+		   " to " MACSTR,
+		   MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
 	item = os_zalloc(sizeof(*item));
 	if (!item)
 		goto err;
@@ -1997,9 +1998,6 @@
 	key = r0kh->key;
 	key_len = sizeof(r0kh->key);
 
-	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
-		   "address " MACSTR, MAC2STR(r0kh->addr));
-
 	if (r0kh->seq->rx.num_last == 0) {
 		/* A sequence request will be sent out anyway when pull
 		 * response is received. Send it out now to avoid one RTT. */
@@ -2008,6 +2006,10 @@
 				   key_len, NULL, 0, NULL, 0, NULL);
 	}
 
+	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request from " MACSTR
+		   " to remote R0KH address " MACSTR,
+		   MAC2STR(sm->wpa_auth->addr), MAC2STR(r0kh->addr));
+
 	if (first &&
 	    random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -2280,6 +2282,54 @@
 }
 
 
+static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+	u8 *subelem, *pos;
+	struct wpa_group *gsm = sm->group;
+	size_t subelem_len;
+	const u8 *kek;
+	size_t kek_len;
+	size_t bigtk_len;
+
+	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+		kek = sm->PTK.kek2;
+		kek_len = sm->PTK.kek2_len;
+	} else {
+		kek = sm->PTK.kek;
+		kek_len = sm->PTK.kek_len;
+	}
+
+	bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+	/* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
+	 * Key[16+8] */
+	subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	pos = subelem;
+	*pos++ = FTIE_SUBELEM_BIGTK;
+	*pos++ = subelem_len - 2;
+	WPA_PUT_LE16(pos, gsm->GN_bigtk);
+	pos += 2;
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
+	pos += 6;
+	*pos++ = bigtk_len;
+	if (aes_wrap(kek, kek_len, bigtk_len / 8,
+		     gsm->IGTK[gsm->GN_bigtk - 6], pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: BIGTK subelem encryption failed: kek_len=%d",
+			   (int) kek_len);
+		os_free(subelem);
+		return NULL;
+	}
+
+	*len = subelem_len;
+	return subelem;
+}
+
+
 static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
 				u8 *pos, u8 *end, u8 id, u8 descr_count,
 				const u8 *ies, size_t ies_len)
@@ -2413,13 +2463,15 @@
 
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 				 size_t max_len, int auth_alg,
-				 const u8 *req_ies, size_t req_ies_len)
+				 const u8 *req_ies, size_t req_ies_len,
+				 int omit_rsnxe)
 {
 	u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
 	u8 *fte_mic, *elem_count;
 	size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
-	u8 rsnxe[10];
+	u8 rsnxe_buf[10], *rsnxe = rsnxe_buf;
 	size_t rsnxe_len;
+	int rsnxe_used;
 	int res;
 	struct wpa_auth_config *conf;
 	struct wpa_ft_ies parse;
@@ -2440,6 +2492,32 @@
 
 	end = pos + max_len;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (auth_alg == WLAN_AUTH_FT &&
+	    sm->wpa_auth->conf.rsne_override_ft_set) {
+		wpa_printf(MSG_DEBUG,
+			   "TESTING: RSNE FT override for MIC calculation");
+		rsnie = sm->wpa_auth->conf.rsne_override_ft;
+		rsnie_len = sm->wpa_auth->conf.rsne_override_ft_len;
+		if (end - pos < (long int) rsnie_len)
+			return pos;
+		os_memcpy(pos, rsnie, rsnie_len);
+		rsnie = pos;
+		pos += rsnie_len;
+		if (rsnie_len > PMKID_LEN && sm->pmk_r1_name_valid) {
+			int idx;
+
+			/* Replace all 0xff PMKID with the valid PMKR1Name */
+			for (idx = 0; idx < PMKID_LEN; idx++) {
+				if (rsnie[rsnie_len - 1 - idx] != 0xff)
+					break;
+			}
+			if (idx == PMKID_LEN)
+				os_memcpy(&rsnie[rsnie_len - PMKID_LEN],
+					  sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+		}
+	} else
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (auth_alg == WLAN_AUTH_FT ||
 	    ((auth_alg == WLAN_AUTH_FILS_SK ||
 	      auth_alg == WLAN_AUTH_FILS_SK_PFS ||
@@ -2509,6 +2587,29 @@
 			subelem_len += igtk_len;
 			os_free(igtk);
 		}
+		if (sm->mgmt_frame_prot && conf->beacon_prot) {
+			u8 *bigtk;
+			size_t bigtk_len;
+			u8 *nbuf;
+
+			bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
+			if (!bigtk) {
+				wpa_printf(MSG_DEBUG,
+					   "FT: Failed to add BIGTK subelement");
+				os_free(subelem);
+				return NULL;
+			}
+			nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+			if (!nbuf) {
+				os_free(subelem);
+				os_free(bigtk);
+				return NULL;
+			}
+			subelem = nbuf;
+			os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+			subelem_len += bigtk_len;
+			os_free(bigtk);
+		}
 #ifdef CONFIG_OCV
 		if (wpa_auth_uses_ocv(sm)) {
 			struct wpa_channel_info ci;
@@ -2544,9 +2645,11 @@
 		anonce = NULL;
 		snonce = NULL;
 	}
+	rsnxe_used = (auth_alg == WLAN_AUTH_FT) &&
+		(conf->sae_pwe == 1 || conf->sae_pwe == 2);
 	res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
 			     anonce, snonce, pos, end - pos,
-			     subelem, subelem_len);
+			     subelem, subelem_len, rsnxe_used);
 	os_free(subelem);
 	if (res < 0)
 		return NULL;
@@ -2582,10 +2685,24 @@
 	if (ric_start == pos)
 		ric_start = NULL;
 
-	res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe));
-	if (res < 0)
-		return NULL;
-	rsnxe_len = res;
+	if (omit_rsnxe) {
+		rsnxe_len = 0;
+	} else {
+		res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe,
+				      sizeof(rsnxe_buf));
+		if (res < 0)
+			return NULL;
+		rsnxe_len = res;
+	}
+#ifdef CONFIG_TESTING_OPTIONS
+	if (auth_alg == WLAN_AUTH_FT &&
+	    sm->wpa_auth->conf.rsnxe_override_ft_set) {
+		wpa_printf(MSG_DEBUG,
+			   "TESTING: RSNXE FT override for MIC calculation");
+		rsnxe = sm->wpa_auth->conf.rsnxe_override_ft;
+		rsnxe_len = sm->wpa_auth->conf.rsnxe_override_ft_len;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
 		*elem_count += 1;
 
@@ -2620,12 +2737,13 @@
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
+				   u8 *key, size_t key_len,
+				   enum key_flag key_flag)
 {
 	if (wpa_auth->cb->set_key == NULL)
 		return -1;
 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-				     key, key_len);
+				     key, key_len, key_flag);
 }
 
 
@@ -2657,8 +2775,8 @@
 	 * again after association to get the PTK configured, but that could be
 	 * optimized by adding the STA entry earlier.
 	 */
-	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk, klen))
+	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
+			     sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
 		return;
 
 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -3057,7 +3175,8 @@
 	pos += ret;
 
 	ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
-			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0,
+			     0);
 	if (ret < 0)
 		goto fail;
 	pos += ret;
@@ -3129,10 +3248,13 @@
 	int use_sha384;
 	const u8 *anonce, *snonce, *fte_mic;
 	u8 fte_elem_count;
+	int rsnxe_used;
+	struct wpa_auth_config *conf;
 
 	if (sm == NULL)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
+	conf = &sm->wpa_auth->conf;
 	use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
 
 	wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
@@ -3161,8 +3283,7 @@
 
 	mdie = (struct rsn_mdie *) parse.mdie;
 	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
-	    os_memcmp(mdie->mobility_domain,
-		      sm->wpa_auth->conf.mobility_domain,
+	    os_memcmp(mdie->mobility_domain, conf->mobility_domain,
 		      MOBILITY_DOMAIN_ID_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
 		return WLAN_STATUS_INVALID_MDIE;
@@ -3179,6 +3300,7 @@
 
 		anonce = ftie->anonce;
 		snonce = ftie->snonce;
+		rsnxe_used = ftie->mic_control[0] & 0x01;
 		fte_elem_count = ftie->mic_control[1];
 		fte_mic = ftie->mic;
 	} else {
@@ -3192,6 +3314,7 @@
 
 		anonce = ftie->anonce;
 		snonce = ftie->snonce;
+		rsnxe_used = ftie->mic_control[0] & 0x01;
 		fte_elem_count = ftie->mic_control[1];
 		fte_mic = ftie->mic;
 	}
@@ -3237,14 +3360,14 @@
 		return WLAN_STATUS_INVALID_FTIE;
 	}
 
-	if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+	if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder,
 			    FT_R1KH_ID_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
 			   "ReassocReq");
 		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
 			    parse.r1kh_id, FT_R1KH_ID_LEN);
 		wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
-			    sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+			    conf->r1_key_holder, FT_R1KH_ID_LEN);
 		return WLAN_STATUS_INVALID_FTIE;
 	}
 
@@ -3306,6 +3429,13 @@
 		return WLAN_STATUS_INVALID_FTIE;
 	}
 
+	if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) &&
+	    !parse.rsnxe) {
+		wpa_printf(MSG_INFO,
+			   "FT: FTE indicated that STA uses RSNXE, but RSNXE was not included");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
 #ifdef CONFIG_OCV
 	if (wpa_auth_uses_ocv(sm)) {
 		struct wpa_channel_info ci;
@@ -3687,6 +3817,10 @@
 		goto out;
 	}
 
+	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull response from " MACSTR
+		   " to " MACSTR,
+		   MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
 	resp[0].type = FT_RRB_S1KH_ID;
 	resp[0].len = f_s1kh_id_len;
 	resp[0].data = f_s1kh_id;
@@ -4193,6 +4327,10 @@
 		goto out;
 	}
 
+	wpa_printf(MSG_DEBUG, "FT: Send sequence number response from " MACSTR
+		   " to " MACSTR,
+		   MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
 	seq_resp_auth[0].type = FT_RRB_NONCE;
 	seq_resp_auth[0].len = f_nonce_len;
 	seq_resp_auth[0].data = f_nonce;
@@ -4452,9 +4590,11 @@
 	size_t alen, elen;
 	int no_defer = 0;
 
-	wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
-		   MACSTR, MAC2STR(src_addr));
-	wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+	wpa_printf(MSG_DEBUG, "FT: RRB-OUI(" MACSTR
+		   ") received frame from remote AP "
+		   MACSTR " oui_suffix=%u dst=" MACSTR,
+		   MAC2STR(wpa_auth->addr), MAC2STR(src_addr), oui_suffix,
+		   MAC2STR(dst_addr));
 	wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
 
 	if (is_multicast_ether_addr(src_addr)) {
@@ -4464,13 +4604,8 @@
 		return;
 	}
 
-	if (is_multicast_ether_addr(dst_addr)) {
-		wpa_printf(MSG_DEBUG,
-			   "FT: RRB-OUI received frame from remote AP " MACSTR
-			   " to multicast address " MACSTR,
-			   MAC2STR(src_addr), MAC2STR(dst_addr));
+	if (is_multicast_ether_addr(dst_addr))
 		no_defer = 1;
-	}
 
 	if (data_len < sizeof(u16)) {
 		wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
@@ -4545,6 +4680,10 @@
 		return -1;
 	}
 
+	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 push from " MACSTR
+		   " to remote R0KH address " MACSTR,
+		   MAC2STR(wpa_auth->addr), MAC2STR(r1kh->addr));
+
 	if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
 				r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
 				FT_PACKET_R0KH_R1KH_PUSH,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 7fb0923..7a1ed24 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -37,8 +37,11 @@
 				  struct hostapd_config *iconf,
 				  struct wpa_auth_config *wconf)
 {
+	int sae_pw_id;
+
 	os_memset(wconf, 0, sizeof(*wconf));
 	wconf->wpa = conf->wpa;
+	wconf->extended_key_id = conf->extended_key_id;
 	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
 	wconf->wpa_pairwise = conf->wpa_pairwise;
 	wconf->wpa_group = conf->wpa_group;
@@ -65,6 +68,7 @@
 #endif /* CONFIG_OCV */
 	wconf->okc = conf->okc;
 	wconf->ieee80211w = conf->ieee80211w;
+	wconf->beacon_prot = conf->beacon_prot;
 	wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
 	wconf->sae_require_mfp = conf->sae_require_mfp;
 #ifdef CONFIG_IEEE80211R_AP
@@ -118,14 +122,58 @@
 			  wpabuf_head(conf->own_ie_override),
 			  wconf->own_ie_override_len);
 	}
+	if (conf->rsne_override_eapol &&
+	    wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+		wconf->rsne_override_eapol_set = 1;
+		wconf->rsne_override_eapol_len =
+			wpabuf_len(conf->rsne_override_eapol);
+		os_memcpy(wconf->rsne_override_eapol,
+			  wpabuf_head(conf->rsne_override_eapol),
+			  wconf->rsne_override_eapol_len);
+	}
 	if (conf->rsnxe_override_eapol &&
 	    wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+		wconf->rsnxe_override_eapol_set = 1;
 		wconf->rsnxe_override_eapol_len =
 			wpabuf_len(conf->rsnxe_override_eapol);
 		os_memcpy(wconf->rsnxe_override_eapol,
 			  wpabuf_head(conf->rsnxe_override_eapol),
 			  wconf->rsnxe_override_eapol_len);
 	}
+	if (conf->rsne_override_ft &&
+	    wpabuf_len(conf->rsne_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+		wconf->rsne_override_ft_set = 1;
+		wconf->rsne_override_ft_len =
+			wpabuf_len(conf->rsne_override_ft);
+		os_memcpy(wconf->rsne_override_ft,
+			  wpabuf_head(conf->rsne_override_ft),
+			  wconf->rsne_override_ft_len);
+	}
+	if (conf->rsnxe_override_ft &&
+	    wpabuf_len(conf->rsnxe_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+		wconf->rsnxe_override_ft_set = 1;
+		wconf->rsnxe_override_ft_len =
+			wpabuf_len(conf->rsnxe_override_ft);
+		os_memcpy(wconf->rsnxe_override_ft,
+			  wpabuf_head(conf->rsnxe_override_ft),
+			  wconf->rsnxe_override_ft_len);
+	}
+	if (conf->gtk_rsc_override &&
+	    wpabuf_len(conf->gtk_rsc_override) > 0 &&
+	    wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+		os_memcpy(wconf->gtk_rsc_override,
+			  wpabuf_head(conf->gtk_rsc_override),
+			  wpabuf_len(conf->gtk_rsc_override));
+		wconf->gtk_rsc_override_set = 1;
+	}
+	if (conf->igtk_rsc_override &&
+	    wpabuf_len(conf->igtk_rsc_override) > 0 &&
+	    wpabuf_len(conf->igtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+		os_memcpy(wconf->igtk_rsc_override,
+			  wpabuf_head(conf->igtk_rsc_override),
+			  wpabuf_len(conf->igtk_rsc_override));
+		wconf->igtk_rsc_override_set = 1;
+	}
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_P2P
 	os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -139,6 +187,18 @@
 		  FILS_CACHE_ID_LEN);
 #endif /* CONFIG_FILS */
 	wconf->sae_pwe = conf->sae_pwe;
+	sae_pw_id = hostapd_sae_pw_id_in_use(conf);
+	if (sae_pw_id == 2 && wconf->sae_pwe != 3)
+		wconf->sae_pwe = 1;
+	else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
+		wconf->sae_pwe = 2;
+#ifdef CONFIG_OWE
+	wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
+#endif /* CONFIG_OWE */
+	wconf->transition_disable = conf->transition_disable;
+#ifdef CONFIG_DPP2
+	wconf->dpp_pfs = conf->dpp_pfs;
+#endif /* CONFIG_DPP2 */
 }
 
 
@@ -362,19 +422,27 @@
 
 static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 				    const u8 *addr, int idx, u8 *key,
-				    size_t key_len)
+				    size_t key_len, enum key_flag key_flag)
 {
 	struct hostapd_data *hapd = ctx;
 	const char *ifname = hapd->conf->iface;
 
 	if (vlan_id > 0) {
 		ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
-		if (ifname == NULL)
-			return -1;
+		if (!ifname) {
+			if (!(hapd->iface->drv_flags &
+			      WPA_DRIVER_FLAGS_VLAN_OFFLOAD))
+				return -1;
+			ifname = hapd->conf->iface;
+		}
 	}
 
 #ifdef CONFIG_TESTING_OPTIONS
-	if (addr && !is_broadcast_ether_addr(addr)) {
+	if (key_flag & KEY_FLAG_MODIFY) {
+		/* We are updating an already installed key. Don't overwrite
+		 * the already stored key information with zeros.
+		 */
+	} else if (addr && !is_broadcast_ether_addr(addr)) {
 		struct sta_info *sta;
 
 		sta = ap_get_sta(hapd, addr);
@@ -402,8 +470,8 @@
 		hapd->last_gtk_len = key_len;
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
-	return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
-				   key, key_len);
+	return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id, 1,
+				   NULL, 0, key, key_len, key_flag);
 }
 
 
@@ -623,10 +691,6 @@
 	}
 #endif /* CONFIG_IEEE80211R_AP */
 
-	if (hapd->driver && hapd->driver->send_ether)
-		return hapd->driver->send_ether(hapd->drv_priv, dst,
-						hapd->own_addr, proto,
-						data, data_len);
 	if (hapd->l2 == NULL)
 		return -1;
 
@@ -688,6 +752,12 @@
 	dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
 			      struct oui_deliver_later_data, list) {
 		oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
+		wpa_printf(MSG_DEBUG, "RRB(%s): %s src=" MACSTR " dst=" MACSTR
+			   " oui_suffix=%u data_len=%u data=%p",
+			   hapd->conf->iface, __func__,
+			   MAC2STR(data->src_addr), MAC2STR(data->dst_addr),
+			   data->oui_suffix, (unsigned int) data->data_len,
+			   data);
 		if (hapd->wpa_auth && oui_ctx) {
 			eth_p_oui_deliver(oui_ctx, data->src_addr,
 					  data->dst_addr,
@@ -712,16 +782,26 @@
 {
 	struct wpa_auth_oui_iface_iter_data *idata = ctx;
 	struct oui_deliver_later_data *data;
-	struct hostapd_data *hapd;
+	struct hostapd_data *hapd, *src_hapd = idata->src_hapd;
 	size_t j;
 
 	for (j = 0; j < iface->num_bss; j++) {
 		hapd = iface->bss[j];
-		if (hapd == idata->src_hapd)
-			continue;
+		if (hapd == src_hapd)
+			continue; /* don't deliver back to same interface */
+		if (!wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) ||
+		    hapd->conf->ssid.ssid_len !=
+		    src_hapd->conf->ssid.ssid_len ||
+		    os_memcmp(hapd->conf->ssid.ssid,
+			      src_hapd->conf->ssid.ssid,
+			      hapd->conf->ssid.ssid_len) != 0 ||
+		    os_memcmp(hapd->conf->mobility_domain,
+			      src_hapd->conf->mobility_domain,
+			      MOBILITY_DOMAIN_ID_LEN) != 0)
+			continue; /* no matching FT SSID/mobility domain */
 		if (!is_multicast_ether_addr(idata->dst_addr) &&
 		    os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
-			continue;
+			continue; /* destination address does not match */
 
 		/* defer eth_p_oui_deliver until next eloop step as this is
 		 * when it would be triggerd from reading from sock
@@ -733,14 +813,20 @@
 		data = os_zalloc(sizeof(*data) + idata->data_len);
 		if (!data)
 			return 1;
+		wpa_printf(MSG_DEBUG,
+			   "RRB(%s): local delivery to %s dst=" MACSTR
+			   " oui_suffix=%u data_len=%u data=%p",
+			   src_hapd->conf->iface, hapd->conf->iface,
+			   MAC2STR(idata->dst_addr), idata->oui_suffix,
+			   (unsigned int) idata->data_len, data);
 
-		os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
+		os_memcpy(data->src_addr, src_hapd->own_addr, ETH_ALEN);
 		os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
 		os_memcpy(data + 1, idata->data, idata->data_len);
 		data->data_len = idata->data_len;
 		data->oui_suffix = idata->oui_suffix;
 
-		dl_list_add(&hapd->l2_oui_queue, &data->list);
+		dl_list_add_tail(&hapd->l2_oui_queue, &data->list);
 
 		if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
 						 hapd, NULL))
@@ -748,7 +834,11 @@
 					       hostapd_oui_deliver_later,
 					       hapd, NULL);
 
-		return 1;
+		/* If dst_addr is a multicast address, do not return any
+		 * non-zero value here. Otherwise, the iteration of
+		 * for_each_interface() will be stopped. */
+		if (!is_multicast_ether_addr(idata->dst_addr))
+			return 1;
 	}
 
 	return 0;
@@ -764,6 +854,10 @@
 	struct hostapd_data *hapd = ctx;
 	struct eth_p_oui_ctx *oui_ctx;
 
+	wpa_printf(MSG_DEBUG, "RRB(%s): send to dst=" MACSTR
+		   " oui_suffix=%u data_len=%u",
+		   hapd->conf->iface, MAC2STR(dst), oui_suffix,
+		   (unsigned int) data_len);
 #ifdef CONFIG_IEEE80211R_AP
 	if (hapd->iface->interfaces &&
 	    hapd->iface->interfaces->for_each_interface) {
@@ -807,26 +901,32 @@
 #ifndef CONFIG_NO_VLAN
 	struct hostapd_data *hapd = ctx;
 	struct sta_info *sta;
-	struct vlan_description vlan_desc;
 
 	sta = ap_get_sta(hapd, addr);
 	if (!sta)
 		return -1;
 
-	os_memset(&vlan_desc, 0, sizeof(vlan_desc));
-	vlan_desc.notempty = 1;
-	vlan_desc.untagged = vlan_id;
-	if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
-		wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
-			   vlan_id);
-		return -1;
-	}
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+		struct vlan_description vlan_desc;
 
-	if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
-		wpa_printf(MSG_INFO,
-			   "Failed to assign VLAN ID %d from wpa_psk_file to "
-			   MACSTR, vlan_id, MAC2STR(sta->addr));
-		return -1;
+		os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+		vlan_desc.notempty = 1;
+		vlan_desc.untagged = vlan_id;
+		if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+			wpa_printf(MSG_INFO,
+				   "Invalid VLAN ID %d in wpa_psk_file",
+				   vlan_id);
+			return -1;
+		}
+
+		if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
+			wpa_printf(MSG_INFO,
+				   "Failed to assign VLAN ID %d from wpa_psk_file to "
+				   MACSTR, vlan_id, MAC2STR(sta->addr));
+			return -1;
+		}
+	} else {
+		sta->vlan_id = vlan_id;
 	}
 
 	wpa_printf(MSG_INFO,
@@ -888,7 +988,7 @@
 	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
 	os_memcpy(&m->u, data, data_len);
 
-	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0, NULL, 0, 0);
 	os_free(m);
 	return res;
 }
@@ -1318,6 +1418,22 @@
 		_conf.tx_status = 1;
 	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
 		_conf.ap_mlme = 1;
+
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+	    (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+	     (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+	      !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			"Disable PTK0 rekey support - replaced with disconnect");
+		_conf.wpa_deny_ptk0_rekey = 1;
+	}
+
+	if (_conf.extended_key_id &&
+	    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID))
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Extended Key ID supported");
+	else
+		_conf.extended_key_id = 0;
+
 	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
 	if (hapd->wpa_auth == NULL) {
 		wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1352,9 +1468,7 @@
 			   hapd->conf->iface;
 		hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
 					  hostapd_rrb_receive, hapd, 1);
-		if (hapd->l2 == NULL &&
-		    (hapd->driver == NULL ||
-		     hapd->driver->send_ether == NULL)) {
+		if (!hapd->l2) {
 			wpa_printf(MSG_ERROR, "Failed to open l2_packet "
 				   "interface");
 			return -1;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index a993f50..bc59d6a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -61,6 +61,8 @@
 	unsigned int pmk_len;
 	u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
 	struct wpa_ptk PTK;
+	u8 keyidx_active;
+	Boolean use_ext_key_id;
 	Boolean PTK_valid;
 	Boolean pairwise_set;
 	Boolean tk_already_set;
@@ -193,7 +195,9 @@
 	Boolean first_sta_seen;
 	Boolean reject_4way_hs_for_entropy;
 	u8 IGTK[2][WPA_IGTK_MAX_LEN];
+	u8 BIGTK[2][WPA_IGTK_MAX_LEN];
 	int GN_igtk, GM_igtk;
+	int GN_bigtk, GM_bigtk;
 	/* Number of references except those in struct wpa_group->next */
 	unsigned int references;
 	unsigned int num_setup_iface;
@@ -292,7 +296,7 @@
 		   const u8 *r0kh_id, size_t r0kh_id_len,
 		   const u8 *anonce, const u8 *snonce,
 		   u8 *buf, size_t len, const u8 *subelem,
-		   size_t subelem_len);
+		   size_t subelem_len, int rsnxe_used);
 int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
 struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 2e6d059..2ac1df4 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -297,6 +297,8 @@
 	if (rsn_testing)
 		capab |= BIT(8) | BIT(15);
 #endif /* CONFIG_RSN_TESTING */
+	if (conf->extended_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
 	WPA_PUT_LE16(pos, capab);
 	pos += 2;
 
@@ -546,13 +548,15 @@
 }
 
 
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
-			struct wpa_state_machine *sm, int freq,
-			const u8 *wpa_ie, size_t wpa_ie_len,
-			const u8 *rsnxe, size_t rsnxe_len,
-			const u8 *mdie, size_t mdie_len,
-			const u8 *owe_dh, size_t owe_dh_len)
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+		    struct wpa_state_machine *sm, int freq,
+		    const u8 *wpa_ie, size_t wpa_ie_len,
+		    const u8 *rsnxe, size_t rsnxe_len,
+		    const u8 *mdie, size_t mdie_len,
+		    const u8 *owe_dh, size_t owe_dh_len)
 {
+	struct wpa_auth_config *conf = &wpa_auth->conf;
 	struct wpa_ie_data data;
 	int ciphers, key_mgmt, res, version;
 	u32 selector;
@@ -860,6 +864,16 @@
 	}
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
+	    ((conf->dpp_pfs == 1 && !owe_dh) ||
+	     (conf->dpp_pfs == 2 && owe_dh))) {
+		wpa_printf(MSG_DEBUG, "DPP: PFS %s",
+			   conf->dpp_pfs == 1 ? "required" : "not allowed");
+		return WPA_DENIED_OTHER_REASON;
+	}
+#endif /* CONFIG_DPP2 */
+
 	sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
 	if (sm->pairwise < 0)
 		return WPA_INVALID_PAIRWISE;
@@ -944,6 +958,23 @@
 	}
 #endif /* CONFIG_DPP */
 
+	if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
+	    sm->pairwise != WPA_CIPHER_TKIP &&
+	    (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+		sm->use_ext_key_id = TRUE;
+		if (conf->extended_key_id == 2 &&
+		    !wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+		    !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+			sm->keyidx_active = 1;
+		else
+			sm->keyidx_active = 0;
+		wpa_printf(MSG_DEBUG,
+			   "RSN: Extended Key ID supported (start with %d)",
+			   sm->keyidx_active);
+	} else {
+		sm->use_ext_key_id = FALSE;
+	}
+
 	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
 		os_free(sm->wpa_ie);
 		sm->wpa_ie = os_malloc(wpa_ie_len);
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 175b9fc..1d77b94 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -125,6 +125,7 @@
 	os_memcpy(p->addr, mac_addr, ETH_ALEN);
 	os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
 	os_memcpy(p->psk, psk, PMK_LEN);
+	p->wps = 1;
 
 	if (hapd->new_psk_cb) {
 		hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
@@ -137,16 +138,17 @@
 	if (ssid->wpa_psk_file) {
 		FILE *f;
 		char hex[PMK_LEN * 2 + 1];
+
 		/* Add the new PSK to PSK list file */
 		f = fopen(ssid->wpa_psk_file, "a");
-		if (f == NULL) {
-			wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
-				   "'%s'", ssid->wpa_psk_file);
+		if (!f) {
+			wpa_printf(MSG_DEBUG, "Failed to add the PSK to '%s'",
+				   ssid->wpa_psk_file);
 			return -1;
 		}
 
 		wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
-		fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+		fprintf(f, "wps=1 " MACSTR " %s\n", MAC2STR(mac_addr), hex);
 		fclose(f);
 	}
 
@@ -269,6 +271,44 @@
 }
 
 
+static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr,
+					 const u8 **psk)
+{
+	const struct hostapd_data *hapd = ctx;
+	const struct hostapd_wpa_psk *wpa_psk;
+	const u8 *any_psk = NULL;
+	const u8 *dev_psk = NULL;
+
+	for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk;
+	     wpa_psk = wpa_psk->next) {
+		if (!wpa_psk->wps)
+			continue;
+
+		if (!any_psk && is_zero_ether_addr(wpa_psk->addr))
+			any_psk = wpa_psk->psk;
+
+		if (mac_addr && !dev_psk &&
+		    os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) {
+			dev_psk = wpa_psk->psk;
+			break;
+		}
+	}
+
+	if (dev_psk) {
+		*psk = dev_psk;
+	} else if (any_psk) {
+		*psk = any_psk;
+	} else {
+		*psk = NULL;
+		wpa_printf(MSG_DEBUG,
+			   "WPS: No appropriate PSK in wpa_psk_file");
+		return 0;
+	}
+
+	return 1;
+}
+
+
 static void wps_reload_config(void *eloop_data, void *user_ctx)
 {
 	struct hostapd_iface *iface = eloop_data;
@@ -611,8 +651,10 @@
 		    (str_starts(buf, "ssid=") ||
 		     str_starts(buf, "ssid2=") ||
 		     str_starts(buf, "auth_algs=") ||
+#ifdef CONFIG_WEP
 		     str_starts(buf, "wep_default_key=") ||
 		     str_starts(buf, "wep_key") ||
+#endif /* CONFIG_WEP */
 		     str_starts(buf, "wps_state=") ||
 		     (pmf_changed && str_starts(buf, "ieee80211w=")) ||
 		     str_starts(buf, "wpa=") ||
@@ -985,6 +1027,21 @@
 }
 
 
+static int hostapd_wps_set_application_ext(struct hostapd_data *hapd,
+					   struct wps_context *wps)
+{
+	wpabuf_free(wps->dev.application_ext);
+
+	if (!hapd->conf->wps_application_ext) {
+		wps->dev.application_ext = NULL;
+		return 0;
+	}
+
+	wps->dev.application_ext = wpabuf_dup(hapd->conf->wps_application_ext);
+	return wps->dev.application_ext ? 0 : -1;
+}
+
+
 static void hostapd_free_wps(struct wps_context *wps)
 {
 	int i;
@@ -1074,7 +1131,8 @@
 	os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
 		  WPS_DEV_TYPE_LEN);
 
-	if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
+	if (hostapd_wps_set_vendor_ext(hapd, wps) < 0 ||
+	    hostapd_wps_set_application_ext(hapd, wps) < 0)
 		goto fail;
 
 	wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
@@ -1140,6 +1198,7 @@
 		wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
 				 conf->ssid.wpa_psk->psk, PMK_LEN);
 		wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
 	} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
 		wps->network_key = os_malloc(conf->ssid.wep.len[0]);
 		if (wps->network_key == NULL)
@@ -1147,6 +1206,7 @@
 		os_memcpy(wps->network_key, conf->ssid.wep.key[0],
 			  conf->ssid.wep.len[0]);
 		wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
 	}
 
 	if (conf->ssid.wpa_psk) {
@@ -1197,14 +1257,13 @@
 	cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
 	cfg.reg_success_cb = hostapd_wps_reg_success_cb;
 	cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+	cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb;
 	cfg.cb_ctx = hapd;
 	cfg.skip_cred_build = conf->skip_cred_build;
 	cfg.extra_cred = conf->extra_cred;
 	cfg.extra_cred_len = conf->extra_cred_len;
 	cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
 		conf->skip_cred_build;
-	if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
-		cfg.static_wep_only = 1;
 	cfg.dualband = interface_count(hapd->iface) > 1;
 	if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
 	    (WPS_RF_50GHZ | WPS_RF_24GHZ))
@@ -1311,6 +1370,7 @@
 #endif /* CONFIG_WPS_UPNP */
 
 	hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+	hostapd_wps_set_application_ext(hapd, hapd->wps);
 
 	if (hapd->conf->wps_state)
 		wps_registrar_update_ie(hapd->wps->registrar);
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 7694c96..a58bf66 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -434,7 +434,8 @@
 		goto fail;
 
 	/* Check that output matches the test vector */
-	sae_write_commit(&sae, buf, NULL, pwid);
+	if (sae_write_commit(&sae, buf, NULL, pwid) < 0)
+		goto fail;
 	wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
 
 	if (wpabuf_len(buf) != sizeof(local_commit) ||
diff --git a/src/common/defs.h b/src/common/defs.h
index e2fa4b2..f62c3ce 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -82,6 +82,13 @@
 			 WPA_KEY_MGMT_FT_FILS_SHA384));
 }
 
+static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_PSK |
+			 WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_PSK_SHA256));
+}
+
 static inline int wpa_key_mgmt_wpa_psk(int akm)
 {
 	return !!(akm & (WPA_KEY_MGMT_PSK |
@@ -193,7 +200,6 @@
 	WPA_ALG_TKIP,
 	WPA_ALG_CCMP,
 	WPA_ALG_IGTK,
-	WPA_ALG_PMK,
 	WPA_ALG_GCMP,
 	WPA_ALG_SMS4,
 	WPA_ALG_KRK,
@@ -423,4 +429,47 @@
 	CHAN_WIDTH_UNKNOWN
 };
 
+enum key_flag {
+	KEY_FLAG_MODIFY			= BIT(0),
+	KEY_FLAG_DEFAULT		= BIT(1),
+	KEY_FLAG_RX			= BIT(2),
+	KEY_FLAG_TX			= BIT(3),
+	KEY_FLAG_GROUP			= BIT(4),
+	KEY_FLAG_PAIRWISE		= BIT(5),
+	KEY_FLAG_PMK			= BIT(6),
+	/* Used flag combinations */
+	KEY_FLAG_RX_TX			= KEY_FLAG_RX | KEY_FLAG_TX,
+	KEY_FLAG_GROUP_RX_TX		= KEY_FLAG_GROUP | KEY_FLAG_RX_TX,
+	KEY_FLAG_GROUP_RX_TX_DEFAULT	= KEY_FLAG_GROUP_RX_TX |
+					  KEY_FLAG_DEFAULT,
+	KEY_FLAG_GROUP_RX		= KEY_FLAG_GROUP | KEY_FLAG_RX,
+	KEY_FLAG_GROUP_TX_DEFAULT	= KEY_FLAG_GROUP | KEY_FLAG_TX |
+					  KEY_FLAG_DEFAULT,
+	KEY_FLAG_PAIRWISE_RX_TX		= KEY_FLAG_PAIRWISE | KEY_FLAG_RX_TX,
+	KEY_FLAG_PAIRWISE_RX		= KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
+	KEY_FLAG_PAIRWISE_RX_TX_MODIFY	= KEY_FLAG_PAIRWISE_RX_TX |
+					  KEY_FLAG_MODIFY,
+	/* Max allowed flags for each key type */
+	KEY_FLAG_PAIRWISE_MASK		= KEY_FLAG_PAIRWISE_RX_TX_MODIFY,
+	KEY_FLAG_GROUP_MASK		= KEY_FLAG_GROUP_RX_TX_DEFAULT,
+	KEY_FLAG_PMK_MASK		= KEY_FLAG_PMK,
+};
+
+static inline int check_key_flag(enum key_flag key_flag)
+{
+	return !!(!key_flag ||
+		  ((key_flag & (KEY_FLAG_PAIRWISE | KEY_FLAG_MODIFY)) &&
+		   (key_flag & ~KEY_FLAG_PAIRWISE_MASK)) ||
+		  ((key_flag & KEY_FLAG_GROUP) &&
+		   (key_flag & ~KEY_FLAG_GROUP_MASK)) ||
+		  ((key_flag & KEY_FLAG_PMK) &&
+		   (key_flag & ~KEY_FLAG_PMK_MASK)));
+}
+
+enum ptk0_rekey_handling {
+	PTK0_REKEY_ALLOW_ALWAYS,
+	PTK0_REKEY_ALLOW_LOCAL_OK,
+	PTK0_REKEY_ALLOW_NEVER
+};
+
 #endif /* DEFS_H */
diff --git a/src/common/dhcp.h b/src/common/dhcp.h
index e38512c..7dc67d5 100644
--- a/src/common/dhcp.h
+++ b/src/common/dhcp.h
@@ -39,7 +39,7 @@
 } STRUCT_PACKED;
 
 struct bootp_pkt {
-	struct iphdr iph;
+	struct ip iph;
 	struct udphdr udph;
 	u8 op;
 	u8 htype;
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 7542c66..d8690ad 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -1,7 +1,7 @@
 /*
  * DPP functionality shared between hostapd and wpa_supplicant
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,6 +29,7 @@
 #include "crypto/aes_siv.h"
 #include "crypto/sha384.h"
 #include "crypto/sha512.h"
+#include "tls/asn1.h"
 #include "drivers/driver.h"
 #include "dpp.h"
 
@@ -72,6 +73,14 @@
 		*ps = sig->s;
 }
 
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+	if (pkey->type != EVP_PKEY_EC)
+		return NULL;
+	return pkey->pkey.ec;
+}
+
 #endif
 
 
@@ -130,6 +139,7 @@
 	struct dl_list tcp_init; /* struct dpp_connection */
 	void *cb_ctx;
 	int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+	void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
 #endif /* CONFIG_DPP2 */
 };
 
@@ -453,6 +463,76 @@
 }
 
 
+#ifdef CONFIG_DPP2
+
+static int dpp_pbkdf2_f(size_t hash_len,
+			const u8 *password, size_t password_len,
+			const u8 *salt, size_t salt_len,
+			unsigned int iterations, unsigned int count, u8 *digest)
+{
+	unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
+	unsigned int i;
+	size_t j;
+	u8 count_buf[4];
+	const u8 *addr[2];
+	size_t len[2];
+
+	addr[0] = salt;
+	len[0] = salt_len;
+	addr[1] = count_buf;
+	len[1] = 4;
+
+	/* F(P, S, c, i) = U1 xor U2 xor ... Uc
+	 * U1 = PRF(P, S || i)
+	 * U2 = PRF(P, U1)
+	 * Uc = PRF(P, Uc-1)
+	 */
+
+	WPA_PUT_BE32(count_buf, count);
+	if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
+			    tmp))
+		return -1;
+	os_memcpy(digest, tmp, hash_len);
+
+	for (i = 1; i < iterations; i++) {
+		if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
+			     tmp2))
+			return -1;
+		os_memcpy(tmp, tmp2, hash_len);
+		for (j = 0; j < hash_len; j++)
+			digest[j] ^= tmp2[j];
+	}
+
+	return 0;
+}
+
+
+static int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
+		      const u8 *salt, size_t salt_len, unsigned int iterations,
+		      u8 *buf, size_t buflen)
+{
+	unsigned int count = 0;
+	unsigned char *pos = buf;
+	size_t left = buflen, plen;
+	unsigned char digest[DPP_MAX_HASH_LEN];
+
+	while (left > 0) {
+		count++;
+		if (dpp_pbkdf2_f(hash_len, password, password_len,
+				 salt, salt_len, iterations, count, digest))
+			return -1;
+		plen = left > hash_len ? hash_len : left;
+		os_memcpy(pos, digest, plen);
+		pos += plen;
+		left -= plen;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
 static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
 {
 	int num_bytes, offset;
@@ -820,7 +900,10 @@
 		return;
 	os_free(info->uri);
 	os_free(info->info);
+	os_free(info->chan);
+	os_free(info->pk);
 	EVP_PKEY_free(info->pubkey);
+	str_clear_free(info->configurator_params);
 	os_free(info);
 }
 
@@ -982,6 +1065,32 @@
 }
 
 
+static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
+			      const u8 *data, size_t data_len)
+{
+	const u8 *addr[2];
+	size_t len[2];
+
+	addr[0] = data;
+	len[0] = data_len;
+	if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
+		    bi->pubkey_hash, SHA256_MAC_LEN);
+
+	addr[0] = (const u8 *) "chirp";
+	len[0] = 5;
+	addr[1] = data;
+	len[1] = data_len;
+	if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
+		    bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+
+	return 0;
+}
+
+
 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
 {
 	const char *end;
@@ -1020,14 +1129,11 @@
 	wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
 		    data, data_len);
 
-	if (sha256_vector(1, (const u8 **) &data, &data_len,
-			  bi->pubkey_hash) < 0) {
+	if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
 		os_free(data);
 		return -1;
 	}
-	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
-		    bi->pubkey_hash, SHA256_MAC_LEN);
 
 	/* DER encoded ASN.1 SubjectPublicKeyInfo
 	 *
@@ -1445,41 +1551,31 @@
 }
 
 
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+static int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
 {
 	struct wpabuf *der;
 	int res;
-	const u8 *addr[1];
-	size_t len[1];
 
 	der = dpp_bootstrap_key_der(bi->pubkey);
 	if (!der)
 		return -1;
 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
 			der);
-
-	addr[0] = wpabuf_head(der);
-	len[0] = wpabuf_len(der);
-	res = sha256_vector(1, addr, len, bi->pubkey_hash);
+	res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
 	if (res < 0)
 		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
-	else
-		wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
-			    SHA256_MAC_LEN);
 	wpabuf_free(der);
 	return res;
 }
 
 
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
-		  const u8 *privkey, size_t privkey_len)
+static int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
+		      const u8 *privkey, size_t privkey_len)
 {
 	char *base64 = NULL;
 	char *pos, *end;
 	size_t len;
 	struct wpabuf *der = NULL;
-	const u8 *addr[1];
-	int res;
 
 	if (!curve) {
 		bi->curve = &dpp_curves[0];
@@ -1488,7 +1584,7 @@
 		if (!bi->curve) {
 			wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
 				   curve);
-			return NULL;
+			return -1;
 		}
 	}
 	if (privkey)
@@ -1505,15 +1601,10 @@
 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
 			der);
 
-	addr[0] = wpabuf_head(der);
-	len = wpabuf_len(der);
-	res = sha256_vector(1, addr, &len, bi->pubkey_hash);
-	if (res < 0) {
+	if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
 		goto fail;
 	}
-	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
-		    SHA256_MAC_LEN);
 
 	base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
 	wpabuf_free(der);
@@ -1528,11 +1619,13 @@
 			break;
 		os_memmove(pos, pos + 1, end - pos);
 	}
-	return base64;
+	os_free(bi->pk);
+	bi->pk = base64;
+	return 0;
 fail:
 	os_free(base64);
 	wpabuf_free(der);
-	return NULL;
+	return -1;
 }
 
 
@@ -1916,9 +2009,11 @@
 
 #ifdef CONFIG_DPP2
 	/* Protocol Version */
-	wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
-	wpabuf_put_le16(msg, 1);
-	wpabuf_put_u8(msg, 2);
+	if (auth->peer_version >= 2) {
+		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+		wpabuf_put_le16(msg, 1);
+		wpabuf_put_u8(msg, 2);
+	}
 #endif /* CONFIG_DPP2 */
 
 	attr_end = wpabuf_put(msg, 0);
@@ -2159,6 +2254,7 @@
 
 
 static int dpp_prepare_channel_list(struct dpp_authentication *auth,
+				    unsigned int neg_freq,
 				    struct hostapd_hw_modes *own_modes,
 				    u16 num_modes)
 {
@@ -2166,6 +2262,14 @@
 	char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
 	unsigned int i;
 
+	if (!own_modes) {
+		if (!neg_freq)
+			return -1;
+		auth->num_freq = 1;
+		auth->freq[0] = neg_freq;
+		return 0;
+	}
+
 	if (auth->peer_bi->num_freq > 0)
 		res = dpp_channel_intersect(auth, own_modes, num_modes);
 	else
@@ -2198,11 +2302,42 @@
 }
 
 
+static int dpp_gen_uri(struct dpp_bootstrap_info *bi)
+{
+	char macstr[ETH_ALEN * 2 + 10];
+	size_t len;
+
+	len = 4; /* "DPP:" */
+	if (bi->chan)
+		len += 3 + os_strlen(bi->chan); /* C:...; */
+	if (is_zero_ether_addr(bi->mac_addr))
+		macstr[0] = '\0';
+	else
+		os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
+			    MAC2STR(bi->mac_addr));
+	len += os_strlen(macstr); /* M:...; */
+	if (bi->info)
+		len += 3 + os_strlen(bi->info); /* I:...; */
+	len += 4 + os_strlen(bi->pk); /* K:...;; */
+
+	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%sK:%s;;",
+		    bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
+		    bi->chan ? ";" : "",
+		    macstr,
+		    bi->info ? "I:" : "", bi->info ? bi->info : "",
+		    bi->info ? ";" : "",
+		    bi->pk);
+	return 0;
+}
+
+
 static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
 {
 	struct dpp_bootstrap_info *bi;
-	char *pk = NULL;
-	size_t len;
 
 	if (auth->own_bi)
 		return 0; /* already generated */
@@ -2211,33 +2346,38 @@
 	if (!bi)
 		return -1;
 	bi->type = DPP_BOOTSTRAP_QR_CODE;
-	pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
-	if (!pk)
+	if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
+	    dpp_gen_uri(bi) < 0)
 		goto fail;
-
-	len = 4; /* "DPP:" */
-	len += 4 + os_strlen(pk);
-	bi->uri = os_malloc(len + 1);
-	if (!bi->uri)
-		goto fail;
-	os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
 	wpa_printf(MSG_DEBUG,
 		   "DPP: Auto-generated own bootstrapping key info: URI %s",
 		   bi->uri);
 
 	auth->tmp_own_bi = auth->own_bi = bi;
 
-	os_free(pk);
-
 	return 0;
 fail:
-	os_free(pk);
 	dpp_bootstrap_info_free(bi);
 	return -1;
 }
 
 
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
+{
+	struct dpp_authentication *auth;
+
+	auth = os_zalloc(sizeof(*auth));
+	if (!auth)
+		return NULL;
+	auth->global = dpp;
+	auth->msg_ctx = msg_ctx;
+	auth->conf_resp_status = 255;
+	return auth;
+}
+
+
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
 					  struct dpp_bootstrap_info *peer_bi,
 					  struct dpp_bootstrap_info *own_bi,
 					  u8 dpp_allowed_roles,
@@ -2254,10 +2394,12 @@
 	u8 test_hash[SHA256_MAC_LEN];
 #endif /* CONFIG_TESTING_OPTIONS */
 
-	auth = os_zalloc(sizeof(*auth));
+	auth = dpp_alloc_auth(dpp, msg_ctx);
 	if (!auth)
 		return NULL;
-	auth->msg_ctx = msg_ctx;
+	if (peer_bi->configurator_params &&
+	    dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+		goto fail;
 	auth->initiator = 1;
 	auth->waiting_auth_resp = 1;
 	auth->allowed_roles = dpp_allowed_roles;
@@ -2267,7 +2409,7 @@
 	auth->curve = peer_bi->curve;
 
 	if (dpp_autogen_bootstrap_key(auth) < 0 ||
-	    dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
+	    dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0)
 		goto fail;
 
 #ifdef CONFIG_TESTING_OPTIONS
@@ -2363,6 +2505,8 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
+	if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq)
+		neg_freq = 0;
 	auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
 					   i_pubkey_hash, neg_freq);
 	if (!auth->req_msg)
@@ -3149,8 +3293,8 @@
 
 
 struct dpp_authentication *
-dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
-		struct dpp_bootstrap_info *peer_bi,
+dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
+		int qr_mutual, struct dpp_bootstrap_info *peer_bi,
 		struct dpp_bootstrap_info *own_bi,
 		unsigned int freq, const u8 *hdr, const u8 *attr_start,
 		size_t attr_len)
@@ -3191,10 +3335,12 @@
 		    wrapped_data, wrapped_data_len);
 	attr_len = wrapped_data - 4 - attr_start;
 
-	auth = os_zalloc(sizeof(*auth));
+	auth = dpp_alloc_auth(dpp, msg_ctx);
 	if (!auth)
 		goto fail;
-	auth->msg_ctx = msg_ctx;
+	if (peer_bi && peer_bi->configurator_params &&
+	    dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+		goto fail;
 	auth->peer_bi = peer_bi;
 	auth->own_bi = own_bi;
 	auth->curve = own_bi->curve;
@@ -4137,7 +4283,11 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
-	if (auth->initiator || !auth->own_bi) {
+	if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
+			   auth->initiator, !!auth->own_bi,
+			   auth->waiting_auth_conf);
 		dpp_auth_fail(auth, "Unexpected Authentication Confirm");
 		return -1;
 	}
@@ -4404,6 +4554,10 @@
 		conf = conf_ap;
 	}
 
+	pos = os_strstr(cmd, " conf=configurator");
+	if (pos)
+		auth->provision_configurator = 1;
+
 	if (!conf)
 		return 0;
 
@@ -4558,25 +4712,38 @@
 }
 
 
-int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
-			 struct dpp_authentication *auth,
-			 const char *cmd)
+int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
 {
 	const char *pos;
+	char *tmp = NULL;
+	int ret = -1;
 
-	if (!cmd)
+	if (!cmd || auth->configurator_set)
 		return 0;
+	auth->configurator_set = 1;
+
+	if (cmd[0] != ' ') {
+		size_t len;
+
+		len = os_strlen(cmd);
+		tmp = os_malloc(len + 2);
+		if (!tmp)
+			goto fail;
+		tmp[0] = ' ';
+		os_memcpy(tmp + 1, cmd, len + 1);
+		cmd = tmp;
+	}
 
 	wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
 
 	pos = os_strstr(cmd, " configurator=");
 	if (pos) {
 		pos += 14;
-		auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
+		auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
 		if (!auth->conf) {
 			wpa_printf(MSG_INFO,
 				   "DPP: Could not find the specified configurator");
-			return -1;
+			goto fail;
 		}
 	}
 
@@ -4593,11 +4760,28 @@
 	}
 
 	if (dpp_configuration_parse(auth, cmd) < 0) {
-		wpa_msg(msg_ctx, MSG_INFO,
+		wpa_msg(auth->msg_ctx, MSG_INFO,
 			"DPP: Failed to set configurator parameters");
-		return -1;
+		goto fail;
 	}
-	return 0;
+	ret = 0;
+fail:
+	os_free(tmp);
+	return ret;
+}
+
+
+static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
+{
+	while (key) {
+		struct dpp_asymmetric_key *next = key->next;
+
+		EVP_PKEY_free(key->csign);
+		str_clear_free(key->config_template);
+		str_clear_free(key->connector_template);
+		os_free(key);
+		key = next;
+	}
 }
 
 
@@ -4622,6 +4806,7 @@
 		os_free(conf->connector);
 		wpabuf_free(conf->c_sign_key);
 	}
+	dpp_free_asymmetric_key(auth->conf_key_pkg);
 	wpabuf_free(auth->net_access_key);
 	dpp_bootstrap_info_free(auth->tmp_own_bi);
 #ifdef CONFIG_TESTING_OPTIONS
@@ -5051,17 +5236,499 @@
 		return NULL;
 	}
 
-	if (dpp_akm_dpp(conf->akm))
+	if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
 		return dpp_build_conf_obj_dpp(auth, conf);
 	return dpp_build_conf_obj_legacy(auth, conf);
 }
 
 
+#ifdef CONFIG_DPP2
+
+static struct wpabuf * dpp_build_conf_params(void)
+{
+	struct wpabuf *buf;
+	size_t len;
+	/* TODO: proper template values */
+	const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
+	const char *connector_template = NULL;
+
+	len = 100 + os_strlen(conf_template);
+	if (connector_template)
+		len += os_strlen(connector_template);
+	buf = wpabuf_alloc(len);
+	if (!buf)
+		return NULL;
+
+	/*
+	 * DPPConfigurationParameters ::= SEQUENCE {
+	 *    configurationTemplate	UTF8String,
+	 *    connectorTemplate		UTF8String OPTIONAL}
+	 */
+
+	asn1_put_utf8string(buf, conf_template);
+	if (connector_template)
+		asn1_put_utf8string(buf, connector_template);
+	return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_attribute(void)
+{
+	struct wpabuf *conf_params, *attr;
+
+	/*
+	 * aa-DPPConfigurationParameters ATTRIBUTE ::=
+	 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+	 *
+	 * Attribute ::= SEQUENCE {
+	 *    type OBJECT IDENTIFIER,
+	 *    values SET SIZE(1..MAX) OF Type
+	 */
+	conf_params = dpp_build_conf_params();
+	conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
+				  ASN1_TAG_SET);
+	if (!conf_params)
+		return NULL;
+
+	attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
+	if (!attr) {
+		wpabuf_clear_free(conf_params);
+		return NULL;
+	}
+
+	asn1_put_oid(attr, &asn1_dpp_config_params_oid);
+	wpabuf_put_buf(attr, conf_params);
+	wpabuf_clear_free(conf_params);
+
+	return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
+{
+	const struct asn1_oid *oid;
+	struct wpabuf *params, *res;
+
+	switch (curve->ike_group) {
+	case 19:
+		oid = &asn1_prime256v1_oid;
+		break;
+	case 20:
+		oid = &asn1_secp384r1_oid;
+		break;
+	case 21:
+		oid = &asn1_secp521r1_oid;
+		break;
+	case 28:
+		oid = &asn1_brainpoolP256r1_oid;
+		break;
+	case 29:
+		oid = &asn1_brainpoolP384r1_oid;
+		break;
+	case 30:
+		oid = &asn1_brainpoolP512r1_oid;
+		break;
+	default:
+		return NULL;
+	}
+
+	params = wpabuf_alloc(20);
+	if (!params)
+		return NULL;
+	asn1_put_oid(params, oid); /* namedCurve */
+
+	res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
+	wpabuf_free(params);
+	return res;
+}
+
+
+static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
+{
+	struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
+	EC_KEY *eckey;
+	unsigned char *der = NULL;
+	int der_len;
+
+	eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
+	if (!eckey)
+		return NULL;
+
+	EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+	der_len = i2d_ECPrivateKey(eckey, &der);
+	if (der_len > 0)
+		priv_key = wpabuf_alloc_copy(der, der_len);
+	OPENSSL_free(der);
+
+	alg = dpp_build_key_alg(auth->conf->curve);
+
+	/* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
+	attr = dpp_build_attribute();
+	attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
+	if (!priv_key || !attr || !alg)
+		goto fail;
+
+	/*
+	 * OneAsymmetricKey ::= SEQUENCE {
+	 *    version			Version,
+	 *    privateKeyAlgorithm	PrivateKeyAlgorithmIdentifier,
+	 *    privateKey		PrivateKey,
+	 *    attributes		[0] Attributes OPTIONAL,
+	 *    ...,
+	 *    [[2: publicKey		[1] BIT STRING OPTIONAL ]],
+	 *    ...
+	 * }
+	 */
+
+	key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
+			   wpabuf_len(attr));
+	if (!key)
+		goto fail;
+
+	asn1_put_integer(key, 1); /* version = v2(1) */
+
+	/* PrivateKeyAlgorithmIdentifier */
+	wpabuf_put_buf(key, alg);
+
+	/* PrivateKey ::= OCTET STRING */
+	asn1_put_octet_string(key, priv_key);
+
+	/* [0] Attributes OPTIONAL */
+	asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
+	wpabuf_put_buf(key, attr);
+
+fail:
+	wpabuf_clear_free(attr);
+	wpabuf_clear_free(priv_key);
+	wpabuf_free(alg);
+
+	/*
+	 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+	 *
+	 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+	 *
+	 * OneAsymmetricKey ::= SEQUENCE
+	 */
+	return asn1_encaps(asn1_encaps(key,
+				       ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
+			   ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
+					       size_t hash_len)
+{
+	struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
+	const struct asn1_oid *oid;
+
+	/*
+	 * PBKDF2-params ::= SEQUENCE {
+	 *    salt CHOICE {
+	 *       specified OCTET STRING,
+	 *       otherSource AlgorithmIdentifier}
+	 *    iterationCount INTEGER (1..MAX),
+	 *    keyLength INTEGER (1..MAX),
+	 *    prf AlgorithmIdentifier}
+	 *
+	 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+	 * on Configurator signing key length, prf is
+	 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+	 */
+
+	if (hash_len == 32)
+		oid = &asn1_pbkdf2_hmac_sha256_oid;
+	else if (hash_len == 48)
+		oid = &asn1_pbkdf2_hmac_sha384_oid;
+	else if (hash_len == 64)
+		oid = &asn1_pbkdf2_hmac_sha512_oid;
+	else
+		goto fail;
+	prf = asn1_build_alg_id(oid, NULL);
+	if (!prf)
+		goto fail;
+	params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
+	if (!params)
+		goto fail;
+	asn1_put_octet_string(params, salt); /* salt.specified */
+	asn1_put_integer(params, 1000); /* iterationCount */
+	asn1_put_integer(params, hash_len); /* keyLength */
+	wpabuf_put_buf(params, prf);
+	params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+	if (!params)
+		goto fail;
+	buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
+fail:
+	wpabuf_free(params);
+	wpabuf_free(prf);
+	return buf;
+}
+
+
+static struct wpabuf *
+dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+			    const struct wpabuf *cont_enc_key)
+{
+	struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
+		*key_enc_alg = NULL, *salt;
+	u8 kek[DPP_MAX_HASH_LEN];
+	const u8 *key;
+	size_t key_len;
+
+	salt = wpabuf_alloc(64);
+	if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
+		goto fail;
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
+
+	/* TODO: For initial testing, use ke as the key. Replace this with a
+	 * new key once that has been defined. */
+	key = auth->ke;
+	key_len = auth->curve->hash_len;
+	wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+	if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
+		       kek, hash_len)) {
+		wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+		goto fail;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+			kek, hash_len);
+
+	enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
+	if (!enc_key ||
+	    aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
+			    wpabuf_len(cont_enc_key), 0, NULL, NULL,
+			    wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
+		goto fail;
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
+
+	/*
+	 * PasswordRecipientInfo ::= SEQUENCE {
+	 *    version			CMSVersion,
+	 *    keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+	 *    keyEncryptionAlgorithm	KeyEncryptionAlgorithmIdentifier,
+	 *    encryptedKey		EncryptedKey}
+	 *
+	 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+	 * parameters contains PBKDF2-params SEQUENCE.
+	 */
+
+	key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
+	key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
+	if (!key_der_alg || !key_enc_alg)
+		goto fail;
+	pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
+			    wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
+	if (!pwri)
+		goto fail;
+
+	/* version = 0 */
+	asn1_put_integer(pwri, 0);
+
+	/* [0] KeyDerivationAlgorithmIdentifier */
+	asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
+		     wpabuf_len(key_der_alg));
+	wpabuf_put_buf(pwri, key_der_alg);
+
+	/* KeyEncryptionAlgorithmIdentifier */
+	wpabuf_put_buf(pwri, key_enc_alg);
+
+	/* EncryptedKey ::= OCTET STRING */
+	asn1_put_octet_string(pwri, enc_key);
+
+fail:
+	wpabuf_clear_free(key_der_alg);
+	wpabuf_free(key_enc_alg);
+	wpabuf_free(enc_key);
+	wpabuf_free(salt);
+	forced_memzero(kek, sizeof(kek));
+	return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf *
+dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+			 const struct wpabuf *cont_enc_key)
+{
+	struct wpabuf *pwri;
+
+	/*
+	 * RecipientInfo ::= CHOICE {
+	 *    ktri		KeyTransRecipientInfo,
+	 *    kari	[1]	KeyAgreeRecipientInfo,
+	 *    kekri	[2]	KEKRecipientInfo,
+	 *    pwri	[3]	PasswordRecipientInfo,
+	 *    ori	[4]	OtherRecipientInfo}
+	 *
+	 * Shall always use the pwri CHOICE.
+	 */
+
+	pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
+	return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
+}
+
+
+static struct wpabuf *
+dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
+			const struct wpabuf *cont_enc_key)
+{
+	struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
+		*enc_alg;
+	const struct asn1_oid *oid;
+	size_t enc_cont_len;
+
+	/*
+	 * EncryptedContentInfo ::= SEQUENCE {
+	 *    contentType			ContentType,
+	 *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+	 *    encryptedContent	[0] IMPLICIT	EncryptedContent OPTIONAL}
+	 */
+
+	if (hash_len == 32)
+		oid = &asn1_aes_siv_cmac_aead_256_oid;
+	else if (hash_len == 48)
+		oid = &asn1_aes_siv_cmac_aead_384_oid;
+	else if (hash_len == 64)
+		oid = &asn1_aes_siv_cmac_aead_512_oid;
+	else
+		return NULL;
+
+	key_pkg = dpp_build_key_pkg(auth);
+	enc_alg = asn1_build_alg_id(oid, NULL);
+	if (!key_pkg || !enc_alg)
+		goto fail;
+
+	wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+			    key_pkg);
+
+	enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
+	enc_cont = wpabuf_alloc(enc_cont_len);
+	if (!enc_cont ||
+	    aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
+			    wpabuf_head(key_pkg), wpabuf_len(key_pkg),
+			    0, NULL, NULL,
+			    wpabuf_put(enc_cont, enc_cont_len)) < 0)
+		goto fail;
+
+	enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
+				     wpabuf_len(enc_cont));
+	if (!enc_cont_info)
+		goto fail;
+
+	/* ContentType ::= OBJECT IDENTIFIER */
+	asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
+
+	/* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+	wpabuf_put_buf(enc_cont_info, enc_alg);
+
+	/* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+	 * EncryptedContent ::= OCTET STRING */
+	asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
+		     wpabuf_len(enc_cont));
+	wpabuf_put_buf(enc_cont_info, enc_cont);
+
+fail:
+	wpabuf_clear_free(key_pkg);
+	wpabuf_free(enc_cont);
+	wpabuf_free(enc_alg);
+	return enc_cont_info;
+}
+
+
+static struct wpabuf * dpp_gen_random(size_t len)
+{
+	struct wpabuf *key;
+
+	key = wpabuf_alloc(len);
+	if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
+		wpabuf_free(key);
+		key = NULL;
+	}
+	wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
+	return key;
+}
+
+
+static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
+{
+	struct wpabuf *env = NULL;
+	struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
+	struct wpabuf *cont_enc_key = NULL;
+	size_t hash_len;
+
+	if (!auth->conf) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
+		return NULL;
+	}
+
+	if (!auth->provision_configurator) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Configurator provisioning not allowed");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
+
+	hash_len = auth->conf->curve->hash_len;
+	cont_enc_key = dpp_gen_random(hash_len);
+	if (!cont_enc_key)
+		goto fail;
+	recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
+	enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
+	if (!recipient_info || !enc_cont_info)
+		goto fail;
+
+	env = wpabuf_alloc(wpabuf_len(recipient_info) +
+			   wpabuf_len(enc_cont_info) +
+			   100);
+	if (!env)
+		goto fail;
+
+	/*
+	 * DPPEnvelopedData ::= EnvelopedData
+	 *
+	 * EnvelopedData ::= SEQUENCE {
+	 *    version			CMSVersion,
+	 *    originatorInfo	[0]	IMPLICIT OriginatorInfo OPTIONAL,
+	 *    recipientInfos		RecipientInfos,
+	 *    encryptedContentInfo	EncryptedContentInfo,
+	 *    unprotectedAttrs  [1] IMPLICIT	UnprotectedAttributes OPTIONAL}
+	 *
+	 * For DPP, version is 3, both originatorInfo and
+	 * unprotectedAttrs are omitted, and recipientInfos contains a single
+	 * RecipientInfo.
+	 */
+
+	/* EnvelopedData.version = 3 */
+	asn1_put_integer(env, 3);
+
+	/* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
+	asn1_put_set(env, recipient_info);
+
+	/* EncryptedContentInfo ::= SEQUENCE */
+	asn1_put_sequence(env, enc_cont_info);
+
+	env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
+out:
+	wpabuf_clear_free(cont_enc_key);
+	wpabuf_clear_free(recipient_info);
+	wpabuf_free(enc_cont_info);
+	return env;
+fail:
+	wpabuf_free(env);
+	env = NULL;
+	goto out;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
 static struct wpabuf *
 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
 		    u16 e_nonce_len, enum dpp_netrole netrole)
 {
-	struct wpabuf *conf, *conf2 = NULL;
+	struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
 	size_t clear_len, attr_len;
 	struct wpabuf *clear = NULL, *msg = NULL;
 	u8 *wrapped;
@@ -5069,13 +5736,21 @@
 	size_t len[1];
 	enum dpp_status_error status;
 
-	conf = dpp_build_conf_obj(auth, netrole, 0);
-	if (conf) {
-		wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
-				  wpabuf_head(conf), wpabuf_len(conf));
-		conf2 = dpp_build_conf_obj(auth, netrole, 1);
+	if (netrole == DPP_NETROLE_CONFIGURATOR) {
+#ifdef CONFIG_DPP2
+		env_data = dpp_build_enveloped_data(auth);
+#endif /* CONFIG_DPP2 */
+	} else {
+		conf = dpp_build_conf_obj(auth, netrole, 0);
+		if (conf) {
+			wpa_hexdump_ascii(MSG_DEBUG,
+					  "DPP: configurationObject JSON",
+					  wpabuf_head(conf), wpabuf_len(conf));
+			conf2 = dpp_build_conf_obj(auth, netrole, 1);
+		}
 	}
-	status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
+	status = (conf || env_data) ? DPP_STATUS_OK :
+		DPP_STATUS_CONFIGURE_FAILURE;
 	auth->conf_resp_status = status;
 
 	/* { E-nonce, configurationObject[, sendConnStatus]}ke */
@@ -5084,6 +5759,8 @@
 		clear_len += 4 + wpabuf_len(conf);
 	if (conf2)
 		clear_len += 4 + wpabuf_len(conf2);
+	if (env_data)
+		clear_len += 4 + wpabuf_len(env_data);
 	if (auth->peer_version >= 2 && auth->send_conn_status &&
 	    netrole == DPP_NETROLE_STA)
 		clear_len += 4;
@@ -5142,6 +5819,11 @@
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Second Config Object available, but peer does not support more than one");
 	}
+	if (env_data) {
+		wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
+		wpabuf_put_le16(clear, wpabuf_len(env_data));
+		wpabuf_put_buf(clear, env_data);
+	}
 
 	if (auth->peer_version >= 2 && auth->send_conn_status &&
 	    netrole == DPP_NETROLE_STA) {
@@ -5196,9 +5878,10 @@
 	wpa_hexdump_buf(MSG_DEBUG,
 			"DPP: Configuration Response attributes", msg);
 out:
-	wpabuf_free(conf);
-	wpabuf_free(conf2);
-	wpabuf_free(clear);
+	wpabuf_clear_free(conf);
+	wpabuf_clear_free(conf2);
+	wpabuf_clear_free(env_data);
+	wpabuf_clear_free(clear);
 
 	return msg;
 fail:
@@ -6047,7 +6730,8 @@
 	conf->connector = os_strdup(signed_connector);
 
 	dpp_copy_csign(conf, csign_pub);
-	dpp_copy_netaccesskey(auth, conf);
+	if (dpp_akm_dpp(conf->akm))
+		dpp_copy_netaccesskey(auth, conf);
 
 	ret = 0;
 fail:
@@ -6159,6 +6843,7 @@
 	struct json_token *root, *token, *discovery, *cred;
 	struct dpp_config_obj *conf;
 	struct wpabuf *ssid64 = NULL;
+	int legacy;
 
 	root = json_parse((const char *) conf_obj, conf_obj_len);
 	if (!root)
@@ -6246,10 +6931,21 @@
 	}
 	conf->akm = dpp_akm_from_str(token->string);
 
-	if (dpp_akm_legacy(conf->akm)) {
+	legacy = dpp_akm_legacy(conf->akm);
+	if (legacy && auth->peer_version >= 2) {
+		struct json_token *csign, *s_conn;
+
+		csign = json_get_member(cred, "csign");
+		s_conn = json_get_member(cred, "signedConnector");
+		if (csign && csign->type == JSON_OBJECT &&
+		    s_conn && s_conn->type == JSON_STRING)
+			legacy = 0;
+	}
+	if (legacy) {
 		if (dpp_parse_cred_legacy(conf, cred) < 0)
 			goto fail;
-	} else if (dpp_akm_dpp(conf->akm)) {
+	} else if (dpp_akm_dpp(conf->akm) ||
+		   (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
 		if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
 			goto fail;
 	} else {
@@ -6268,11 +6964,716 @@
 }
 
 
+#ifdef CONFIG_DPP2
+
+struct dpp_enveloped_data {
+	const u8 *enc_cont;
+	size_t enc_cont_len;
+	const u8 *enc_key;
+	size_t enc_key_len;
+	const u8 *salt;
+	size_t pbkdf2_key_len;
+	size_t prf_hash_len;
+};
+
+
+static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
+				     struct dpp_enveloped_data *data)
+{
+	struct asn1_hdr hdr;
+	const u8 *end = pos + len;
+	const u8 *next, *e_end;
+	struct asn1_oid oid;
+	int val;
+	const u8 *params;
+	size_t params_len;
+
+	wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
+
+	/*
+	 * RecipientInfo ::= CHOICE {
+	 *    ktri		KeyTransRecipientInfo,
+	 *    kari	[1]	KeyAgreeRecipientInfo,
+	 *    kekri	[2]	KEKRecipientInfo,
+	 *    pwri	[3]	PasswordRecipientInfo,
+	 *    ori	[4]	OtherRecipientInfo}
+	 *
+	 * Shall always use the pwri CHOICE.
+	 */
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
+		    hdr.payload, hdr.length);
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/*
+	 * PasswordRecipientInfo ::= SEQUENCE {
+	 *    version			CMSVersion,
+	 *    keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+	 *    keyEncryptionAlgorithm	KeyEncryptionAlgorithmIdentifier,
+	 *    encryptedKey		EncryptedKey}
+	 *
+	 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+	 * parameters contains PBKDF2-params SEQUENCE.
+	 */
+
+	if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+		return -1;
+	pos = hdr.payload;
+
+	if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+		return -1;
+	if (val != 0) {
+		wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
+		    pos, end - pos);
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+	e_end = pos + hdr.length;
+
+	/* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
+	if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
+			    &next) < 0)
+		return -1;
+	if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
+		char buf[80];
+
+		asn1_oid_to_str(&oid, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
+			   buf);
+		return -1;
+	}
+
+	/*
+	 * PBKDF2-params ::= SEQUENCE {
+	 *    salt CHOICE {
+	 *       specified OCTET STRING,
+	 *       otherSource AlgorithmIdentifier}
+	 *    iterationCount INTEGER (1..MAX),
+	 *    keyLength INTEGER (1..MAX),
+	 *    prf AlgorithmIdentifier}
+	 *
+	 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+	 * on Configurator signing key length, prf is
+	 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+	 */
+	if (!params ||
+	    asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
+		return -1;
+	pos = hdr.payload;
+
+	if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_OCTETSTRING) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
+		    hdr.payload, hdr.length);
+	if (hdr.length != 64) {
+		wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
+			   hdr.length);
+		return -1;
+	}
+	data->salt = hdr.payload;
+	pos = hdr.payload + hdr.length;
+
+	if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+		return -1;
+	if (val != 1000) {
+		wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
+		return -1;
+	}
+
+	if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+		return -1;
+	if (val != 32 && val != 48 && val != 64) {
+		wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
+		return -1;
+	}
+	data->pbkdf2_key_len = val;
+
+	if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
+	    asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
+		wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
+		return -1;
+	}
+	if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
+		data->prf_hash_len = 32;
+	} else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
+		data->prf_hash_len = 48;
+	} else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
+		data->prf_hash_len = 64;
+	} else {
+		char buf[80];
+
+		asn1_oid_to_str(&oid, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
+			   buf);
+		return -1;
+	}
+
+	pos = next;
+
+	/* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
+	 *
+	 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+	 *
+	 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
+	 * id-alg-AES-SIV-CMAC-aed-512. */
+	if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+		return -1;
+	if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+	    !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+	    !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+		char buf[80];
+
+		asn1_oid_to_str(&oid, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
+			   buf);
+		return -1;
+	}
+
+	/*
+	 * encryptedKey EncryptedKey
+	 *
+	 * EncryptedKey ::= OCTET STRING
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_OCTETSTRING) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
+		    hdr.payload, hdr.length);
+	data->enc_key = hdr.payload;
+	data->enc_key_len = hdr.length;
+
+	return 0;
+}
+
+
+static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
+					    struct dpp_enveloped_data *data)
+{
+	struct asn1_hdr hdr;
+	struct asn1_oid oid;
+
+	/*
+	 * EncryptedContentInfo ::= SEQUENCE {
+	 *    contentType			ContentType,
+	 *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+	 *    encryptedContent	[0] IMPLICIT	EncryptedContent OPTIONAL}
+	 */
+	if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+		return -1;
+	wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
+		    hdr.payload, hdr.length);
+	if (pos < end) {
+		wpa_hexdump(MSG_DEBUG,
+			    "DPP: Unexpected extra data after EncryptedContentInfo",
+			    pos, end - pos);
+		return -1;
+	}
+
+	end = pos;
+	pos = hdr.payload;
+
+	/* ContentType ::= OBJECT IDENTIFIER */
+	if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
+		wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
+		return -1;
+	}
+	if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
+		char buf[80];
+
+		asn1_oid_to_str(&oid, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
+		return -1;
+	}
+
+	/* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+	if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+		return -1;
+	if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+	    !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+	    !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+		char buf[80];
+
+		asn1_oid_to_str(&oid, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
+			   buf);
+		return -1;
+	}
+	/* ignore optional parameters */
+
+	/* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+	 * EncryptedContent ::= OCTET STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
+		    hdr.payload, hdr.length);
+	data->enc_cont = hdr.payload;
+	data->enc_cont_len = hdr.length;
+	return 0;
+}
+
+
+static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
+				    struct dpp_enveloped_data *data)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	int val;
+
+	os_memset(data, 0, sizeof(*data));
+
+	/*
+	 * DPPEnvelopedData ::= EnvelopedData
+	 *
+	 * EnvelopedData ::= SEQUENCE {
+	 *    version			CMSVersion,
+	 *    originatorInfo	[0]	IMPLICIT OriginatorInfo OPTIONAL,
+	 *    recipientInfos		RecipientInfos,
+	 *    encryptedContentInfo	EncryptedContentInfo,
+	 *    unprotectedAttrs  [1] IMPLICIT	UnprotectedAttributes OPTIONAL}
+	 *
+	 * CMSVersion ::= INTEGER
+	 *
+	 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
+	 *
+	 * For DPP, version is 3, both originatorInfo and
+	 * unprotectedAttrs are omitted, and recipientInfos contains a single
+	 * RecipientInfo.
+	 */
+	if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
+		return -1;
+	pos = hdr.payload;
+	if (end < env_data + env_data_len) {
+		wpa_hexdump(MSG_DEBUG,
+			    "DPP: Unexpected extra data after DPPEnvelopedData",
+			    end, env_data + env_data_len - end);
+		return -1;
+	}
+
+	if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+		return -1;
+	if (val != 3) {
+		wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
+		return -1;
+	}
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
+		return -1;
+	return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
+						data);
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos = buf, *end = buf + len, *next;
+	int val;
+	const u8 *params;
+	size_t params_len;
+	struct asn1_oid oid;
+	char txt[80];
+	struct dpp_asymmetric_key *key;
+	EC_KEY *eckey;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
+
+	key = os_zalloc(sizeof(*key));
+	if (!key)
+		return NULL;
+
+	/*
+	 * OneAsymmetricKey ::= SEQUENCE {
+	 *    version			Version,
+	 *    privateKeyAlgorithm	PrivateKeyAlgorithmIdentifier,
+	 *    privateKey		PrivateKey,
+	 *    attributes		[0] Attributes OPTIONAL,
+	 *    ...,
+	 *    [[2: publicKey		[1] BIT STRING OPTIONAL ]],
+	 *    ...
+	 * }
+	 */
+	if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+		goto fail;
+	pos = hdr.payload;
+
+	/* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
+	if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+		goto fail;
+	if (val != 1) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
+			   val);
+		goto fail;
+	}
+
+	/* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
+	if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
+			    &pos) < 0)
+		goto fail;
+	if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
+		asn1_oid_to_str(&oid, txt, sizeof(txt));
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
+			   txt);
+		goto fail;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
+		    params, params_len);
+	/*
+	 * ECParameters ::= CHOICE {
+	 *    namedCurve	OBJECT IDENTIFIER
+	 *    -- implicitCurve	NULL
+	 *    -- specifiedCurve	SpecifiedECDomain}
+	 */
+	if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Could not parse ECParameters.namedCurve");
+		goto fail;
+	}
+	asn1_oid_to_str(&oid, txt, sizeof(txt));
+	wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
+	/* Assume the curve is identified within ECPrivateKey, so that this
+	 * separate indication is not really needed. */
+
+	/*
+	 * PrivateKey ::= OCTET STRING
+	 *    (Contains DER encoding of ECPrivateKey)
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_OCTETSTRING) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		goto fail;
+	}
+	wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
+			hdr.payload, hdr.length);
+	pos = hdr.payload + hdr.length;
+	eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+	if (!eckey) {
+		wpa_printf(MSG_INFO,
+			   "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto fail;
+	}
+	key->csign = EVP_PKEY_new();
+	if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
+		EC_KEY_free(eckey);
+		goto fail;
+	}
+	if (wpa_debug_show_keys)
+		dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
+
+	/*
+	 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+	 *
+	 * Exactly one instance of type Attribute in OneAsymmetricKey.
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected [0] Attributes - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		goto fail;
+	}
+	wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
+			hdr.payload, hdr.length);
+	if (hdr.payload + hdr.length < end) {
+		wpa_hexdump_key(MSG_MSGDUMP,
+				"DPP: Ignore additional data at the end of OneAsymmetricKey",
+				hdr.payload + hdr.length,
+				end - (hdr.payload + hdr.length));
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		goto fail;
+	}
+	if (hdr.payload + hdr.length < end) {
+		wpa_hexdump_key(MSG_MSGDUMP,
+				"DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
+				hdr.payload + hdr.length,
+				end - (hdr.payload + hdr.length));
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/*
+	 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
+	 *    aa-DPPConfigurationParameters,
+	 *    ... -- For local profiles
+	 * }
+	 *
+	 * aa-DPPConfigurationParameters ATTRIBUTE ::=
+	 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+	 *
+	 * Attribute ::= SEQUENCE {
+	 *    type OBJECT IDENTIFIER,
+	 *    values SET SIZE(1..MAX) OF Type
+	 *
+	 * Exactly one instance of ATTRIBUTE in attrValues.
+	 */
+	if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+		goto fail;
+	if (pos < end) {
+		wpa_hexdump_key(MSG_MSGDUMP,
+				"DPP: Ignore additional data at the end of ATTRIBUTE",
+				pos, end - pos);
+	}
+	end = pos;
+	pos = hdr.payload;
+
+	if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
+		goto fail;
+	if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
+		asn1_oid_to_str(&oid, txt, sizeof(txt));
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Unexpected Attribute identifier %s", txt);
+		goto fail;
+	}
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		goto fail;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/*
+	 * DPPConfigurationParameters ::= SEQUENCE {
+	 *    configurationTemplate	UTF8String,
+	 *    connectorTemplate		UTF8String OPTIONAL}
+	 */
+
+	wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
+			pos, end - pos);
+	if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+		goto fail;
+	if (pos < end) {
+		wpa_hexdump_key(MSG_MSGDUMP,
+				"DPP: Ignore additional data after DPPConfigurationParameters",
+				pos, end - pos);
+	}
+	end = pos;
+	pos = hdr.payload;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_UTF8STRING) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		goto fail;
+	}
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
+			      hdr.payload, hdr.length);
+	key->config_template = os_zalloc(hdr.length + 1);
+	if (!key->config_template)
+		goto fail;
+	os_memcpy(key->config_template, hdr.payload, hdr.length);
+
+	pos = hdr.payload + hdr.length;
+
+	if (pos < end) {
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_UNIVERSAL ||
+		    hdr.tag != ASN1_TAG_UTF8STRING) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
+				   hdr.class, hdr.tag);
+			goto fail;
+		}
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
+				      hdr.payload, hdr.length);
+		key->connector_template = os_zalloc(hdr.length + 1);
+		if (!key->connector_template)
+			goto fail;
+		os_memcpy(key->connector_template, hdr.payload, hdr.length);
+	}
+
+	return key;
+fail:
+	wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
+	dpp_free_asymmetric_key(key);
+	return NULL;
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
+	struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+			key_pkg, key_pkg_len);
+
+	/*
+	 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+	 *
+	 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+	 */
+	while (pos < end) {
+		if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
+		    !(key = dpp_parse_one_asymmetric_key(hdr.payload,
+							 hdr.length))) {
+			dpp_free_asymmetric_key(first);
+			return NULL;
+		}
+		if (!last) {
+			first = last = key;
+		} else {
+			last->next = key;
+			last = key;
+		}
+	}
+
+	return first;
+}
+
+
+static int dpp_conf_resp_env_data(struct dpp_authentication *auth,
+				  const u8 *env_data, size_t env_data_len)
+{
+	const u8 *key;
+	size_t key_len;
+	u8 kek[DPP_MAX_HASH_LEN];
+	u8 cont_encr_key[DPP_MAX_HASH_LEN];
+	size_t cont_encr_key_len;
+	int res;
+	u8 *key_pkg;
+	size_t key_pkg_len;
+	struct dpp_enveloped_data data;
+	struct dpp_asymmetric_key *keys;
+
+	wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
+
+	if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
+		return -1;
+
+	/* TODO: For initial testing, use ke as the key. Replace this with a
+	 * new key once that has been defined. */
+	key = auth->ke;
+	key_len = auth->curve->hash_len;
+	wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+	if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
+		       kek, data.pbkdf2_key_len)) {
+		wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+			kek, data.pbkdf2_key_len);
+
+	if (data.enc_key_len < AES_BLOCK_SIZE ||
+	    data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
+		wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
+		return -1;
+	}
+	res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
+			      data.enc_key, data.enc_key_len,
+			      0, NULL, NULL, cont_encr_key);
+	forced_memzero(kek, data.pbkdf2_key_len);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: AES-SIV decryption of encryptedKey failed");
+		return -1;
+	}
+	cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
+	wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
+			cont_encr_key, cont_encr_key_len);
+
+	if (data.enc_cont_len < AES_BLOCK_SIZE)
+		return -1;
+	key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
+	key_pkg = os_malloc(key_pkg_len);
+	if (!key_pkg)
+		return -1;
+	res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
+			      data.enc_cont, data.enc_cont_len,
+			      0, NULL, NULL, key_pkg);
+	forced_memzero(cont_encr_key, cont_encr_key_len);
+	if (res < 0) {
+		bin_clear_free(key_pkg, key_pkg_len);
+		wpa_printf(MSG_DEBUG,
+			   "DPP: AES-SIV decryption of encryptedContent failed");
+		return -1;
+	}
+
+	keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
+	bin_clear_free(key_pkg, key_pkg_len);
+	dpp_free_asymmetric_key(auth->conf_key_pkg);
+	auth->conf_key_pkg = keys;
+
+	return keys != NULL;;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
 int dpp_conf_resp_rx(struct dpp_authentication *auth,
 		     const struct wpabuf *resp)
 {
 	const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
 	u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
+	const u8 *env_data;
+	u16 env_data_len;
 	const u8 *addr[1];
 	size_t len[1];
 	u8 *unwrapped = NULL;
@@ -6348,9 +7749,17 @@
 		goto fail;
 	}
 
+	env_data = dpp_get_attr(unwrapped, unwrapped_len,
+				DPP_ATTR_ENVELOPED_DATA, &env_data_len);
+#ifdef CONFIG_DPP2
+	if (env_data &&
+	    dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
+		goto fail;
+#endif /* CONFIG_DPP2 */
+
 	conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
 				&conf_obj_len);
-	if (!conf_obj) {
+	if (!conf_obj && !env_data) {
 		dpp_auth_fail(auth,
 			      "Missing required Configuration Object attribute");
 		goto fail;
@@ -6770,15 +8179,41 @@
 }
 
 
+static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
+{
+	struct wpabuf *csign_pub = NULL;
+	u8 kid_hash[SHA256_MAC_LEN];
+	const u8 *addr[1];
+	size_t len[1];
+	int res;
+
+	csign_pub = dpp_get_pubkey_point(conf->csign, 1);
+	if (!csign_pub) {
+		wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
+		return -1;
+	}
+
+	/* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
+	addr[0] = wpabuf_head(csign_pub);
+	len[0] = wpabuf_len(csign_pub);
+	res = sha256_vector(1, addr, len, kid_hash);
+	wpabuf_free(csign_pub);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Failed to derive kid for C-sign-key");
+		return -1;
+	}
+
+	conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
+	return conf->kid ? 0 : -1;
+}
+
+
 struct dpp_configurator *
 dpp_keygen_configurator(const char *curve, const u8 *privkey,
 			size_t privkey_len)
 {
 	struct dpp_configurator *conf;
-	struct wpabuf *csign_pub = NULL;
-	u8 kid_hash[SHA256_MAC_LEN];
-	const u8 *addr[1];
-	size_t len[1];
 
 	conf = os_zalloc(sizeof(*conf));
 	if (!conf)
@@ -6804,31 +8239,12 @@
 		goto fail;
 	conf->own = 1;
 
-	csign_pub = dpp_get_pubkey_point(conf->csign, 1);
-	if (!csign_pub) {
-		wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
+	if (dpp_configurator_gen_kid(conf) < 0)
 		goto fail;
-	}
-
-	/* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
-	addr[0] = wpabuf_head(csign_pub);
-	len[0] = wpabuf_len(csign_pub);
-	if (sha256_vector(1, addr, len, kid_hash) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Failed to derive kid for C-sign-key");
-		goto fail;
-	}
-
-	conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
-	if (!conf->kid)
-		goto fail;
-out:
-	wpabuf_free(csign_pub);
 	return conf;
 fail:
 	dpp_configurator_free(conf);
-	conf = NULL;
-	goto out;
+	return NULL;
 }
 
 
@@ -8956,6 +10372,10 @@
 		if (id && bi->id != id)
 			continue;
 		found = 1;
+#ifdef CONFIG_DPP2
+		if (dpp->remove_bi)
+			dpp->remove_bi(dpp->cb_ctx, bi);
+#endif /* CONFIG_DPP2 */
 		dl_list_del(&bi->list);
 		dpp_bootstrap_info_free(bi);
 	}
@@ -9006,11 +10426,10 @@
 
 int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
 {
-	char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
+	char *mac = NULL, *info = NULL, *curve = NULL;
 	char *key = NULL;
 	u8 *privkey = NULL;
 	size_t privkey_len = 0;
-	size_t len;
 	int ret = -1;
 	struct dpp_bootstrap_info *bi;
 
@@ -9030,7 +10449,7 @@
 	else
 		goto fail;
 
-	chan = get_param(cmd, " chan=");
+	bi->chan = get_param(cmd, " chan=");
 	mac = get_param(cmd, " mac=");
 	info = get_param(cmd, " info=");
 	curve = get_param(cmd, " curve=");
@@ -9044,43 +10463,19 @@
 			goto fail;
 	}
 
-	pk = dpp_keygen(bi, curve, privkey, privkey_len);
-	if (!pk)
+	if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
+	    dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
+	    dpp_parse_uri_mac(bi, mac) < 0 ||
+	    dpp_parse_uri_info(bi, info) < 0 ||
+	    dpp_gen_uri(bi) < 0)
 		goto fail;
 
-	len = 4; /* "DPP:" */
-	if (chan) {
-		if (dpp_parse_uri_chan_list(bi, chan) < 0)
-			goto fail;
-		len += 3 + os_strlen(chan); /* C:...; */
-	}
-	if (mac) {
-		if (dpp_parse_uri_mac(bi, mac) < 0)
-			goto fail;
-		len += 3 + os_strlen(mac); /* M:...; */
-	}
-	if (info) {
-		if (dpp_parse_uri_info(bi, info) < 0)
-			goto fail;
-		len += 3 + os_strlen(info); /* I:...; */
-	}
-	len += 4 + os_strlen(pk);
-	bi->uri = os_malloc(len + 1);
-	if (!bi->uri)
-		goto fail;
-	os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
-		    chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
-		    mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
-		    info ? "I:" : "", info ? info : "", info ? ";" : "",
-		    pk);
 	bi->id = dpp_next_id(dpp);
 	dl_list_add(&dpp->bootstrap, &bi->list);
 	ret = bi->id;
 	bi = NULL;
 fail:
 	os_free(curve);
-	os_free(pk);
-	os_free(chan);
 	os_free(mac);
 	os_free(info);
 	str_clear_free(key);
@@ -9175,17 +10570,39 @@
 			   "mac_addr=" MACSTR "\n"
 			   "info=%s\n"
 			   "num_freq=%u\n"
+			   "use_freq=%u\n"
 			   "curve=%s\n"
 			   "pkhash=%s\n",
 			   dpp_bootstrap_type_txt(bi->type),
 			   MAC2STR(bi->mac_addr),
 			   bi->info ? bi->info : "",
 			   bi->num_freq,
+			   bi->num_freq == 1 ? bi->freq[0] : 0,
 			   bi->curve->name,
 			   pkhash);
 }
 
 
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
+{
+	struct dpp_bootstrap_info *bi;
+
+	bi = dpp_bootstrap_get_id(dpp, id);
+	if (!bi)
+		return -1;
+
+	str_clear_free(bi->configurator_params);
+
+	if (params) {
+		bi->configurator_params = os_strdup(params);
+		return bi->configurator_params ? 0 : -1;
+	}
+
+	bi->configurator_params = NULL;
+	return 0;
+}
+
+
 void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
 			     const u8 *r_bootstrap,
 			     struct dpp_bootstrap_info **own_bi,
@@ -9218,7 +10635,108 @@
 		if (*own_bi && *peer_bi)
 			break;
 	}
+}
 
+
+#ifdef CONFIG_DPP2
+struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+						     const u8 *hash)
+{
+	struct dpp_bootstrap_info *bi;
+
+	if (!dpp)
+		return NULL;
+
+	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+		if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
+					  SHA256_MAC_LEN) == 0)
+			return bi;
+	}
+
+	return NULL;
+}
+#endif /* CONFIG_DPP2 */
+
+
+static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
+				     struct dpp_bootstrap_info *peer_bi)
+{
+	unsigned int i, freq = 0;
+	enum hostapd_hw_mode mode;
+	u8 op_class, channel;
+	char chan[20];
+
+	if (peer_bi->num_freq == 0)
+		return 0; /* no channel preference/constraint */
+
+	for (i = 0; i < peer_bi->num_freq; i++) {
+		if (own_bi->num_freq == 0 ||
+		    freq_included(own_bi->freq, own_bi->num_freq,
+				  peer_bi->freq[i])) {
+			freq = peer_bi->freq[i];
+			break;
+		}
+	}
+	if (!freq) {
+		wpa_printf(MSG_DEBUG, "DPP: No common channel found");
+		return -1;
+	}
+
+	mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
+	if (mode == NUM_HOSTAPD_MODES) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Could not determine operating class or channel number for %u MHz",
+			   freq);
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
+		   freq, op_class, channel);
+	os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
+	os_free(own_bi->chan);
+	own_bi->chan = os_strdup(chan);
+	own_bi->freq[0] = freq;
+	own_bi->num_freq = 1;
+	os_free(peer_bi->chan);
+	peer_bi->chan = os_strdup(chan);
+	peer_bi->freq[0] = freq;
+	peer_bi->num_freq = 1;
+
+	return dpp_gen_uri(own_bi);
+}
+
+
+static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
+				 struct dpp_bootstrap_info *peer_bi)
+{
+	if (peer_bi->curve == own_bi->curve)
+		return 0;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Update own bootstrapping key to match peer curve from NFC handover");
+
+	EVP_PKEY_free(own_bi->pubkey);
+	own_bi->pubkey = NULL;
+
+	if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
+	    dpp_gen_uri(own_bi) < 0)
+		goto fail;
+
+	return 0;
+fail:
+	dl_list_del(&own_bi->list);
+	dpp_bootstrap_info_free(own_bi);
+	return -1;
+}
+
+
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+		      struct dpp_bootstrap_info *peer_bi)
+{
+	if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
+	    dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
+		return -1;
+	return 0;
 }
 
 
@@ -9327,6 +10845,48 @@
 
 #ifdef CONFIG_DPP2
 
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+				 struct dpp_asymmetric_key *key)
+{
+	struct dpp_configurator *conf;
+	const EC_KEY *eckey;
+	const EC_GROUP *group;
+	int nid;
+	const struct dpp_curve_params *curve;
+
+	if (!key->csign)
+		return -1;
+	eckey = EVP_PKEY_get0_EC_KEY(key->csign);
+	if (!eckey)
+		return -1;
+	group = EC_KEY_get0_group(eckey);
+	if (!group)
+		return -1;
+	nid = EC_GROUP_get_curve_name(group);
+	curve = dpp_get_curve_nid(nid);
+	if (!curve) {
+		wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
+		return -1;
+	}
+
+	conf = os_zalloc(sizeof(*conf));
+	if (!conf)
+		return -1;
+	conf->curve = curve;
+	conf->csign = key->csign;
+	key->csign = NULL;
+	conf->own = 1;
+	if (dpp_configurator_gen_kid(conf) < 0) {
+		dpp_configurator_free(conf);
+		return -1;
+	}
+
+	conf->id = dpp_next_configurator_id(dpp);
+	dl_list_add(&dpp->configurator, &conf->list);
+	return conf->id;
+}
+
+
 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
 							   void *timeout_ctx);
 
@@ -9405,6 +10965,7 @@
 #ifdef CONFIG_DPP2
 	dpp->cb_ctx = config->cb_ctx;
 	dpp->process_conf_obj = config->process_conf_obj;
+	dpp->remove_bi = config->remove_bi;
 #endif /* CONFIG_DPP2 */
 
 	dl_list_init(&dpp->bootstrap);
@@ -9561,6 +11122,32 @@
 }
 
 
+static int dpp_tcp_send_msg(struct dpp_connection *conn,
+			    const struct wpabuf *msg)
+{
+	wpabuf_free(conn->msg_out);
+	conn->msg_out_pos = 0;
+	conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
+	if (!conn->msg_out)
+		return -1;
+	wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
+	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
+			wpabuf_len(msg) - 1);
+
+	if (dpp_tcp_send(conn) == 1) {
+		if (!conn->write_eloop) {
+			if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+						dpp_conn_tx_ready,
+						conn, NULL) < 0)
+				return -1;
+			conn->write_eloop = 1;
+		}
+	}
+
+	return 0;
+}
+
+
 static void dpp_controller_start_gas_client(struct dpp_connection *conn)
 {
 	struct dpp_authentication *auth = conn->auth;
@@ -9574,27 +11161,8 @@
 		return;
 	}
 
-	wpabuf_free(conn->msg_out);
-	conn->msg_out_pos = 0;
-	conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1);
-	if (!conn->msg_out) {
-		wpabuf_free(buf);
-		return;
-	}
-	wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
-	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
-			wpabuf_len(buf) - 1);
+	dpp_tcp_send_msg(conn, buf);
 	wpabuf_free(buf);
-
-	if (dpp_tcp_send(conn) == 1) {
-		if (!conn->write_eloop) {
-			if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
-						dpp_conn_tx_ready,
-						conn, NULL) < 0)
-				return;
-			conn->write_eloop = 1;
-		}
-	}
 }
 
 
@@ -9793,7 +11361,8 @@
 	 * continue that session (send this over TCP) and return 0.
 	 */
 	if (type != DPP_PA_PEER_DISCOVERY_REQ &&
-	    type != DPP_PA_PEER_DISCOVERY_RESP) {
+	    type != DPP_PA_PEER_DISCOVERY_RESP &&
+	    type != DPP_PA_PRESENCE_ANNOUNCEMENT) {
 		dl_list_for_each(ctrl, &dpp->controllers,
 				 struct dpp_relay_controller, list) {
 			dl_list_for_each(conn, &ctrl->conn,
@@ -9808,7 +11377,14 @@
 	if (!r_bootstrap)
 		return -1;
 
-	ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
+	if (type == DPP_PA_PRESENCE_ANNOUNCEMENT) {
+		/* TODO: Could send this to all configured Controllers. For now,
+		 * only the first Controller is supported. */
+		ctrl = dl_list_first(&dpp->controllers,
+				     struct dpp_relay_controller, list);
+	} else {
+		ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
+	}
 	if (!ctrl)
 		return -1;
 
@@ -9940,7 +11516,8 @@
 		return 0;
 	}
 
-	conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx,
+	conn->auth = dpp_auth_req_rx(conn->ctrl->global,
+				     conn->ctrl->global->msg_ctx,
 				     conn->ctrl->allowed_roles,
 				     conn->ctrl->qr_mutual,
 				     peer_bi, own_bi, -1, hdr, buf, len);
@@ -9949,33 +11526,13 @@
 		return -1;
 	}
 
-	if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx,
-				 conn->auth,
+	if (dpp_set_configurator(conn->auth,
 				 conn->ctrl->configurator_params) < 0) {
 		dpp_connection_remove(conn);
 		return -1;
 	}
 
-	wpabuf_free(conn->msg_out);
-	conn->msg_out_pos = 0;
-	conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1);
-	if (!conn->msg_out)
-		return -1;
-	wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
-	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
-			wpabuf_len(conn->auth->resp_msg) - 1);
-
-	if (dpp_tcp_send(conn) == 1) {
-		if (!conn->write_eloop) {
-			if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
-						dpp_conn_tx_ready,
-						conn, NULL) < 0)
-				return -1;
-			conn->write_eloop = 1;
-		}
-	}
-
-	return 0;
+	return dpp_tcp_send_msg(conn, conn->auth->resp_msg);
 }
 
 
@@ -9984,6 +11541,7 @@
 {
 	struct dpp_authentication *auth = conn->auth;
 	struct wpabuf *msg;
+	int res;
 
 	if (!auth)
 		return -1;
@@ -10002,30 +11560,10 @@
 		return -1;
 	}
 
-	wpabuf_free(conn->msg_out);
-	conn->msg_out_pos = 0;
-	conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
-	if (!conn->msg_out) {
-		wpabuf_free(msg);
-		return -1;
-	}
-	wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
-	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
-			wpabuf_len(msg) - 1);
-	wpabuf_free(msg);
-
 	conn->on_tcp_tx_complete_auth_ok = 1;
-	if (dpp_tcp_send(conn) == 1) {
-		if (!conn->write_eloop) {
-			if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
-						dpp_conn_tx_ready,
-						conn, NULL) < 0)
-				return -1;
-			conn->write_eloop = 1;
-		}
-	}
-
-	return 0;
+	res = dpp_tcp_send_msg(conn, msg);
+	wpabuf_free(msg);
+	return res;
 }
 
 
@@ -10142,6 +11680,56 @@
 }
 
 
+static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
+						   const u8 *hdr, const u8 *buf,
+						   size_t len)
+{
+	const u8 *r_bootstrap;
+	u16 r_bootstrap_len;
+	struct dpp_bootstrap_info *peer_bi;
+	struct dpp_authentication *auth;
+	struct dpp_global *dpp = conn->ctrl->global;
+
+	if (conn->auth) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Ignore Presence Announcement during ongoing Authentication");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "DPP: Presence Announcement");
+
+	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+				   &r_bootstrap_len);
+	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+		wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+		    r_bootstrap, r_bootstrap_len);
+	peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap);
+	if (!peer_bi) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No matching bootstrapping information found");
+		return -1;
+	}
+
+	auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL,
+			     DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
+	if (!auth)
+		return -1;
+	if (dpp_set_configurator(conn->auth,
+				 conn->ctrl->configurator_params) < 0) {
+		dpp_auth_deinit(auth);
+		dpp_connection_remove(conn);
+		return -1;
+	}
+
+	conn->auth = auth;
+	return dpp_tcp_send_msg(conn, conn->auth->req_msg);
+}
+
+
 static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
 				    size_t len)
 {
@@ -10192,6 +11780,9 @@
 	case DPP_PA_CONNECTION_STATUS_RESULT:
 		return dpp_controller_rx_conn_status_result(conn, msg, pos,
 							    end - pos);
+	case DPP_PA_PRESENCE_ANNOUNCEMENT:
+		return dpp_controller_rx_presence_announcement(conn, msg, pos,
+							       end - pos);
 	default:
 		/* TODO: missing messages types */
 		wpa_printf(MSG_DEBUG,
@@ -10286,7 +11877,7 @@
 {
 	struct dpp_authentication *auth = conn->auth;
 	int res;
-	struct wpabuf *msg, *encaps;
+	struct wpabuf *msg;
 	enum dpp_status_error status;
 
 	wpa_printf(MSG_DEBUG,
@@ -10308,35 +11899,19 @@
 	if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
 		return -1;
 
-#ifdef CONFIG_DPP2
 	wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
 	status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
 	msg = dpp_build_conf_result(auth, status);
 	if (!msg)
 		return -1;
 
-	encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
-	if (!encaps) {
-		wpabuf_free(msg);
-		return -1;
-	}
-	wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
-	wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
-	wpabuf_free(msg);
-	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
-
-	wpabuf_free(conn->msg_out);
-	conn->msg_out_pos = 0;
-	conn->msg_out = encaps;
 	conn->on_tcp_tx_complete_remove = 1;
-	dpp_tcp_send(conn);
+	res = dpp_tcp_send_msg(conn, msg);
+	wpabuf_free(msg);
 
 	/* This exchange will be terminated in the TX status handler */
 
-	return 0;
-#else /* CONFIG_DPP2 */
-	return -1;
-#endif /* CONFIG_DPP2 */
+	return res;
 }
 
 
@@ -10721,4 +12296,22 @@
 	}
 }
 
+
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
+
+	msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
+	if (!msg)
+		return NULL;
+
+	/* Responder Bootstrapping Key Hash */
+	dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
+	wpa_hexdump_buf(MSG_DEBUG,
+			"DPP: Presence Announcement frame attributes", msg);
+	return msg;
+}
+
 #endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index cb788ae..ab3f927 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -1,7 +1,7 @@
 /*
  * DPP functionality shared between hostapd and wpa_supplicant
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -36,6 +36,11 @@
 	DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
 	DPP_PA_CONFIGURATION_RESULT = 11,
 	DPP_PA_CONNECTION_STATUS_RESULT = 12,
+	DPP_PA_PRESENCE_ANNOUNCEMENT = 13,
+	DPP_PA_RECONFIG_ANNOUNCEMENT = 14,
+	DPP_PA_RECONFIG_AUTH_REQ = 15,
+	DPP_PA_RECONFIG_AUTH_RESP = 16,
+	DPP_PA_RECONFIG_AUTH_CONF = 17,
 };
 
 enum dpp_attribute_id {
@@ -67,6 +72,9 @@
 	DPP_ATTR_ENVELOPED_DATA = 0x101A,
 	DPP_ATTR_SEND_CONN_STATUS = 0x101B,
 	DPP_ATTR_CONN_STATUS = 0x101C,
+	DPP_ATTR_RECONFIG_FLAGS = 0x101D,
+	DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
+	DPP_ATTR_CSR_ATTR_REQ = 0x101F,
 };
 
 enum dpp_status_error {
@@ -81,6 +89,9 @@
 	DPP_STATUS_NO_MATCH = 8,
 	DPP_STATUS_CONFIG_REJECTED = 9,
 	DPP_STATUS_NO_AP = 10,
+	DPP_STATUS_CONFIGURE_PENDING = 11,
+	DPP_STATUS_CSR_NEEDED = 12,
+	DPP_STATUS_CSR_BAD = 13,
 };
 
 #define DPP_CAPAB_ENROLLEE BIT(0)
@@ -115,15 +126,19 @@
 	enum dpp_bootstrap_type type;
 	char *uri;
 	u8 mac_addr[ETH_ALEN];
+	char *chan;
 	char *info;
+	char *pk;
 	unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
 	unsigned int num_freq;
 	int own;
 	EVP_PKEY *pubkey;
 	u8 pubkey_hash[SHA256_MAC_LEN];
+	u8 pubkey_hash_chirp[SHA256_MAC_LEN];
 	const struct dpp_curve_params *curve;
 	unsigned int pkex_t; /* number of failures before dpp_pkex
 			      * instantiation */
+	char *configurator_params;
 };
 
 #define PKEX_COUNTER_T_LIMIT 5
@@ -187,10 +202,18 @@
 	int psk_set;
 };
 
+struct dpp_asymmetric_key {
+	struct dpp_asymmetric_key *next;
+	EVP_PKEY *csign;
+	char *config_template;
+	char *connector_template;
+};
+
 #define DPP_MAX_CONF_OBJ 10
 #define DPP_MAX_CHANNELS 32
 
 struct dpp_authentication {
+	struct dpp_global *global;
 	void *msg_ctx;
 	u8 peer_version;
 	const struct dpp_curve_params *curve;
@@ -246,6 +269,7 @@
 	struct dpp_configuration *conf2_ap;
 	struct dpp_configuration *conf_sta;
 	struct dpp_configuration *conf2_sta;
+	int provision_configurator;
 	struct dpp_configurator *conf;
 	struct dpp_config_obj {
 		char *connector; /* received signedConnector */
@@ -259,11 +283,13 @@
 		struct wpabuf *c_sign_key;
 	} conf_obj[DPP_MAX_CONF_OBJ];
 	unsigned int num_conf_obj;
+	struct dpp_asymmetric_key *conf_key_pkg;
 	struct wpabuf *net_access_key;
 	os_time_t net_access_key_expiry;
 	int send_conn_status;
 	int conn_status_requested;
 	int akm_use_selector;
+	int configurator_set;
 #ifdef CONFIG_TESTING_OPTIONS
 	char *config_obj_override;
 	char *discovery_override;
@@ -414,15 +440,16 @@
 
 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
 			    const char *chan_list);
 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
-		  const u8 *privkey, size_t privkey_len);
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+		      struct dpp_bootstrap_info *peer_bi);
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx);
 struct hostapd_hw_modes;
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
 					  struct dpp_bootstrap_info *peer_bi,
 					  struct dpp_bootstrap_info *own_bi,
 					  u8 dpp_allowed_roles,
@@ -430,8 +457,8 @@
 					  struct hostapd_hw_modes *own_modes,
 					  u16 num_modes);
 struct dpp_authentication *
-dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
-		struct dpp_bootstrap_info *peer_bi,
+dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
+			int qr_mutual, struct dpp_bootstrap_info *peer_bi,
 		struct dpp_bootstrap_info *own_bi,
 		unsigned int freq, const u8 *hdr, const u8 *attr_start,
 		size_t attr_len);
@@ -456,9 +483,7 @@
 int dpp_akm_ver2(enum dpp_akm akm);
 int dpp_configuration_valid(const struct dpp_configuration *conf);
 void dpp_configuration_free(struct dpp_configuration *conf);
-int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
-			 struct dpp_authentication *auth,
-			 const char *cmd);
+int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
 void dpp_auth_deinit(struct dpp_authentication *auth);
 struct wpabuf *
 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
@@ -551,14 +576,19 @@
 const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
 int dpp_bootstrap_info(struct dpp_global *dpp, int id,
 		       char *reply, int reply_size);
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params);
 void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
 			     const u8 *r_bootstrap,
 			     struct dpp_bootstrap_info **own_bi,
 			     struct dpp_bootstrap_info **peer_bi);
+struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+						     const u8 *hash);
 int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
 int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
 int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
 				char *buf, size_t buflen);
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+				 struct dpp_asymmetric_key *key);
 int dpp_relay_add_controller(struct dpp_global *dpp,
 			     struct dpp_relay_config *config);
 int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
@@ -571,11 +601,13 @@
 void dpp_controller_stop(struct dpp_global *dpp);
 int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
 		 const struct hostapd_ip_addr *addr, int port);
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
 
 struct dpp_global_config {
 	void *msg_ctx;
 	void *cb_ctx;
 	int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+	void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
 };
 
 struct dpp_global * dpp_global_init(struct dpp_global_config *config);
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 19593a5..f6c67a3 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -468,14 +468,74 @@
 			data->bandwidth = (1 << (u8) bw) * 20;
 			data->center_freq1 = freq1;
 			data->center_freq2 = freq2;
-			data->ht_enabled = 0;
-			data->vht_enabled = 0;
 		}
+		data->ht_enabled = 0;
+		data->vht_enabled = 0;
 
 		return 0;
 	}
 
-	if (data->vht_enabled) switch (oper_chwidth) {
+	if (data->he_enabled) switch (oper_chwidth) {
+	case CHANWIDTH_USE_HT:
+		if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
+			if (!(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");
+				return -1;
+			}
+			break;
+		}
+		/* fall through */
+	case CHANWIDTH_80MHZ:
+		if (mode == HOSTAPD_MODE_IEEE80211A) {
+			if (!(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");
+				return -1;
+			}
+		}
+		break;
+	case CHANWIDTH_80P80MHZ:
+		if (!(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] &
+		      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:
+		break;
+	case CHANWIDTH_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:
+		break;
+	case CHANWIDTH_160MHZ:
+		if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+				  VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+			wpa_printf(MSG_ERROR,
+				   "160 MHz channel width is not supported!");
+			return -1;
+		}
+		break;
+	}
+
+	if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
 	case CHANWIDTH_USE_HT:
 		if (center_segment1 ||
 		    (center_segment0 != 0 &&
@@ -484,11 +544,6 @@
 			return -1;
 		break;
 	case CHANWIDTH_80P80MHZ:
-		if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
-			wpa_printf(MSG_ERROR,
-				   "80+80 channel width is not supported!");
-			return -1;
-		}
 		if (center_segment1 == center_segment0 + 4 ||
 		    center_segment1 == center_segment0 - 4)
 			return -1;
@@ -533,12 +588,6 @@
 		break;
 	case CHANWIDTH_160MHZ:
 		data->bandwidth = 160;
-		if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
-				  VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
-			wpa_printf(MSG_ERROR,
-				   "160MHZ channel width is not supported!");
-			return -1;
-		}
 		if (center_segment1)
 			return -1;
 		if (!sec_channel_offset)
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index b330454..42c916b 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -130,6 +130,12 @@
 			elems->multi_ap = pos;
 			elems->multi_ap_len = elen;
 			break;
+		case OWE_OUI_TYPE:
+			/* OWE Transition Mode element */
+			break;
+		case DPP_CC_OUI_TYPE:
+			/* DPP Configurator Connectivity element */
+			break;
 		default:
 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
 				   "information element ignored "
@@ -206,6 +212,8 @@
 	ext_id = *pos++;
 	elen--;
 
+	elems->frag_ies.last_eid_ext = 0;
+
 	switch (ext_id) {
 	case WLAN_EID_EXT_ASSOC_DELAY_INFO:
 		if (elen != 1)
@@ -245,9 +253,9 @@
 		elems->key_delivery = pos;
 		elems->key_delivery_len = elen;
 		break;
-	case WLAN_EID_EXT_FILS_WRAPPED_DATA:
-		elems->fils_wrapped_data = pos;
-		elems->fils_wrapped_data_len = elen;
+	case WLAN_EID_EXT_WRAPPED_DATA:
+		elems->wrapped_data = pos;
+		elems->wrapped_data_len = elen;
 		break;
 	case WLAN_EID_EXT_FILS_PUBLIC_KEY:
 		if (elen < 1)
@@ -286,6 +294,10 @@
 		elems->oci = pos;
 		elems->oci_len = elen;
 		break;
+	case WLAN_EID_EXT_SHORT_SSID_LIST:
+		elems->short_ssid_list = pos;
+		elems->short_ssid_list_len = elen;
+		break;
 	default:
 		if (show_errors) {
 			wpa_printf(MSG_MSGDUMP,
@@ -295,10 +307,39 @@
 		return -1;
 	}
 
+	if (elen == 254)
+		elems->frag_ies.last_eid_ext = ext_id;
+
 	return 0;
 }
 
 
+static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
+				      const u8 *pos, u8 elen)
+{
+	if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
+		wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
+		return;
+	}
+
+	/*
+	 * Note: while EID == 0 is a valid ID (SSID IE), it should not be
+	 * fragmented.
+	 */
+	if (!frag_ies->last_eid) {
+		wpa_printf(MSG_MSGDUMP,
+			   "Fragment without a valid last element - skip");
+		return;
+	}
+
+	frag_ies->frags[frag_ies->n_frags].ie = pos;
+	frag_ies->frags[frag_ies->n_frags].ie_len = elen;
+	frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
+	frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
+	frag_ies->n_frags++;
+}
+
+
 /**
  * ieee802_11_parse_elems - Parse information elements in management frames
  * @start: Pointer to the start of IEs
@@ -331,6 +372,11 @@
 					   elen);
 				break;
 			}
+			if (elems->ssid) {
+				wpa_printf(MSG_MSGDUMP,
+					   "Ignored duplicated SSID element");
+				break;
+			}
 			elems->ssid = pos;
 			elems->ssid_len = elen;
 			break;
@@ -516,7 +562,7 @@
 			elems->dils_len = elen;
 			break;
 		case WLAN_EID_FRAGMENT:
-			/* TODO */
+			ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
 			break;
 		case WLAN_EID_EXTENSION:
 			if (ieee802_11_parse_extension(pos, elen, elems,
@@ -532,6 +578,12 @@
 				   id, elen);
 			break;
 		}
+
+		if (id != WLAN_EID_FRAGMENT && elen == 255)
+			elems->frag_ies.last_eid = id;
+
+		if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
+			elems->frag_ies.last_eid = 0;
 	}
 
 	if (!for_each_element_completed(elem, start, len)) {
@@ -2394,6 +2446,79 @@
 	return CHANWIDTH_USE_HT;
 }
 
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+				       u8 eid, u8 eid_ext,
+				       const u8 *data, u8 len)
+{
+	struct frag_ies_info *frag_ies = &elems->frag_ies;
+	struct wpabuf *buf;
+	unsigned int i;
+
+	if (!elems || !data || !len)
+		return NULL;
+
+	buf = wpabuf_alloc_copy(data, len);
+	if (!buf)
+		return NULL;
+
+	for (i = 0; i < frag_ies->n_frags; i++) {
+		int ret;
+
+		if (frag_ies->frags[i].eid != eid ||
+		    frag_ies->frags[i].eid_ext != eid_ext)
+			continue;
+
+		ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
+		if (ret < 0) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+
+		/* Copy only the fragment data (without the EID and length) */
+		wpabuf_put_data(buf, frag_ies->frags[i].ie,
+				frag_ies->frags[i].ie_len);
+	}
+
+	return buf;
+}
+
+
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+				  u8 eid, u8 eid_ext)
+{
+	const u8 *data;
+	u8 len;
+
+	/*
+	 * TODO: Defragmentation mechanism can be supported for all IEs. For now
+	 * handle only those that are used (or use ieee802_11_defrag_data()).
+	 */
+	switch (eid) {
+	case WLAN_EID_EXTENSION:
+		switch (eid_ext) {
+		case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+			data = elems->fils_hlp;
+			len = elems->fils_hlp_len;
+			break;
+		case WLAN_EID_EXT_WRAPPED_DATA:
+			data = elems->wrapped_data;
+			len = elems->wrapped_data_len;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG,
+				   "Defragmentation not supported. eid_ext=%u",
+				   eid_ext);
+			return NULL;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "Defragmentation not supported. eid=%u", eid);
+		return NULL;
+	}
+
+	return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
+}
 
 /* Parse HT capabilities to get maximum number of supported spatial streams */
 static int parse_ht_mcs_set_for_max_nss(
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2c66507..e395769 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -21,6 +21,7 @@
 struct hostapd_hw_modes;
 
 #define MAX_NOF_MB_IES_SUPPORTED 5
+#define MAX_NUM_FRAG_IES_SUPPORTED 3
 
 struct mb_ies_info {
 	struct {
@@ -30,6 +31,21 @@
 	u8 nof_ies;
 };
 
+struct frag_ies_info {
+	struct {
+		u8 eid;
+		u8 eid_ext;
+		const u8 *ie;
+		u8 ie_len;
+	} frags[MAX_NUM_FRAG_IES_SUPPORTED];
+
+	u8 n_frags;
+
+	/* the last parsed element ID and element extension ID */
+	u8 last_eid;
+	u8 last_eid_ext;
+};
+
 /* Parsed Information Elements */
 struct ieee802_11_elems {
 	const u8 *ssid;
@@ -85,7 +101,7 @@
 	const u8 *fils_hlp;
 	const u8 *fils_ip_addr_assign;
 	const u8 *key_delivery;
-	const u8 *fils_wrapped_data;
+	const u8 *wrapped_data;
 	const u8 *fils_pk;
 	const u8 *fils_nonce;
 	const u8 *owe_dh;
@@ -96,6 +112,7 @@
 	const u8 *multi_ap;
 	const u8 *he_capabilities;
 	const u8 *he_operation;
+	const u8 *short_ssid_list;
 
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -137,7 +154,7 @@
 	u8 fils_hlp_len;
 	u8 fils_ip_addr_assign_len;
 	u8 key_delivery_len;
-	u8 fils_wrapped_data_len;
+	u8 wrapped_data_len;
 	u8 fils_pk_len;
 	u8 owe_dh_len;
 	u8 power_capab_len;
@@ -147,8 +164,10 @@
 	u8 multi_ap_len;
 	u8 he_capabilities_len;
 	u8 he_operation_len;
+	u8 short_ssid_list_len;
 
 	struct mb_ies_info mb_ies;
+	struct frag_ies_info frag_ies;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -291,6 +310,12 @@
 int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
 			    struct ieee80211_edmg_config requested);
 
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+				       u8 eid, u8 eid_ext,
+				       const u8 *data, u8 len);
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+				  u8 eid, u8 eid_ext);
+
 int get_max_nss_capability(struct ieee802_11_elems *elems, int parse_for_rx);
 
 struct supported_chan_width {
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index fdc51dc..4a5eb16 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -458,7 +458,7 @@
 #define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
 #define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
 #define WLAN_EID_EXT_KEY_DELIVERY 7
-#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_WRAPPED_DATA 8
 #define WLAN_EID_EXT_FTM_SYNC_INFO 9
 #define WLAN_EID_EXT_EXTENDED_REQUEST 10
 #define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
@@ -472,9 +472,11 @@
 #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
 #define WLAN_EID_EXT_SPATIAL_REUSE 39
 #define WLAN_EID_EXT_OCV_OCI 54
+#define WLAN_EID_EXT_SHORT_SSID_LIST 58
 #define WLAN_EID_EXT_EDMG_CAPABILITIES 61
 #define WLAN_EID_EXT_EDMG_OPERATION 62
 #define WLAN_EID_EXT_REJECTED_GROUPS 92
+#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
 
 /* Extended Capabilities field */
 #define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -556,6 +558,7 @@
 #define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
 #define WLAN_EXT_CAPAB_SAE_PW_ID 81
 #define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
+#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
 
 /* Extended RSN Capabilities */
 /* bits 0-3: Field length (n-1) */
@@ -1319,6 +1322,8 @@
 #define OWE_IE_VENDOR_TYPE 0x506f9a1c
 #define OWE_OUI_TYPE 28
 #define MULTI_AP_OUI_TYPE 0x1B
+#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
+#define DPP_CC_OUI_TYPE 0x1e
 
 #define MULTI_AP_SUB_ELEM_TYPE 0x06
 #define MULTI_AP_TEAR_DOWN BIT(4)
@@ -1878,7 +1883,15 @@
 /* WNM-Sleep Mode subelement IDs */
 enum wnm_sleep_mode_subelement_id {
 	WNM_SLEEP_SUBELEM_GTK = 0,
-	WNM_SLEEP_SUBELEM_IGTK = 1
+	WNM_SLEEP_SUBELEM_IGTK = 1,
+	WNM_SLEEP_SUBELEM_BIGTK = 2,
+};
+
+/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */
+enum wnm_notification_Type {
+	WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0,
+	WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2,
+	WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221,
 };
 
 /* Channel Switch modes (802.11h) */
@@ -2094,7 +2107,7 @@
 	PHY_TYPE_VHT = 9,
 };
 
-/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
+/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */
 /* BSSID Information Field */
 #define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
 #define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
@@ -2111,6 +2124,7 @@
 #define NEI_REP_BSSID_INFO_HT BIT(11)
 #define NEI_REP_BSSID_INFO_VHT BIT(12)
 #define NEI_REP_BSSID_INFO_FTM BIT(13)
+#define NEI_REP_BSSID_INFO_HE BIT(14)
 
 /*
  * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
@@ -2173,6 +2187,7 @@
 #define HE_CAPABILITIES_IE_MIN_LEN 21
 
 /* HE Capabilities Information defines */
+#define HE_MACCAP_TWT_RESPONDER			((u8) BIT(2))
 #define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX		0
 #define HE_PHYCAP_CHANNEL_WIDTH_MASK		((u8) (BIT(1) | BIT(2) | \
 						      BIT(3) | BIT(4)))
@@ -2215,7 +2230,7 @@
 #define HE_OPERATION_BSS_COLOR_MASK		((u32) (BIT(24) | BIT(25) | \
 							BIT(26) | BIT(27) | \
 							BIT(28) | BIT(29)))
-#define HE_OPERATION_PARTIAL_BSS_COLOR		((u32) BIT(30))
+#define HE_OPERATION_BSS_COLOR_PARTIAL		((u32) BIT(30))
 #define HE_OPERATION_BSS_COLOR_DISABLED		((u32) BIT(31))
 #define HE_OPERATION_BSS_COLOR_OFFSET		24
 
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index b85c6c3..d2c4bbd 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -82,6 +82,7 @@
 	size_t seq_len;
 	u8 key[32];
 	size_t key_len;
+	enum key_flag key_flag;
 };
 
 enum privsep_event {
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ade7aa6..8ef666d 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -21,6 +21,10 @@
 
 #define OUI_QCA 0x001374
 
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
 /**
  * enum qca_radiotap_vendor_ids - QCA radiotap vendor namespace IDs
  */
@@ -619,6 +623,31 @@
  *	association when in disconnected state. For AP mode, only information
  *	of the currently connected stations is available. This command uses
  *	attributes defined in enum qca_wlan_vendor_attr_get_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_EVENT: This acts as an event.
+ *	Host drivers can request the user space entity to set the SAR power
+ *	limits with this event. Accordingly, the user space entity is expected
+ *	to set the SAR power limits. Host drivers can retry this event to the
+ *	user space for the SAR power limits configuration from user space. If
+ *	the driver does not get the SAR power limits from user space for all
+ *	the retried attempts, it can configure a default SAR power limit.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO: This acts as a vendor event and
+ *	is used to update the information about the station from the driver to
+ *	userspace. Uses attributes from enum
+ *	qca_wlan_vendor_attr_update_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON: This acts as an event.
+ *	The host driver initiates the disconnection for scenarios such as beacon
+ *	miss, NUD failure, peer kick out, etc. The disconnection indication
+ *	through cfg80211_disconnected() expects the reason codes from enum
+ *	ieee80211_reasoncode which does not signify these various reasons why
+ *	the driver has triggered the disconnection. This event will be used to
+ *	send the driver specific reason codes by the host driver to userspace.
+ *	Host drivers should trigger this event and pass the respective reason
+ *	code immediately prior to triggering cfg80211_disconnected(). The
+ *	attributes used with this event are defined in enum
+ *	qca_wlan_vendor_attr_driver_disconnect_reason.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -795,6 +824,9 @@
 	QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184,
 	QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185,
 	QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO = 186,
+	QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187,
+	QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188,
+	QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189,
 };
 
 enum qca_wlan_vendor_attr {
@@ -1191,7 +1223,9 @@
  *
  * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL: Required (u8).
  * Used with event to notify the VHT segment 0 center channel number selected in
- * ACS operation.
+ * ACS operation. The value is the index of the channel center frequency for
+ * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center frequency index
+ * of the primary 80 MHz segment for 160 MHz and 80+80 MHz channels.
  * Note: If both the driver and user-space application supports the 6 GHz band,
  * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is deprecated; use
  * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY instead.
@@ -1201,7 +1235,10 @@
  *
  * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL: Required (u8).
  * Used with event to notify the VHT segment 1 center channel number selected in
- * ACS operation.
+ * ACS operation. The value is zero for 20 MHz, 40 MHz, and 80 MHz channels.
+ * The value is the index of the channel center frequency for 160 MHz channels
+ * and the center frequency index of the secondary 80 MHz segment for 80+80 MHz
+ * channels.
  * Note: If both the driver and user-space application supports the 6 GHz band,
  * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is deprecated; use
  * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY instead.
@@ -1244,6 +1281,15 @@
  * Note: If the driver supports the 6 GHz band, the event sent from the driver
  * includes this attribute along with
  * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED: Flag attribute.
+ * Used with command to notify the driver of EDMG request for ACS
+ * operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL: Optional (u8).
+ * Used with event to notify the EDMG channel number selected in ACS
+ * operation.
+ * EDMG primary channel is indicated by QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
  */
 enum qca_wlan_vendor_attr_acs_offload {
 	QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
@@ -1262,6 +1308,8 @@
 	QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY = 13,
 	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY = 14,
 	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15,
+	QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED = 16,
+	QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
@@ -1320,6 +1368,11 @@
  * @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
  * @QCA_WLAN_VENDOR_FEATURE_11AX: Device supports 802.11ax (HE)
  * @QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT: Device supports 6 GHz band operation
+ * @QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG: Device is capable of receiving
+ *	and applying thermal configuration through
+ *	%QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL and
+ *	%QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW attributes from
+ *	userspace.
  * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
  */
 enum qca_wlan_vendor_features {
@@ -1334,6 +1387,7 @@
 	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,
 	NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
 };
 
@@ -1675,6 +1729,9 @@
  *	randomisation
  * @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
  *	specific BSSID to scan for.
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME: Unsigned 64-bit dwell time in
+ *	microseconds. This is a common value which applies across all
+ *	frequencies specified by QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES.
  */
 enum qca_wlan_vendor_attr_scan {
 	QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@@ -1689,6 +1746,7 @@
 	QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9,
 	QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
 	QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
+	QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12,
 	QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
 	QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -2043,19 +2101,41 @@
 	 * take the union of IEs from both of these interfaces and send in
 	 * further disassoc/deauth frames.
 	 */
-	QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
+	QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58,
 
 	/* 8-bit unsigned value for ELNA bypass.
 	 * 1-Enable, 0-Disable
 	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
 
+	/* 8-bit unsigned value. This attribute enables/disables the host driver
+	 * to send the Beacon Report Response with failure reason for the
+	 * scenarios where STA cannot honor the Beacon Report Request from AP.
+	 * 1-Enable, 0-Disable.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL = 60,
+
+	/* 8-bit unsigned value. This attribute enables/disables the host driver
+	 * to send roam reason information in the Reassociation Request frame to
+	 * the target AP when roaming within the same ESS.
+	 * 1-Enable, 0-Disable.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON = 61,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
 };
 
+/* Compatibility defines for previously used incorrect enum
+ * qca_wlan_vendor_attr_config names. These values should not be used in any
+ * new implementation. */
+#define QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES \
+	QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES
+#define QCA_WLAN_VENDOR_ATTR_BEACON_REPORT_FAIL \
+	QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL
+
 /**
  * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
  *
@@ -5656,6 +5736,39 @@
 	QCA_WLAN_HANG_DXE_FAILURE = 12,
 	/* WMI pending commands exceed the maximum count */
 	QCA_WLAN_HANG_WMI_EXCEED_MAX_PENDING_CMDS = 13,
+	/* Timeout for peer STA connection accept command's response from the
+	 * FW in AP mode. This command is triggered when a STA (peer) connects
+	 * to AP (DUT).
+	 */
+	QCA_WLAN_HANG_AP_STA_CONNECT_REQ_TIMEOUT = 14,
+	/* Timeout for the AP connection accept command's response from the FW
+	 * in STA mode. This command is triggered when the STA (DUT) connects
+	 * to an AP (peer).
+	 */
+	QCA_WLAN_HANG_STA_AP_CONNECT_REQ_TIMEOUT = 15,
+	/* Timeout waiting for the response to the MAC HW mode change command
+	 * sent to FW as a part of MAC mode switch among DBS (Dual Band
+	 * Simultaneous), SCC (Single Channel Concurrency), and MCC (Multi
+	 * Channel Concurrency) mode.
+	 */
+	QCA_WLAN_HANG_MAC_HW_MODE_CHANGE_TIMEOUT = 16,
+	/* Timeout waiting for the response from FW to configure the MAC HW's
+	 * mode. This operation is to configure the single/two MACs in either
+	 * SCC/MCC/DBS mode.
+	 */
+	QCA_WLAN_HANG_MAC_HW_MODE_CONFIG_TIMEOUT = 17,
+	/* Timeout waiting for response of VDEV start command from the FW */
+	QCA_WLAN_HANG_VDEV_START_RESPONSE_TIMED_OUT = 18,
+	/* Timeout waiting for response of VDEV restart command from the FW */
+	QCA_WLAN_HANG_VDEV_RESTART_RESPONSE_TIMED_OUT = 19,
+	/* Timeout waiting for response of VDEV stop command from the FW */
+	QCA_WLAN_HANG_VDEV_STOP_RESPONSE_TIMED_OUT = 20,
+	/* Timeout waiting for response of VDEV delete command from the FW */
+	QCA_WLAN_HANG_VDEV_DELETE_RESPONSE_TIMED_OUT = 21,
+	/* Timeout waiting for response of peer all delete request command to
+	 * the FW on a specific VDEV.
+	 */
+	QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT = 22,
 };
 
 /**
@@ -5668,6 +5781,12 @@
 	 * qca_wlan_vendor_hang_reason.
 	 */
 	QCA_WLAN_VENDOR_ATTR_HANG_REASON = 1,
+	/* The binary blob data associated with the hang reason specified by
+	 * QCA_WLAN_VENDOR_ATTR_HANG_REASON. This binary data is expected to
+	 * contain the required dump to analyze the reason for the hang.
+	 * NLA_BINARY attribute, the max size is 1024 bytes.
+	 */
+	QCA_WLAN_VENDOR_ATTR_HANG_REASON_DATA = 2,
 
 	QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_HANG_MAX =
@@ -5768,12 +5887,22 @@
 enum qca_wlan_vendor_attr_rtplinst {
 	QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0,
 
-	/* Primary channel number (u8) */
+	/* Primary channel number (u8).
+	 * Note: If both the driver and user space application support the
+	 * 6 GHz band, this attribute is deprecated and
+	 * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY should be used. To
+	 * maintain backward compatibility,
+	 * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY is still used if either the
+	 * driver or user space application or both do not support the 6 GHz
+	 * band.
+	 */
 	QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY = 1,
 	/* Representative Tx power in dBm (s32) with emphasis on throughput. */
 	QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_THROUGHPUT = 2,
 	/* Representative Tx power in dBm (s32) with emphasis on range. */
 	QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_RANGE = 3,
+	/* Primary channel center frequency (u32) in MHz */
+	QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY = 4,
 
 	QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX =
@@ -6305,6 +6434,29 @@
 };
 
 /**
+ * enum qca_wlan_vendor_thermal_level - Defines various thermal levels
+ * configured by userspace to the driver/firmware. The values will be
+ * encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL attribute.
+ * The driver/firmware takes actions requested by userspace such as throttling
+ * wifi TX etc. in order to mitigate high temperature.
+ *
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE: Stop/clear all throttling actions.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT: Throttle TX lightly.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE: Throttle TX moderately.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE: Throttle TX severely.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL: Critical thermal level reached.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY: Emergency thermal level reached.
+ */
+enum qca_wlan_vendor_thermal_level {
+	QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE = 0,
+	QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT = 1,
+	QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE = 2,
+	QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE = 3,
+	QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL = 4,
+	QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY = 5,
+};
+
+/**
  * enum qca_wlan_vendor_attr_thermal_cmd - Vendor subcmd attributes to set
  * cmd value. Used for NL attributes for data used by
  * QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
@@ -6317,6 +6469,21 @@
 	 * u32 attribute.
 	 */
 	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
+	/* Userspace uses this attribute to configure thermal level to the
+	 * driver/firmware. Used in request, u32 attribute, possible values
+	 * are defined in enum qca_wlan_vendor_thermal_level.
+	 */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL = 2,
+	/* Userspace uses this attribute to configure the time in which the
+	 * driver/firmware should complete applying settings it received from
+	 * userspace with QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL
+	 * command type. Used in request, u32 attribute, value is in
+	 * milliseconds. A value of zero indicates to apply the settings
+	 * immediately. The driver/firmware can delay applying the configured
+	 * thermal settings within the time specified in this attribute if
+	 * there is any critical ongoing operation.
+	 */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW = 3,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
@@ -6340,12 +6507,15 @@
  * suspend action.
  * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal
  * resume action.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: Configure thermal level to
+ * the driver/firmware.
  */
 enum qca_wlan_vendor_attr_thermal_cmd_type {
 	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
 	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE,
 	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND,
 	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
+	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL,
 };
 
 /**
@@ -7254,10 +7424,42 @@
  * enum qca_wlan_vendor_cfr_method - QCA vendor CFR methods used by
  * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD as part of vendor
  * command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG.
+ * @QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL: CFR method using QoS Null frame
+ * @QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE: CFR method using QoS Null frame
+ * with phase
+ * @QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE: CFR method using Probe Response frame
  */
 enum qca_wlan_vendor_cfr_method {
-	/* CFR method using QOS Null frame */
 	QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0,
+	QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE = 1,
+	QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_cfr_capture_type - QCA vendor CFR capture type used by
+ * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_FTM: Filter directed FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK: Filter all FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP: Filter NDPA NDP directed frames.
+ * @QCA_WLAN_VENDOR_CFR_TA_RA: Filter frames based on TA/RA/Subtype which
+ * is provided by one or more of below attributes:
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ * @QCA_WLAN_CFR_ALL_PACKET: Filter all packets.
+ * @QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL: Filter all NDPA NDP frames.
+ */
+enum qca_wlan_vendor_cfr_capture_type {
+	QCA_WLAN_VENDOR_CFR_DIRECT_FTM = 0,
+	QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK = 1,
+	QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP = 2,
+	QCA_WLAN_VENDOR_CFR_TA_RA = 3,
+	QCA_WLAN_VENDOR_CFR_ALL_PACKET = 4,
+	QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL = 5,
 };
 
 /**
@@ -7265,44 +7467,177 @@
  * QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer
  * Channel Frequency Response capture parameters and enable periodic CFR
  * capture.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR: Optional (6-byte MAC address)
+ * MAC address of peer. This is for CFR version 1 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE: Required (flag)
+ * Enable peer CFR capture. This attribute is mandatory to enable peer CFR
+ * capture. If this attribute is not present, peer CFR capture is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH: Optional (u8)
+ * BW of measurement, attribute uses the values in enum nl80211_chan_width
+ * Supported values: 20, 40, 80, 80+80, 160.
+ * Note that all targets may not support all bandwidths.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY: Optional (u32)
+ * Periodicity of CFR measurement in milliseconds.
+ * Periodicity should be a multiple of Base timer.
+ * Current Base timer value supported is 10 milliseconds (default).
+ * 0 for one shot capture.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD: Optional (u8)
+ * Method used to capture Channel Frequency Response.
+ * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE: Optional (flag)
+ * Enable periodic CFR capture.
+ * This attribute is mandatory for version 1 to enable Periodic CFR capture.
+ * If this attribute is not present, periodic CFR capture is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION: Optional (u8)
+ * Value is 1 or 2 since there are two versions of CFR capture. Two versions
+ * can't be enabled at same time. This attribute is mandatory if target
+ * support both versions and use one of them.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP: Optional (u32)
+ * This attribute is mandatory for version 2 if
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY is used.
+ * Bits 15:0 bitfield indicates which group is to be enabled.
+ * Bits 31:16 Reserved for future use.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION: Optional (u32)
+ * CFR capture duration in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL: Optional (u32)
+ * CFR capture interval in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE: Optional (u32)
+ * CFR capture type is defined in enum qca_wlan_vendor_cfr_capture_type.
+ * This attribute is mandatory for version 2.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK: Optional (u64)
+ * Bitfield indicating which user in the current UL MU transmissions are
+ * enabled for CFR capture. Bits 36 to 0 indicate user indexes for 37 users in
+ * a UL MU transmission. If bit 0 is set, the CFR capture will happen for user
+ * index 0 in the current UL MU transmission. If bits 0 and 2 are set, CFR
+ * capture for UL MU TX corresponds to user indices 0 and 2. Bits 63:37 are
+ * reserved for future use. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT: Optional (u32)
+ * Indicates the number of consecutive RX frames to be skipped before CFR
+ * capture is enabled again. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE: Nested attribute containing
+ * one or more %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY attributes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY: Nested attribute containing
+ * the following group attributes:
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER,
+ *	%QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER: Optional (u32)
+ * Target supports multiple groups for some configurations. The group number
+ * can be any value between 0 and 15. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA: Optional (6-byte MAC address)
+ * Transmitter address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA: Optional (6-byte MAC address)
+ * Receiver address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK: Optional (6-byte MAC address)
+ * Mask of transmitter address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK: Optional (6-byte MAC address)
+ * Mask of receiver address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS: Optional (u32)
+ * Indicates frames with a specific NSS will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 7:0 request CFR
+ * capture to be done for frames matching the NSS specified within this bitmask.
+ * Bits 31:8 are reserved for future use. Bits 7:0 map to NSS:
+ *     bit 0 : NSS 1
+ *     bit 1 : NSS 2
+ *     ...
+ *     bit 7 : NSS 8
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW: Optional (u32)
+ * Indicates frames with a specific bandwidth will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 4:0 request CFR
+ * capture to be done for frames matching the bandwidths specified within this
+ * bitmask. Bits 31:5 are reserved for future use. Bits 4:0 map to bandwidth
+ * numerated in enum nl80211_band (although not all bands may be supported
+ * by a given device).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER: Optional (u32)
+ * Management frames matching the subtype filter categories will be filtered in
+ * by MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Management frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. For example, Beacon frame control type
+ * is 8 and its value is 1 << 8 = 0x100. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER: Optional (u32)
+ * Control frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Control frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER: Optional (u32)
+ * Data frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Data frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
  */
 enum qca_wlan_vendor_peer_cfr_capture_attr {
 	QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0,
-	/* 6-byte MAC address of the peer.
-	 * This attribute is mandatory.
-	 */
 	QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR = 1,
-	/* Enable peer CFR Capture, flag attribute.
-	 * This attribute is mandatory to enable peer CFR capture.
-	 * If this attribute is not present, peer CFR capture is disabled.
-	 */
 	QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE = 2,
-	/* BW of measurement, attribute uses the values in enum nl80211_chan_width
-	 * Supported values: 20, 40, 80, 80+80, 160.
-	 * Note that all targets may not support all bandwidths.
-	 * u8 attribute. This attribute is mandatory if attribute
-	 * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
-	 */
 	QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH = 3,
-	/* Periodicity of CFR measurement in msec.
-	 * Periodicity should be a multiple of Base timer.
-	 * Current Base timer value supported is 10 msecs (default).
-	 * 0 for one shot capture. u32 attribute.
-	 * This attribute is mandatory if attribute
-	 * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
-	 */
 	QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY = 4,
-	/* Method used to capture Channel Frequency Response.
-	 * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
-	 * u8 attribute. This attribute is mandatory if attribute
-	 * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
-	 */
 	QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD = 5,
-	/* Enable periodic CFR capture, flag attribute.
-	 * This attribute is mandatory to enable Periodic CFR capture.
-	 * If this attribute is not present, periodic CFR capture is disabled.
-	 */
 	QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE = 6,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION = 7,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP = 8,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION = 9,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL = 10,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE = 11,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK = 12,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT = 13,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE = 14,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY = 15,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER = 16,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA = 17,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA = 18,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK = 19,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK = 20,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS = 21,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW = 22,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER = 23,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER = 24,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER = 25,
 
 	/* Keep last */
 	QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
@@ -8091,10 +8426,10 @@
  * used by QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command.
  *
  * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC:
- * Required attribute in request, 6-byte MAC address,
- * used in both STA and AP modes.
- * MAC address of the station for which information is requested (BSSID of the
- * AP in STA mode).
+ * Required attribute in request for AP mode only, 6-byte MAC address,
+ * corresponding to the station's MAC address for which information is
+ * requested. For STA mode this is not required as the info always correspond
+ * to the self STA and the current/last association.
  *
  * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS:
  * Optionally used in response, u32 attribute, contains a bitmap of different
@@ -8122,7 +8457,7 @@
  * back to host from target.
  *
  * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED:
- * Optionally used in response, u32 attribute, used in AP mode only.
+ * Optionally used in response, u32 attribute, used in both STA and AP mode.
  * Value indicates the number of data frames not transmitted successfully even
  * after retrying the packets for the number of times equal to the total number
  * of retries allowed for that packet and for which the TX status has been
@@ -8139,10 +8474,167 @@
  * after retrying the packets.
  *
  * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED:
- * Optionally used in response, u32 attribute, used in AP mode only.
+ * Optionally used in response, u32 attribute, used in both STA & AP mode.
  * Value indicates the number of data frames not transmitted successfully even
  * after retrying the packets for the number of times equal to the total number
  * of retries allowed for that packet.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT: u32, used in
+ * the STA mode only. Represent the number of probe requests sent by the STA
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. If queried in the disconnected state, this represents the
+ * count for the last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT: u32, used in
+ * the STA mode. Represent the number of probe responses received by the station
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. When queried in the disconnected state, this represents the
+ * count when in last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT: u32, used in the
+ * STA mode only. Represents the total number of frames sent out by STA
+ * including Data, ACK, RTS, CTS, Control Management. This data is maintained
+ * only for the connect session. Represents the count of last connected session,
+ * when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT: u32, used in the STA mode.
+ * Total number of RTS sent out by the STA. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT: u32, used in the
+ * STA mode.Represent the number of RTS transmission failure that reach retry
+ * limit. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT: u32, used in
+ * the STA mode. Represent the total number of non aggregated frames transmitted
+ * by the STA. This data is maintained per connect session. Represents the count
+ * of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT: u32, used in the
+ * STA mode. Represent the total number of aggregated frames transmitted by the
+ * STA. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT: u32, used in
+ * the STA mode. Represents the number of received frames with a good PLCP. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT: u32,
+ * used in the STA mode. Represents the number of occasions that no valid
+ * delimiter is detected by A-MPDU parser. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT: u32, used in the
+ * STA mode. Represents the number of frames for which CRC check failed in the
+ * MAC. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT: u32, used in the
+ * STA mode. Represents the number of unicast ACKs received with good FCS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT: u32, used in the STA
+ * mode. Represents the number of received Block Acks. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT: u32, used in the STA
+ * mode. Represents the number of beacons received from the connected BSS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT: u32, used in the
+ * STA mode. Represents the number of beacons received by the other BSS when in
+ * connected state (through the probes done by the STA). This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT: u64, used in
+ * the STA mode. Represents the number of received DATA frames with good FCS and
+ * matching Receiver Address when in connected state. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT: u32, used in the
+ * STA mode. Represents the number of RX Data multicast frames dropped by the HW
+ * when in the connected state. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS: u32, used in the
+ * STA mode. This represents the target power in dBm for the transmissions done
+ * to the AP in 2.4 GHz at 1 Mbps (DSSS) rate. This data is maintained per
+ * connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 5 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in
+ * the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for for transmissions done
+ * to the AP in 5 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT: u32, used
+ * in the STA mode. This represents the Nested attribute representing the
+ * overflow counts of each receive buffer allocated to the hardware during the
+ * STA's connection. The number of hw buffers might vary for each WLAN
+ * solution and hence this attribute represents the nested array of all such
+ * HW buffer count. This data is maintained per connect session. Represents
+ * the count of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER: u32, Max TX power (dBm)
+ * allowed as per the regulatory requirements for the current or last connected
+ * session. Used in the STA mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER: u32, Latest TX power
+ * (dBm) used by the station in its latest unicast frame while communicating
+ * to the AP in the connected state. When queried in the disconnected state,
+ * this represents the TX power used by the STA with last AP communication
+ * when in connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL: u32, Adaptive noise immunity
+ * level used to adjust the RX sensitivity. Represents the current ANI level
+ * when queried in the connected state. When queried in the disconnected
+ * state, this corresponds to the latest ANI level at the instance of
+ * disconnection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES: Binary attribute containing
+ * the raw information elements from Beacon frames. Represents the Beacon frames
+ * of the current BSS in the connected state. When queried in the disconnected
+ * state, these IEs correspond to the last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES: Binary attribute
+ * containing the raw information elements from Probe Response frames.
+ * Represents the Probe Response frames of the current BSS in the connected
+ * state. When queried in the disconnected state, these IEs correspond to the
+ * last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON: u32, Driver
+ * disconnect reason for the last disconnection if the disconnection is
+ * triggered from the host driver. The values are referred from
+ * enum qca_disconnect_reason_codes.
  */
 enum qca_wlan_vendor_attr_get_sta_info {
 	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -8156,6 +8648,34 @@
 	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL = 8,
 	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY = 9,
 	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED = 10,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT = 11,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT = 12,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT = 13,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT = 14,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT = 15,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT = 16,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT = 17,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT = 18,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT = 19,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT = 20,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT = 21,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT = 22,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT = 23,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT = 24,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT = 25,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT = 26,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS = 27,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS = 28,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0 = 29,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS = 30,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0 = 31,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT = 32,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER = 33,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER = 34,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL = 35,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES = 36,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES = 37,
+	QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON = 38,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
@@ -8163,4 +8683,126 @@
 	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_vendor_attr_update_sta_info - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS: Type is NLA_UNSPEC.
+ * Used in STA mode. This attribute represents the list of channel center
+ * frequencies in MHz (u32) the station has learnt during the last connection
+ * or roaming attempt. This information shall not signify the channels for
+ * an explicit scan request from the user space. Host drivers can update this
+ * information to the user space in both connected and disconnected state.
+ * In the disconnected state this information shall signify the channels
+ * scanned in the last connection/roam attempt that lead to the disconnection.
+ */
+enum qca_wlan_vendor_attr_update_sta_info {
+	QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS = 1,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_MAX =
+	QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_disconnect_reason_codes - Specifies driver disconnect reason codes.
+ * Used when the driver triggers the STA to disconnect from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSPECIFIED: The host driver triggered the
+ * disconnection with the AP due to unspecified reasons.
+ *
+ * @QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE: The host driver triggered the
+ * disconnection with the AP due to a roaming failure. This roaming is triggered
+ * internally (host driver/firmware).
+ *
+ * @QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE: The driver disconnected from
+ * the AP when the user/external triggered roaming fails.
+ *
+ * @QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE: This reason code is used
+ * by the host driver whenever gateway reachability failure is detected and the
+ * driver disconnects with AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA: The driver disconnected from
+ * the AP on a channel switch announcement from it with an unsupported channel.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR: On a concurrent AP start
+ * with indoor channels disabled and if the STA is connected on one of these
+ * disabled channels, the host driver disconnected the STA with this reason
+ * code.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED: Disconnection due to an
+ * explicit request from the user to disable the current operating channel.
+ *
+ * @QCA_DISCONNECT_REASON_DEVICE_RECOVERY: STA disconnected from the AP due to
+ * the internal host driver/firmware recovery.
+ *
+ * @QCA_DISCONNECT_REASON_KEY_TIMEOUT: The driver triggered the disconnection on
+ * a timeout for the key installations from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE: The dDriver disconnected the
+ * STA on a band change request from the user space to a different band from the
+ * current operation channel/band.
+ *
+ * @QCA_DISCONNECT_REASON_IFACE_DOWN: The STA disconnected from the AP on an
+ * interface down trigger from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL: The host driver disconnected the
+ * STA on getting continuous transmission failures for multiple Data frames.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_INACTIVITY: The STA does a keep alive
+ * notification to the AP by transmitting NULL/G-ARP frames. This disconnection
+ * represents inactivity from AP on such transmissions.
+
+ * @QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT: This reason code is used on
+ * disconnection when SA Query times out (AP does not respond to SA Query).
+ *
+ * @QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE: The host driver disconnected the
+ * STA on missing the beacons continuously from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE: Disconnection due to STA not
+ * able to move to the channel mentioned by the AP in CSA.
+ *
+ * @QCA_DISCONNECT_REASON_USER_TRIGGERED: User triggered disconnection.
+ */
+enum qca_disconnect_reason_codes {
+	QCA_DISCONNECT_REASON_UNSPECIFIED = 0,
+	QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE = 1,
+	QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE = 2,
+	QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE = 3,
+	QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA = 4,
+	QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR = 5,
+	QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED = 6,
+	QCA_DISCONNECT_REASON_DEVICE_RECOVERY = 7,
+	QCA_DISCONNECT_REASON_KEY_TIMEOUT = 8,
+	QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE = 9,
+	QCA_DISCONNECT_REASON_IFACE_DOWN = 10,
+	QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL = 11,
+	QCA_DISCONNECT_REASON_PEER_INACTIVITY = 12,
+	QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT = 13,
+	QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE = 14,
+	QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE = 15,
+	QCA_DISCONNECT_REASON_USER_TRIGGERED = 16,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_driver_disconnect_reason - Defines attributes
+ * used by %QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE: u32 attribute.
+ * This attribute represents the driver specific reason codes (local
+ * driver/firmware initiated reasons for disconnection) defined
+ * in enum qca_disconnect_reason_codes.
+ */
+enum qca_wlan_vendor_attr_driver_disconnect_reason {
+	QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE = 1,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_MAX =
+	QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index bf8cc9d..543640d 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -123,6 +123,7 @@
 		return;
 	sae_clear_temp_data(sae);
 	crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+	crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0);
 	os_memset(sae, 0, sizeof(*sae));
 }
 
@@ -864,7 +865,7 @@
 }
 
 
-struct crypto_ec_point *
+static struct crypto_ec_point *
 sae_derive_pt_ecc(struct crypto_ec *ec, int group,
 		  const u8 *ssid, size_t ssid_len,
 		  const u8 *password, size_t password_len,
@@ -1622,38 +1623,42 @@
 }
 
 
-void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
-		      const struct wpabuf *token, const char *identifier)
+int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+		     const struct wpabuf *token, const char *identifier)
 {
 	u8 *pos;
 
 	if (sae->tmp == NULL)
-		return;
+		return -1;
 
 	wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
-	if (token) {
+	if (!sae->tmp->h2e && token) {
 		wpabuf_put_buf(buf, token);
 		wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
 			    wpabuf_head(token), wpabuf_len(token));
 	}
 	pos = wpabuf_put(buf, sae->tmp->prime_len);
-	crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
-			     sae->tmp->prime_len, sae->tmp->prime_len);
+	if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
+				 sae->tmp->prime_len, sae->tmp->prime_len) < 0)
+		return -1;
 	wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
 		    pos, sae->tmp->prime_len);
 	if (sae->tmp->ec) {
 		pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
-		crypto_ec_point_to_bin(sae->tmp->ec,
-				       sae->tmp->own_commit_element_ecc,
-				       pos, pos + sae->tmp->prime_len);
+		if (crypto_ec_point_to_bin(sae->tmp->ec,
+					   sae->tmp->own_commit_element_ecc,
+					   pos, pos + sae->tmp->prime_len) < 0)
+			return -1;
 		wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
 			    pos, sae->tmp->prime_len);
 		wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
 			    pos + sae->tmp->prime_len, sae->tmp->prime_len);
 	} else {
 		pos = wpabuf_put(buf, sae->tmp->prime_len);
-		crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
-				     sae->tmp->prime_len, sae->tmp->prime_len);
+		if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
+					 sae->tmp->prime_len,
+					 sae->tmp->prime_len) < 0)
+			return -1;
 		wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
 			    pos, sae->tmp->prime_len);
 	}
@@ -1677,6 +1682,18 @@
 		wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
 		wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
 	}
+
+	if (sae->tmp->h2e && token) {
+		wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+		wpabuf_put_u8(buf, 1 + wpabuf_len(token));
+		wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+		wpabuf_put_buf(buf, token);
+		wpa_hexdump_buf(MSG_DEBUG,
+				"SAE: Anti-clogging token (in container)",
+				token);
+	}
+
+	return 0;
 }
 
 
@@ -1742,32 +1759,34 @@
 }
 
 
+static int sae_is_token_container_elem(const u8 *pos, const u8 *end)
+{
+	return end - pos >= 3 &&
+		pos[0] == WLAN_EID_EXTENSION &&
+		pos[1] >= 1 &&
+		end - pos - 2 >= pos[1] &&
+		pos[2] == WLAN_EID_EXT_ANTI_CLOGGING_TOKEN;
+}
+
+
 static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
 				   const u8 *end, const u8 **token,
 				   size_t *token_len, int h2e)
 {
 	size_t scalar_elem_len, tlen;
-	const u8 *elem;
 
 	if (token)
 		*token = NULL;
 	if (token_len)
 		*token_len = 0;
 
+	if (h2e)
+		return; /* No Anti-Clogging Token field outside container IE */
+
 	scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
 	if (scalar_elem_len >= (size_t) (end - *pos))
 		return; /* No extra data beyond peer scalar and element */
 
-	/* It is a bit difficult to parse this now that there is an
-	 * optional variable length Anti-Clogging Token field and
-	 * optional variable length Password Identifier element in the
-	 * frame. We are sending out fixed length Anti-Clogging Token
-	 * fields, so use that length as a requirement for the received
-	 * token and check for the presence of possible Password
-	 * Identifier element based on the element header information.
-	 * When parsing H2E case, also consider the Rejected Groupd element
-	 * similarly.
-	 */
 	tlen = end - (*pos + scalar_elem_len);
 
 	if (tlen < SHA256_MAC_LEN) {
@@ -1777,36 +1796,6 @@
 		return;
 	}
 
-	elem = *pos + scalar_elem_len;
-	if (sae_is_password_id_elem(elem, end)) {
-		 /* Password Identifier element takes out all available
-		  * extra octets, so there can be no Anti-Clogging token in
-		  * this frame. */
-		return;
-	}
-	if (h2e && sae_is_rejected_groups_elem(elem, end)) {
-		 /* Rejected Groups takes out all available extra octets, so
-		  * there can be no Anti-Clogging token in this frame. */
-		return;
-	}
-
-	elem += SHA256_MAC_LEN;
-	if (sae_is_password_id_elem(elem, end)) {
-		 /* Password Identifier element is included in the end, so
-		  * remove its length from the Anti-Clogging token field. */
-		tlen -= 2 + elem[1];
-		elem += 2 + elem[1];
-		if (h2e && sae_is_rejected_groups_elem(elem, end)) {
-			/* Also remove Rejected Groups element from the
-			 * Anti-Clogging token field length */
-			tlen -= 2 + elem[1];
-		}
-	} else if (h2e && sae_is_rejected_groups_elem(elem, end)) {
-		 /* Rejected Groups element is included in the end, so
-		  * remove its length from the Anti-Clogging token field. */
-		tlen -= 2 + elem[1];
-	}
-
 	wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
 	if (token)
 		*token = *pos;
@@ -1816,6 +1805,21 @@
 }
 
 
+static void sae_parse_token_container(struct sae_data *sae,
+				      const u8 *pos, const u8 *end,
+				      const u8 **token, size_t *token_len)
+{
+	wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+		    pos, end - pos);
+	if (!sae_is_token_container_elem(pos, end))
+		return;
+	*token = pos + 3;
+	*token_len = pos[1] - 1;
+	wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)",
+		    *token, *token_len);
+}
+
+
 static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
 				   const u8 *end)
 {
@@ -1836,8 +1840,9 @@
 	 * shall be dropped if the peer-scalar is identical to the one used in
 	 * the existing protocol instance.
 	 */
-	if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
-	    crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
+	if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar_accepted &&
+	    crypto_bignum_cmp(sae->peer_commit_scalar_accepted,
+			      peer_scalar) == 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
 			   "peer-commit-scalar");
 		crypto_bignum_deinit(peer_scalar, 0);
@@ -2010,19 +2015,21 @@
 
 
 static int sae_parse_rejected_groups(struct sae_data *sae,
-				     const u8 *pos, const u8 *end)
+				     const u8 **pos, const u8 *end)
 {
 	wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
-		    pos, end - pos);
-	if (!sae_is_rejected_groups_elem(pos, end))
+		    *pos, end - *pos);
+	if (!sae_is_rejected_groups_elem(*pos, end))
 		return WLAN_STATUS_SUCCESS;
 	wpabuf_free(sae->tmp->peer_rejected_groups);
-	sae->tmp->peer_rejected_groups = wpabuf_alloc(pos[1] - 1);
+	sae->tmp->peer_rejected_groups = wpabuf_alloc((*pos)[1] - 1);
 	if (!sae->tmp->peer_rejected_groups)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	wpabuf_put_data(sae->tmp->peer_rejected_groups, pos + 3, pos[1] - 1);
+	wpabuf_put_data(sae->tmp->peer_rejected_groups, (*pos) + 3,
+			(*pos)[1] - 1);
 	wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
 			sae->tmp->peer_rejected_groups);
+	*pos = *pos + 2 + (*pos)[1];
 	return WLAN_STATUS_SUCCESS;
 }
 
@@ -2062,11 +2069,15 @@
 
 	/* Conditional Rejected Groups element */
 	if (h2e) {
-		res = sae_parse_rejected_groups(sae, pos, end);
+		res = sae_parse_rejected_groups(sae, &pos, end);
 		if (res != WLAN_STATUS_SUCCESS)
 			return res;
 	}
 
+	/* Optional Anti-Clogging Token Container element */
+	if (h2e)
+		sae_parse_token_container(sae, pos, end, token, token_len);
+
 	/*
 	 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
 	 * the values we sent which would be evidence of a reflection attack.
diff --git a/src/common/sae.h b/src/common/sae.h
index b3787e4..7966d70 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -70,6 +70,7 @@
 	u8 pmk[SAE_PMK_LEN];
 	u8 pmkid[SAE_PMKID_LEN];
 	struct crypto_bignum *peer_commit_scalar;
+	struct crypto_bignum *peer_commit_scalar_accepted;
 	int group;
 	unsigned int sync; /* protocol instance variable: Sync */
 	u16 rc; /* protocol instance variable: Rc (received send-confirm) */
@@ -87,8 +88,8 @@
 			  const u8 *addr1, const u8 *addr2,
 			  int *rejected_groups);
 int sae_process_commit(struct sae_data *sae);
-void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
-		      const struct wpabuf *token, const char *identifier);
+int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+		     const struct wpabuf *token, const char *identifier);
 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
 		     const u8 **token, size_t *token_len, int *allowed_groups,
 		     int h2e);
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index de4b6ec..1284743 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -355,6 +355,14 @@
 	size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
 	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
 	size_t ptk_len;
+#ifdef CONFIG_OWE
+	int owe_ptk_workaround = 0;
+
+	if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) {
+		owe_ptk_workaround = 1;
+		akmp = WPA_KEY_MGMT_OWE;
+	}
+#endif /* CONFIG_OWE */
 
 	if (pmk_len == 0) {
 		wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
@@ -407,11 +415,33 @@
 #else /* CONFIG_SUITEB192 || CONFIG_FILS */
 		return -1;
 #endif /* CONFIG_SUITEB192 || CONFIG_FILS */
-	} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
+	} else if (wpa_key_mgmt_sha256(akmp)) {
 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
 		if (sha256_prf(pmk, pmk_len, label, data, data_len,
 			       tmp, ptk_len) < 0)
 			return -1;
+#ifdef CONFIG_OWE
+	} else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 ||
+						owe_ptk_workaround)) {
+		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
+		if (sha256_prf(pmk, pmk_len, label, data, data_len,
+			       tmp, ptk_len) < 0)
+			return -1;
+	} else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) {
+		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
+		if (sha384_prf(pmk, pmk_len, label, data, data_len,
+			       tmp, ptk_len) < 0)
+			return -1;
+	} else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) {
+		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
+		if (sha512_prf(pmk, pmk_len, label, data, data_len,
+			       tmp, ptk_len) < 0)
+			return -1;
+	} else if (akmp == WPA_KEY_MGMT_OWE) {
+		wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u",
+			   (unsigned int) pmk_len);
+		return -1;
+#endif /* CONFIG_OWE */
 #ifdef CONFIG_DPP
 	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -904,6 +934,10 @@
 			parse->oci_len = len;
 			break;
 #endif /* CONFIG_OCV */
+		case FTIE_SUBELEM_BIGTK:
+			parse->bigtk = pos;
+			parse->bigtk_len = len;
+			break;
 		default:
 			wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
 			break;
@@ -1940,10 +1974,12 @@
 	switch (cipher) {
 	case WPA_CIPHER_NONE:
 		return "NONE";
+#ifdef CONFIG_WEP
 	case WPA_CIPHER_WEP40:
 		return "WEP-40";
 	case WPA_CIPHER_WEP104:
 		return "WEP-104";
+#endif /* CONFIG_WEP */
 	case WPA_CIPHER_TKIP:
 		return "TKIP";
 	case WPA_CIPHER_CCMP:
@@ -2079,8 +2115,6 @@
 		return RSN_AUTH_KEY_MGMT_OWE;
 	if (akm & WPA_KEY_MGMT_DPP)
 		return RSN_AUTH_KEY_MGMT_DPP;
-	if (akm & WPA_KEY_MGMT_OSEN)
-		return RSN_AUTH_KEY_MGMT_OSEN;
 	return 0;
 }
 
@@ -2444,10 +2478,12 @@
 			val |= WPA_CIPHER_GCMP;
 		else if (os_strcmp(start, "TKIP") == 0)
 			val |= WPA_CIPHER_TKIP;
+#ifdef CONFIG_WEP
 		else if (os_strcmp(start, "WEP104") == 0)
 			val |= WPA_CIPHER_WEP104;
 		else if (os_strcmp(start, "WEP40") == 0)
 			val |= WPA_CIPHER_WEP40;
+#endif /* CONFIG_WEP */
 		else if (os_strcmp(start, "NONE") == 0)
 			val |= WPA_CIPHER_NONE;
 		else if (os_strcmp(start, "GTK_NOT_USED") == 0)
@@ -2645,12 +2681,10 @@
 /**
  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
  * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
  * @ie: Pointer to parsed IE data
  * Returns: 0 on success, 1 if end mark is found, -1 on failure
  */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
-			     struct wpa_eapol_ie_parse *ie)
+static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
 {
 	if (pos[1] == 0)
 		return 1;
@@ -2672,8 +2706,7 @@
 		return 0;
 	}
 
-	if (1 + RSN_SELECTOR_LEN < end - pos &&
-	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+	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",
@@ -2681,6 +2714,14 @@
 		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);
+		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;
@@ -2708,6 +2749,15 @@
 		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;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		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;
@@ -2734,6 +2784,16 @@
 		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;
+		wpa_hexdump(MSG_DEBUG,
+			    "WPA: Transition Disable KDE in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
 	return 0;
 }
 
@@ -2842,7 +2902,7 @@
 				ie->supp_oper_classes_len = pos[1];
 			}
 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
-			ret = wpa_parse_generic(pos, end, ie);
+			ret = wpa_parse_generic(pos, ie);
 			if (ret < 0)
 				break;
 			if (ret > 0) {
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index beb1ecd..da58159 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -109,9 +109,11 @@
 #define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
 #define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
 #define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
 
 #define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
 #define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
+#define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20)
 
 #define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
 
@@ -130,6 +132,8 @@
 
 #define WPA_IGTK_LEN 16
 #define WPA_IGTK_MAX_LEN 32
+#define WPA_BIGTK_LEN 16
+#define WPA_BIGTK_MAX_LEN 32
 
 
 /* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -227,6 +231,11 @@
 	size_t igtk_len;
 };
 
+struct wpa_bigtk {
+	u8 bigtk[WPA_BIGTK_MAX_LEN];
+	size_t bigtk_len;
+};
+
 /* WPA IE version 1
  * 00-50-f2:1 (OUI:OUI type)
  * 0x01 0x00 (version; little endian)
@@ -292,6 +301,13 @@
 	u8 igtk[WPA_IGTK_MAX_LEN];
 } STRUCT_PACKED;
 
+#define WPA_BIGTK_KDE_PREFIX_LEN (2 + 6)
+struct wpa_bigtk_kde {
+	u8 keyid[2];
+	u8 pn[6];
+	u8 bigtk[WPA_BIGTK_MAX_LEN];
+} STRUCT_PACKED;
+
 struct rsn_mdie {
 	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
 	u8 ft_capab;
@@ -321,6 +337,7 @@
 #define FTIE_SUBELEM_R0KH_ID 3
 #define FTIE_SUBELEM_IGTK 4
 #define FTIE_SUBELEM_OCI 5
+#define FTIE_SUBELEM_BIGTK 6
 
 struct rsn_rdie {
 	u8 id;
@@ -328,6 +345,12 @@
 	le16 status_code;
 } STRUCT_PACKED;
 
+/* WFA Transition Disable KDE (using OUI_WFA) */
+/* Transition Disable Bitmap bits */
+#define TRANSITION_DISABLE_WPA3_PERSONAL BIT(0)
+#define TRANSITION_DISABLE_SAE_PK BIT(1)
+#define TRANSITION_DISABLE_WPA3_ENTERPRISE BIT(2)
+#define TRANSITION_DISABLE_ENHANCED_OPEN BIT(3)
 
 #ifdef _MSC_VER
 #pragma pack(pop)
@@ -455,6 +478,8 @@
 	size_t tie_len;
 	const u8 *igtk;
 	size_t igtk_len;
+	const u8 *bigtk;
+	size_t bigtk_len;
 #ifdef CONFIG_OCV
 	const u8 *oci;
 	size_t oci_len;
@@ -476,18 +501,23 @@
 	const u8 *rsn_ie;
 	size_t rsn_ie_len;
 	const u8 *pmkid;
+	const u8 *key_id;
 	const u8 *gtk;
 	size_t gtk_len;
 	const u8 *mac_addr;
 	size_t mac_addr_len;
 	const u8 *igtk;
 	size_t igtk_len;
+	const u8 *bigtk;
+	size_t bigtk_len;
 	const u8 *mdie;
 	size_t mdie_len;
 	const u8 *ftie;
 	size_t ftie_len;
 	const u8 *ip_addr_req;
 	const u8 *ip_addr_alloc;
+	const u8 *transition_disable;
+	size_t transition_disable_len;
 	const u8 *oci;
 	size_t oci_len;
 	const u8 *osen;
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 944b6e3..c1ce68c 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -270,7 +270,6 @@
 void wpa_ctrl_cleanup(void)
 {
 	DIR *dir;
-	struct dirent entry;
 	struct dirent *result;
 	size_t dirnamelen;
 	size_t maxcopy;
@@ -288,8 +287,8 @@
 	}
 	namep = pathname + dirnamelen;
 	maxcopy = PATH_MAX - dirnamelen;
-	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
-		if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+	while ((result = readdir(dir)) != NULL) {
+		if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
 			unlink(pathname);
 	}
 	closedir(dir);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index f03c698..ca1c35f 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -95,6 +95,8 @@
 /** SAE authentication failed due to unknown password identifier */
 #define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
 	"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
+/** Unprotected Beacon frame dropped */
+#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON "
 
 /** IP subnet status change notification
  *
@@ -179,6 +181,7 @@
 #define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
 #define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
 #define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
+#define DPP_EVENT_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID "
 #define DPP_EVENT_RX "DPP-RX "
 #define DPP_EVENT_TX "DPP-TX "
 #define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
@@ -186,6 +189,7 @@
 #define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
 #define DPP_EVENT_INTRO "DPP-INTRO "
 #define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
+#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
 
 /* MESH events */
 #define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -379,6 +383,13 @@
 #define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
 #define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
 
+/* Transition mode disabled indication - followed by bitmap */
+#define TRANSITION_DISABLE "TRANSITION-DISABLE "
+
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index ab108da..c40e955 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -54,6 +54,8 @@
 	sha384.o \
 	sha384-prf.o \
 	sha384-internal.o \
+	sha512.o \
+	sha512-prf.o \
 	sha512-internal.o
 
 LIB_OBJS += crypto_internal.o
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 440da03..7c7515f 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -916,5 +916,6 @@
 struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
 					const u8 *key, size_t len);
 void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
 
 #endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 783b293..47b6ebb 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -2168,4 +2168,10 @@
 	}
 }
 
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+	return crypto_ec_prime_len(ecdh->ec);
+}
+
 #endif /* CONFIG_ECC */
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 85ce565..dc68bd6 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -1834,4 +1834,10 @@
 	goto done;
 }
 
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+	return crypto_ec_prime_len(ecdh->ec);
+}
+
 #endif /* CONFIG_ECC */
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index b55e976..17af964 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -28,10 +28,10 @@
 {
 	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[32];
-	const u8 *_addr[6];
-	size_t _len[6], i;
+	const u8 *_addr[11];
+	size_t _len[11], i;
 
-	if (num_elem > 5) {
+	if (num_elem > 10) {
 		/*
 		 * Fixed limit on the number of fragments to avoid having to
 		 * allocate memory (which could fail).
diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c
index ee136ce..fd84b82 100644
--- a/src/crypto/sha384.c
+++ b/src/crypto/sha384.c
@@ -28,10 +28,10 @@
 {
 	unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[48];
-	const u8 *_addr[6];
-	size_t _len[6], i;
+	const u8 *_addr[11];
+	size_t _len[11], i;
 
-	if (num_elem > 5) {
+	if (num_elem > 10) {
 		/*
 		 * Fixed limit on the number of fragments to avoid having to
 		 * allocate memory (which could fail).
diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c
index 66311c3..f60a576 100644
--- a/src/crypto/sha512.c
+++ b/src/crypto/sha512.c
@@ -28,10 +28,10 @@
 {
 	unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[64];
-	const u8 *_addr[6];
-	size_t _len[6], i;
+	const u8 *_addr[11];
+	size_t _len[11], i;
 
-	if (num_elem > 5) {
+	if (num_elem > 10) {
 		/*
 		 * Fixed limit on the number of fragments to avoid having to
 		 * allocate memory (which could fail).
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 84ec985..7ee371a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2208,6 +2208,7 @@
 		else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
 			tod = 2; /* TOD-TOFU */
 	}
+	sk_POLICYINFO_pop_free(ext, POLICYINFO_free);
 
 	return tod;
 }
@@ -4926,6 +4927,76 @@
 #endif /* HAVE_OCSP */
 
 
+static size_t max_str_len(const char **lines)
+{
+	const char **p;
+	size_t max_len = 0;
+
+	for (p = lines; *p; p++) {
+		size_t len = os_strlen(*p);
+
+		if (len > max_len)
+			max_len = len;
+	}
+
+	return max_len;
+}
+
+
+static int match_lines_in_file(const char *path, const char **lines)
+{
+	FILE *f;
+	char *buf;
+	size_t bufsize;
+	int found = 0, is_linestart = 1;
+
+	bufsize = max_str_len(lines) + sizeof("\r\n");
+	buf = os_malloc(bufsize);
+	if (!buf)
+		return 0;
+
+	f = fopen(path, "r");
+	if (!f) {
+		os_free(buf);
+		return 0;
+	}
+
+	while (!found && fgets(buf, bufsize, f)) {
+		int is_lineend;
+		size_t len;
+		const char **p;
+
+		len = strcspn(buf, "\r\n");
+		is_lineend = buf[len] != '\0';
+		buf[len] = '\0';
+
+		if (is_linestart && is_lineend) {
+			for (p = lines; !found && *p; p++)
+				found = os_strcmp(buf, *p) == 0;
+		}
+		is_linestart = is_lineend;
+	}
+
+	fclose(f);
+	bin_clear_free(buf, bufsize);
+
+	return found;
+}
+
+
+static int is_tpm2_key(const char *path)
+{
+	/* Check both new and old format of TPM2 PEM guard tag */
+	static const char *tpm2_tags[] = {
+		"-----BEGIN TSS2 PRIVATE KEY-----",
+		"-----BEGIN TSS2 KEY BLOB-----",
+		NULL
+	};
+
+	return match_lines_in_file(path, tpm2_tags);
+}
+
+
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 			      const struct tls_connection_params *params)
 {
@@ -4978,6 +5049,17 @@
 	if (can_pkcs11 == 2 && !engine_id)
 		engine_id = "pkcs11";
 
+	/* If private_key points to a TPM2-wrapped key, automatically enable
+	 * tpm2 engine and use it to unwrap the key. */
+	if (params->private_key &&
+	    (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
+	    is_tpm2_key(params->private_key)) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
+			   params->private_key);
+		key_id = key_id ? key_id : params->private_key;
+		engine_id = engine_id ? engine_id : "tpm2";
+	}
+
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 	if (params->flags & TLS_CONN_EAP_FAST) {
@@ -5009,7 +5091,8 @@
 	}
 
 	if (engine_id) {
-		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s",
+			   engine_id);
 		ret = tls_engine_init(conn, engine_id, params->pin,
 				      key_id, cert_id, ca_cert_id);
 		if (ret)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index f0e2a6f..032bbd8 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -182,6 +182,7 @@
 	struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM];
 };
 
+#define HE_MAC_CAPAB_0		0
 #define HE_MAX_MAC_CAPAB_SIZE	6
 #define HE_MAX_PHY_CAPAB_SIZE	11
 #define HE_MAX_MCS_CAPAB_SIZE	12
@@ -1095,6 +1096,13 @@
 	const struct ieee80211_vht_capabilities *vhtcaps_mask;
 #endif /* CONFIG_VHT_OVERRIDES */
 
+#ifdef CONFIG_HE_OVERRIDES
+	/**
+	 * disable_he - Disable HE for this connection
+	 */
+	int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
 	/**
 	 * req_key_mgmt_offload - Request key management offload for connection
 	 *
@@ -1402,14 +1410,6 @@
 	u8 p2p_go_ctwindow;
 
 	/**
-	 * smps_mode - SMPS mode
-	 *
-	 * SMPS mode to be used by the AP, specified as the relevant bits of
-	 * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
-	 */
-	unsigned int smps_mode;
-
-	/**
 	 * disable_dgaf - Whether group-addressed frames are disabled
 	 */
 	int disable_dgaf;
@@ -1487,6 +1487,26 @@
 	 * he_spr_srg_obss_pd_max_offset - Maximum TX power offset
 	 */
 	 int he_spr_srg_obss_pd_max_offset;
+
+	/**
+	 * he_bss_color - Whether the BSS Color is disabled
+	 */
+	int he_bss_color_disabled;
+
+	/**
+	 * he_bss_color_partial - The BSS Color AID equation
+	 */
+	int he_bss_color_partial;
+
+	/**
+	 * he_bss_color - The BSS Color of the AP
+	 */
+	int he_bss_color;
+
+	/**
+	 * twt_responder - Whether Target Wait Time responder is enabled
+	 */
+	int twt_responder;
 };
 
 struct wpa_driver_mesh_bss_params {
@@ -1524,6 +1544,120 @@
 	unsigned int flags;
 };
 
+struct wpa_driver_set_key_params {
+	/**
+	 * ifname - Interface name (for multi-SSID/VLAN support) */
+	const char *ifname;
+
+	/**
+	 * alg - Encryption algorithm
+	 *
+	 * (%WPA_ALG_NONE, %WPA_ALG_WEP, %WPA_ALG_TKIP, %WPA_ALG_CCMP,
+	 * %WPA_ALG_IGTK, %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
+	 * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, %WPA_ALG_BIP_CMAC_256);
+	 * %WPA_ALG_NONE clears the key. */
+	enum wpa_alg alg;
+
+	/**
+	 * addr - Address of the peer STA
+	 *
+	 * (BSSID of the current AP when setting pairwise key in station mode),
+	 * ff:ff:ff:ff:ff:ff for broadcast keys, %NULL for default keys that
+	 * are used both for broadcast and unicast; when clearing keys, %NULL
+	 * is used to indicate that both the broadcast-only and default key of
+	 * the specified key index is to be cleared */
+	const u8 *addr;
+
+	/**
+	 * key_idx - Key index
+	 *
+	 * (0..3), usually 0 for unicast keys; 4..5 for IGTK; 6..7 for BIGTK */
+	int key_idx;
+
+	/**
+	 * set_tx - Configure this key as the default Tx key
+	 *
+	 * Only used when driver does not support separate unicast/individual
+	 * key */
+	int set_tx;
+
+	/**
+	 * seq - Sequence number/packet number
+	 *
+	 * seq_len octets, the next packet number to be used for in replay
+	 * protection; configured for Rx keys (in most cases, this is only used
+	 * with broadcast keys and set to zero for unicast keys); %NULL if not
+	 * set */
+	const u8 *seq;
+
+	/**
+	 * seq_len - Length of the seq, depends on the algorithm
+	 *
+	 * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets */
+	size_t seq_len;
+
+	/**
+	 * key - Key buffer
+	 *
+	 * TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key */
+	const u8 *key;
+
+	/**
+	 * key_len - Length of the key buffer in octets
+	 *
+	 * WEP: 5 or 13, TKIP: 32, CCMP/GCMP: 16, IGTK: 16 */
+	size_t key_len;
+
+	/**
+	 * vlan_id - VLAN index (0..4095) for VLAN offload cases */
+	int vlan_id;
+
+	/**
+	 * key_flag - Additional key flags
+	 *
+	 * %KEY_FLAG_MODIFY
+	 *  Set when an already installed key must be updated.
+	 *  So far the only use-case is changing RX/TX status for
+	 *  pairwise keys. Must not be set when deleting a key.
+	 * %KEY_FLAG_DEFAULT
+	 *  Set when the key is also a default key. Must not be set when
+	 *  deleting a key.
+	 * %KEY_FLAG_RX
+	 *  The key is valid for RX. Must not be set when deleting a key.
+	 * %KEY_FLAG_TX
+	 *  The key is valid for TX. Must not be set when deleting a key.
+	 * %KEY_FLAG_GROUP
+	 *  The key is a broadcast or group key.
+	 * %KEY_FLAG_PAIRWISE
+	 *  The key is a pairwise key.
+	 * %KEY_FLAG_PMK
+	 *  The key is a Pairwise Master Key (PMK).
+	 *
+	 * Valid and pre-defined combinations are:
+	 * %KEY_FLAG_GROUP_RX_TX
+	 *  WEP key not to be installed as default key.
+	 * %KEY_FLAG_GROUP_RX_TX_DEFAULT
+	 *  Default WEP or WPA-NONE key.
+	 * %KEY_FLAG_GROUP_RX
+	 *  GTK key valid for RX only.
+	 * %KEY_FLAG_GROUP_TX_DEFAULT
+	 *  GTK key valid for TX only, immediately taking over TX.
+	 * %KEY_FLAG_PAIRWISE_RX_TX
+	 *  Pairwise key immediately becoming the active pairwise key.
+	 * %KEY_FLAG_PAIRWISE_RX
+	 *  Pairwise key not yet valid for TX. (Only usable when Extended
+	 *  Key ID is supported by the driver.)
+	 * %KEY_FLAG_PAIRWISE_RX_TX_MODIFY
+	 *  Enable TX for a pairwise key installed with
+	 *  KEY_FLAG_PAIRWISE_RX.
+	 *
+	 * Not a valid standalone key type but pre-defined to be combined
+	 * with other key_flags:
+	 * %KEY_FLAG_RX_TX
+	 *  RX/TX key. */
+	enum key_flag key_flag;
+};
+
 /**
  * struct wpa_driver_capa - Driver capability information
  */
@@ -1577,7 +1711,7 @@
 /** Driver takes care of all DFS operations */
 #define WPA_DRIVER_FLAGS_DFS_OFFLOAD			0x00000004
 /** Driver takes care of RSN 4-way handshake internally; PMK is configured with
- * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+ * struct wpa_driver_ops::set_key using key_flag = KEY_FLAG_PMK */
 #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X		0x00000008
 /** Driver is for a wired Ethernet interface */
 #define WPA_DRIVER_FLAGS_WIRED		0x00000010
@@ -1704,15 +1838,23 @@
 #define WPA_DRIVER_FLAGS_FTM_RESPONDER		0x0100000000000000ULL
 /** Driver support 4-way handshake offload for WPA-Personal */
 #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK	0x0200000000000000ULL
+/** Driver supports a separate control port for EAPOL frames */
+#define WPA_DRIVER_FLAGS_CONTROL_PORT		0x0400000000000000ULL
+/** Driver supports VLAN offload */
+#define WPA_DRIVER_FLAGS_VLAN_OFFLOAD		0x0800000000000000ULL
+/** Driver supports UPDATE_FT_IES command */
+#define WPA_DRIVER_FLAGS_UPDATE_FT_IES		0x1000000000000000ULL
+/** Driver can correctly rekey PTKs without Extended Key ID */
+#define WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS	0x2000000000000000ULL
+/** Driver supports Beacon protection */
+#define WPA_DRIVER_FLAGS_BEACON_PROTECTION	0x4000000000000000ULL
+/** Driver supports Extended Key ID */
+#define WPA_DRIVER_FLAGS_EXTENDED_KEY_ID	0x8000000000000000ULL
 	u64 flags;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
 	(drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE)
 
-#define WPA_DRIVER_SMPS_MODE_STATIC			0x00000001
-#define WPA_DRIVER_SMPS_MODE_DYNAMIC			0x00000002
-	unsigned int smps_modes;
-
 	unsigned int wmm_ac_supported:1;
 
 	unsigned int mac_addr_rand_scan_supported:1;
@@ -2194,6 +2336,9 @@
 
 	/* ACS frequency list info */
 	const int *freq_list;
+
+	/* Indicates whether EDMG is enabled */
+	int edmg_enabled;
 };
 
 struct wpa_bss_trans_info {
@@ -2219,6 +2364,8 @@
 	const u8 *pmkid;
 	const u8 *pmk;
 	size_t pmk_len;
+	u32 pmk_lifetime;
+	u8 pmk_reauth_threshold;
 };
 
 /* Mask used to specify which connection parameters have to be updated */
@@ -2305,35 +2452,8 @@
 
 	/**
 	 * set_key - Configure encryption key
-	 * @ifname: Interface name (for multi-SSID/VLAN support)
 	 * @priv: private driver interface data
-	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
-	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
-	 *	%WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
-	 *	%WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256,
-	 *	%WPA_ALG_BIP_CMAC_256);
-	 *	%WPA_ALG_NONE clears the key.
-	 * @addr: Address of the peer STA (BSSID of the current AP when setting
-	 *	pairwise key in station mode), ff:ff:ff:ff:ff:ff for
-	 *	broadcast keys, %NULL for default keys that are used both for
-	 *	broadcast and unicast; when clearing keys, %NULL is used to
-	 *	indicate that both the broadcast-only and default key of the
-	 *	specified key index is to be cleared
-	 * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
-	 *	IGTK
-	 * @set_tx: configure this key as the default Tx key (only used when
-	 *	driver does not support separate unicast/individual key
-	 * @seq: sequence number/packet number, seq_len octets, the next
-	 *	packet number to be used for in replay protection; configured
-	 *	for Rx keys (in most cases, this is only used with broadcast
-	 *	keys and set to zero for unicast keys); %NULL if not set
-	 * @seq_len: length of the seq, depends on the algorithm:
-	 *	TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
-	 * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
-	 *	8-byte Rx Mic Key
-	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
-	 *	TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
-	 *
+	 * @params: Key parameters
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * Configure the given key for the kernel driver. If the driver
@@ -2354,10 +2474,7 @@
 	 * in driver_*.c set_key() implementation, see driver_ndis.c for an
 	 * example on how this can be done.
 	 */
-	int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
-		       const u8 *addr, int key_idx, int set_tx,
-		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
+	int (*set_key)(void *priv, struct wpa_driver_set_key_params *params);
 
 	/**
 	 * init - Initialize driver interface
@@ -2609,11 +2726,15 @@
 	 * driver decide
 	 * @csa_offs: Array of CSA offsets or %NULL
 	 * @csa_offs_len: Number of elements in csa_offs
+	 * @no_encrypt: Do not encrypt frame even if appropriate key exists
+	 *	(used only for testing purposes)
+	 * @wait: Time to wait off-channel for a response (in ms), or zero
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
 			 int noack, unsigned int freq, const u16 *csa_offs,
-			 size_t csa_offs_len);
+			 size_t csa_offs_len, int no_encrypt,
+			 unsigned int wait);
 
 	/**
 	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2868,6 +2989,33 @@
 			     const u8 *addr);
 
 	/**
+	 * tx_control_port - Send a frame over the 802.1X controlled port
+	 * @priv: Private driver interface data
+	 * @dest: Destination MAC address
+	 * @proto: Ethertype in host byte order
+	 * @buf: Frame payload starting from IEEE 802.1X header
+	 * @len: Frame payload length
+	 * @no_encrypt: Do not encrypt frame
+	 *
+	 * Returns 0 on success, else an error
+	 *
+	 * This is like a normal Ethernet send except that the driver is aware
+	 * (by other means than the Ethertype) that this frame is special,
+	 * and more importantly it gains an ordering between the transmission of
+	 * the frame and other driver management operations such as key
+	 * installations. This can be used to work around known limitations in
+	 * IEEE 802.11 protocols such as race conditions between rekeying 4-way
+	 * handshake message 4/4 and a PTK being overwritten.
+	 *
+	 * This function is only used for a given interface if the driver
+	 * instance reports WPA_DRIVER_FLAGS_CONTROL_PORT capability. Otherwise,
+	 * API users will fall back to sending the frame via a normal socket.
+	 */
+	int (*tx_control_port)(void *priv, const u8 *dest,
+			       u16 proto, const u8 *buf, size_t len,
+			       int no_encrypt);
+
+	/**
 	 * hapd_send_eapol - Send an EAPOL packet (AP only)
 	 * @priv: private driver interface data
 	 * @addr: Destination MAC address
@@ -3113,19 +3261,6 @@
 	int (*commit)(void *priv);
 
 	/**
-	 * send_ether - Send an ethernet packet (AP only)
-	 * @priv: private driver interface data
-	 * @dst: Destination MAC address
-	 * @src: Source MAC address
-	 * @proto: Ethertype
-	 * @data: EAPOL packet starting with IEEE 802.1X header
-	 * @data_len: Length of the EAPOL packet in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
-			  const u8 *data, size_t data_len);
-
-	/**
 	 * set_radius_acl_auth - Notification of RADIUS ACL change
 	 * @priv: Private driver interface data
 	 * @mac: MAC address of the station
@@ -3348,20 +3483,6 @@
 	int (*signal_monitor)(void *priv, int threshold, int hysteresis);
 
 	/**
-	 * send_frame - Send IEEE 802.11 frame (testing use only)
-	 * @priv: Private driver interface data
-	 * @data: IEEE 802.11 frame with IEEE 802.11 header
-	 * @data_len: Size of the frame
-	 * @encrypt: Whether to encrypt the frame (if keys are set)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only used for debugging purposes and is not
-	 * required to be implemented for normal operations.
-	 */
-	int (*send_frame)(void *priv, const u8 *data, size_t data_len,
-			  int encrypt);
-
-	/**
 	 * get_noa - Get current Notice of Absence attribute payload
 	 * @priv: Private driver interface data
 	 * @buf: Buffer for returning NoA
@@ -3513,6 +3634,12 @@
 				unsigned int val);
 
 	/**
+	 * get_wowlan - Get wake-on-wireless status
+	 * @priv: Private driver interface data
+	 */
+	int (*get_wowlan)(void *priv);
+
+	/**
 	 * set_wowlan - Set wake-on-wireless triggers
 	 * @priv: Private driver interface data
 	 * @triggers: wowlan triggers
@@ -4843,6 +4970,15 @@
 	  * EVENT_UPDATE_DH - Notification of updated DH information
 	  */
 	EVENT_UPDATE_DH,
+
+	/**
+	 * EVENT_UNPROT_BEACON - Unprotected Beacon frame received
+	 *
+	 * This event should be called when a Beacon frame is dropped due to it
+	 * not being protected correctly. union wpa_event_data::unprot_beacon
+	 * is required to provide more details of the frame.
+	 */
+	EVENT_UNPROT_BEACON,
 };
 
 
@@ -5609,8 +5745,17 @@
 	 * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
 	 * @pri_freq: Selected primary frequency
 	 * @sec_freq: Selected secondary frequency
+	 * @edmg_channel: Selected EDMG channel
 	 * @vht_seg0_center_ch: VHT mode Segment0 center channel
+	 *	The value is the index of the channel center frequency for
+	 *	20 MHz, 40 MHz, and 80 MHz channels. The value is the center
+	 *	frequency index of the primary 80 MHz segment for 160 MHz and
+	 *	80+80 MHz channels.
 	 * @vht_seg1_center_ch: VHT mode Segment1 center channel
+	 *	The value is zero for 20 MHz, 40 MHz, and 80 MHz channels. The
+	 *	value is the index of the channel center frequency for 160 MHz
+	 *	channels and the center frequency index of the secondary 80 MHz
+	 *	segment for 80+80 MHz channels.
 	 * @ch_width: Selected Channel width by driver. Driver may choose to
 	 *	change hostapd configured ACS channel width due driver internal
 	 *	channel restrictions.
@@ -5619,6 +5764,7 @@
 	struct acs_selected_channels {
 		unsigned int pri_freq;
 		unsigned int sec_freq;
+		u8 edmg_channel;
 		u8 vht_seg0_center_ch;
 		u8 vht_seg1_center_ch;
 		u16 ch_width;
@@ -5685,6 +5831,13 @@
 		const u8 *ie;
 		size_t ie_len;
 	} update_dh;
+
+	/**
+	 * struct unprot_beacon - Data for EVENT_UNPROT_BEACON
+	 */
+	struct unprot_beacon {
+		const u8 *sa;
+	} unprot_beacon;
 };
 
 /**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index eac3ae8..d630c3d 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -492,14 +492,18 @@
 }
 
 static int
-atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-		const u8 *addr, int key_idx, int set_tx, const u8 *seq,
-		size_t seq_len, const u8 *key, size_t key_len)
+atheros_set_key(void *priv, struct wpa_driver_set_key_params *params)
 {
 	struct atheros_driver_data *drv = priv;
 	struct ieee80211req_key wk;
 	u_int8_t cipher;
 	int ret;
+	enum wpa_alg alg = params->alg;
+	const u8 *addr = params->addr;
+	int key_idx = params->key_idx;
+	int set_tx = params->set_tx;
+	const u8 *key = params->key;
+	size_t key_len = params->key_len;
 
 	if (alg == WPA_ALG_NONE)
 		return atheros_del_key(drv, addr, key_idx);
@@ -1960,7 +1964,8 @@
 
 static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
 			     int noack, unsigned int freq,
-			     const u16 *csa_offs, size_t csa_offs_len)
+			     const u16 *csa_offs, size_t csa_offs_len,
+			     int no_encrypt, unsigned int wait)
 {
 	struct atheros_driver_data *drv = priv;
 	u8 buf[1510];
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 8667ee5..b4400d7 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -9,7 +9,6 @@
 
 #include "includes.h"
 #include <sys/ioctl.h>
-#include <sys/sysctl.h>
 
 #include "common.h"
 #include "driver.h"
@@ -51,22 +50,19 @@
 	void		*ctx;
 	int		sock;			/* socket for 802.11 ioctls */
 	int		route;			/* routing socket for events */
-	char		*event_buf;
-	size_t		event_buf_len;
 	struct dl_list	ifaces;			/* list of interfaces */
 };
 
 struct bsd_driver_data {
 	struct dl_list	list;
 	struct bsd_driver_global *global;
-	struct hostapd_data *hapd;	/* back pointer */
+	void	*ctx;
 
 	struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
 	char	ifname[IFNAMSIZ+1];	/* interface name */
 	int	flags;
 	unsigned int ifindex;		/* interface index */
 	int	if_removed;		/* has the interface been removed? */
-	void	*ctx;
 	struct wpa_driver_capa capa;	/* driver capability */
 	int	is_ap;			/* Access point mode */
 	int	prev_roaming;	/* roaming state to restore on deinit */
@@ -90,7 +86,6 @@
 	return NULL;
 }
 
-#ifndef HOSTAPD
 static struct bsd_driver_data *
 bsd_get_drvname(void *priv, const char *ifname)
 {
@@ -103,7 +98,6 @@
 	}
 	return NULL;
 }
-#endif /* HOSTAPD */
 
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
@@ -295,9 +289,8 @@
 }
 
 static int
-bsd_ctrl_iface(void *priv, int enable)
+bsd_get_iface_flags(struct bsd_driver_data *drv)
 {
-	struct bsd_driver_data *drv = priv;
 	struct ifreq ifr;
 
 	os_memset(&ifr, 0, sizeof(ifr));
@@ -309,36 +302,24 @@
 		return -1;
 	}
 	drv->flags = ifr.ifr_flags;
-
-	if (enable) {
-		if (ifr.ifr_flags & IFF_UP)
-			return 0;
-		ifr.ifr_flags |= IFF_UP;
-	} else {
-		if (!(ifr.ifr_flags & IFF_UP))
-			return 0;
-		ifr.ifr_flags &= ~IFF_UP;
-	}
-
-	if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
-		wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
-			   strerror(errno));
-		return -1;
-	}
-
-	drv->flags = ifr.ifr_flags;
 	return 0;
 }
 
 static int
-bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
-	    size_t seq_len, const u8 *key, size_t key_len)
+bsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
 {
 	struct ieee80211req_key wk;
 #ifdef IEEE80211_KEY_NOREPLAY
 	struct bsd_driver_data *drv = priv;
 #endif /* IEEE80211_KEY_NOREPLAY */
+	enum wpa_alg alg = params->alg;
+	const u8 *addr = params->addr;
+	int key_idx = params->key_idx;
+	int set_tx = params->set_tx;
+	const u8 *seq = params->seq;
+	size_t seq_len = params->seq_len;
+	const u8 *key = params->key;
+	size_t key_len = params->key_len;
 
 	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
 		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -540,7 +521,7 @@
 			   __func__);
 		return -1;
 	}
-	return bsd_ctrl_iface(priv, 1);
+	return 0;
 }
 
 static void
@@ -595,17 +576,13 @@
 
 	if (channel < 14) {
 		mode =
-#ifdef CONFIG_IEEE80211N
 			freq->ht_enabled ? IFM_IEEE80211_11NG :
-#endif /* CONFIG_IEEE80211N */
-		        IFM_IEEE80211_11G;
+			IFM_IEEE80211_11G;
 	} else if (channel == 14) {
 		mode = IFM_IEEE80211_11B;
 	} else {
 		mode =
-#ifdef CONFIG_IEEE80211N
 			freq->ht_enabled ? IFM_IEEE80211_11NA :
-#endif /* CONFIG_IEEE80211N */
 			IFM_IEEE80211_11A;
 	}
 	if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
@@ -636,20 +613,152 @@
 	return 0;
 }
 
-static size_t
-rtbuf_len(void)
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
-	size_t len;
+	char event_buf[2048]; /* max size of a single route(4) msg */
+	struct bsd_driver_global *global = sock_ctx;
+	struct bsd_driver_data *drv;
+	struct if_announcemsghdr *ifan;
+	struct if_msghdr *ifm;
+	struct rt_msghdr *rtm;
+	union wpa_event_data event;
+	struct ieee80211_michael_event *mic;
+	struct ieee80211_leave_event *leave;
+	struct ieee80211_join_event *join;
+	int n;
 
-	int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
-		wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
-			   strerror(errno));
-		len = 2048;
+	n = read(sock, event_buf, sizeof(event_buf));
+	if (n < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			wpa_printf(MSG_ERROR, "%s read() failed: %s",
+				   __func__, strerror(errno));
+		return;
 	}
 
-	return len;
+	rtm = (struct rt_msghdr *) event_buf;
+	if (rtm->rtm_version != RTM_VERSION) {
+		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+			   rtm->rtm_version);
+		return;
+	}
+	os_memset(&event, 0, sizeof(event));
+	switch (rtm->rtm_type) {
+	case RTM_IEEE80211:
+		ifan = (struct if_announcemsghdr *) rtm;
+		drv = bsd_get_drvindex(global, ifan->ifan_index);
+		if (drv == NULL)
+			return;
+		switch (ifan->ifan_what) {
+		case RTM_IEEE80211_ASSOC:
+		case RTM_IEEE80211_REASSOC:
+			if (drv->is_ap)
+				break;
+			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+			break;
+		case RTM_IEEE80211_DISASSOC:
+			if (drv->is_ap)
+				break;
+			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+			break;
+		case RTM_IEEE80211_SCAN:
+			if (drv->is_ap)
+				break;
+			wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+					     NULL);
+			break;
+		case RTM_IEEE80211_LEAVE:
+			leave = (struct ieee80211_leave_event *) &ifan[1];
+			drv_event_disassoc(drv->ctx, leave->iev_addr);
+			break;
+		case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+		case RTM_IEEE80211_REJOIN:
+#endif
+			join = (struct ieee80211_join_event *) &ifan[1];
+			bsd_new_sta(drv, drv->ctx, join->iev_addr);
+			break;
+		case RTM_IEEE80211_REPLAY:
+			/* ignore */
+			break;
+		case RTM_IEEE80211_MICHAEL:
+			mic = (struct ieee80211_michael_event *) &ifan[1];
+			wpa_printf(MSG_DEBUG,
+				"Michael MIC failure wireless event: "
+				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+				MAC2STR(mic->iev_src));
+			os_memset(&event, 0, sizeof(event));
+			event.michael_mic_failure.unicast =
+				!IEEE80211_IS_MULTICAST(mic->iev_dst);
+			event.michael_mic_failure.src = mic->iev_src;
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_MICHAEL_MIC_FAILURE, &event);
+			break;
+		}
+		break;
+	case RTM_IFANNOUNCE:
+		ifan = (struct if_announcemsghdr *) rtm;
+		switch (ifan->ifan_what) {
+		case IFAN_DEPARTURE:
+			drv = bsd_get_drvindex(global, ifan->ifan_index);
+			if (drv)
+				drv->if_removed = 1;
+			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+			break;
+		case IFAN_ARRIVAL:
+			drv = bsd_get_drvname(global, ifan->ifan_name);
+			if (drv) {
+				drv->ifindex = ifan->ifan_index;
+				drv->if_removed = 0;
+			}
+			event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
+			   ifan->ifan_name,
+			   ifan->ifan_what == IFAN_DEPARTURE ?
+				"removed" : "added");
+		os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
+			   sizeof(event.interface_status.ifname));
+		if (drv) {
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+					     &event);
+			/*
+			 * Set ifindex to zero after sending the event as the
+			 * event might query the driver to ensure a match.
+			 */
+			if (ifan->ifan_what == IFAN_DEPARTURE)
+				drv->ifindex = 0;
+		} else {
+			wpa_supplicant_event_global(global->ctx,
+						    EVENT_INTERFACE_STATUS,
+						    &event);
+		}
+		break;
+	case RTM_IFINFO:
+		ifm = (struct if_msghdr *) rtm;
+		drv = bsd_get_drvindex(global, ifm->ifm_index);
+		if (drv == NULL)
+			return;
+		if ((ifm->ifm_flags & IFF_UP) == 0 &&
+		    (drv->flags & IFF_UP) != 0) {
+			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+				   drv->ifname);
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+					     NULL);
+		} else if ((ifm->ifm_flags & IFF_UP) != 0 &&
+		    (drv->flags & IFF_UP) == 0) {
+			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+				   drv->ifname);
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+					     NULL);
+		}
+		drv->flags = ifm->ifm_flags;
+		break;
+	}
 }
 
 #ifdef HOSTAPD
@@ -770,80 +879,10 @@
 }
 
 static void
-bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
-{
-	struct bsd_driver_global *global = sock_ctx;
-	struct bsd_driver_data *drv;
-	struct if_announcemsghdr *ifan;
-	struct rt_msghdr *rtm;
-	struct ieee80211_michael_event *mic;
-	struct ieee80211_join_event *join;
-	struct ieee80211_leave_event *leave;
-	int n;
-	union wpa_event_data data;
-
-	n = read(sock, global->event_buf, global->event_buf_len);
-	if (n < 0) {
-		if (errno != EINTR && errno != EAGAIN)
-			wpa_printf(MSG_ERROR, "%s read() failed: %s",
-				   __func__, strerror(errno));
-		return;
-	}
-
-	rtm = (struct rt_msghdr *) global->event_buf;
-	if (rtm->rtm_version != RTM_VERSION) {
-		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
-			   rtm->rtm_version);
-		return;
-	}
-	switch (rtm->rtm_type) {
-	case RTM_IEEE80211:
-		ifan = (struct if_announcemsghdr *) rtm;
-		drv = bsd_get_drvindex(global, ifan->ifan_index);
-		if (drv == NULL)
-			return;
-		switch (ifan->ifan_what) {
-		case RTM_IEEE80211_ASSOC:
-		case RTM_IEEE80211_REASSOC:
-		case RTM_IEEE80211_DISASSOC:
-		case RTM_IEEE80211_SCAN:
-			break;
-		case RTM_IEEE80211_LEAVE:
-			leave = (struct ieee80211_leave_event *) &ifan[1];
-			drv_event_disassoc(drv->hapd, leave->iev_addr);
-			break;
-		case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
-		case RTM_IEEE80211_REJOIN:
-#endif
-			join = (struct ieee80211_join_event *) &ifan[1];
-			bsd_new_sta(drv, drv->hapd, join->iev_addr);
-			break;
-		case RTM_IEEE80211_REPLAY:
-			/* ignore */
-			break;
-		case RTM_IEEE80211_MICHAEL:
-			mic = (struct ieee80211_michael_event *) &ifan[1];
-			wpa_printf(MSG_DEBUG,
-				"Michael MIC failure wireless event: "
-				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
-				MAC2STR(mic->iev_src));
-			os_memset(&data, 0, sizeof(data));
-			data.michael_mic_failure.unicast = 1;
-			data.michael_mic_failure.src = mic->iev_src;
-			wpa_supplicant_event(drv->hapd,
-					     EVENT_MICHAEL_MIC_FAILURE, &data);
-			break;
-		}
-		break;
-	}
-}
-
-static void
 handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
 {
 	struct bsd_driver_data *drv = ctx;
-	drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
+	drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
 }
 
 static void *
@@ -864,7 +903,8 @@
 		goto bad;
 	}
 
-	drv->hapd = hapd;
+	drv->ctx = hapd;
+	drv->is_ap = 1;
 	drv->global = params->global_priv;
 	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
 
@@ -875,8 +915,7 @@
 	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
 		goto bad;
 
-	/* mark down during setup */
-	if (bsd_ctrl_iface(drv, 0) < 0)
+	if (bsd_get_iface_flags(drv) < 0)
 		goto bad;
 
 	if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
@@ -901,8 +940,6 @@
 {
 	struct bsd_driver_data *drv = priv;
 
-	if (drv->ifindex != 0)
-		bsd_ctrl_iface(drv, 0);
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
 	os_free(drv);
@@ -910,13 +947,6 @@
 
 
 static int
-bsd_commit(void *priv)
-{
-	return bsd_ctrl_iface(priv, 1);
-}
-
-
-static int
 bsd_set_sta_authorized(void *priv, const u8 *addr,
 		       unsigned int total_flags, unsigned int flags_or,
 		       unsigned int flags_and)
@@ -1169,8 +1199,11 @@
 	}
 
 	/* NB: interface must be marked UP to do a scan */
-	if (bsd_ctrl_iface(drv, 1) < 0)
+	if (!(drv->flags & IFF_UP)) {
+		wpa_printf(MSG_DEBUG, "%s: interface is not up, cannot scan",
+			   __func__);
 		return -1;
+	}
 
 #ifdef IEEE80211_IOC_SCAN_MAX_SSID
 	os_memset(&sr, 0, sizeof(sr));
@@ -1208,153 +1241,6 @@
 }
 
 static void
-wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
-{
-	struct bsd_driver_global *global = sock_ctx;
-	struct bsd_driver_data *drv;
-	struct if_announcemsghdr *ifan;
-	struct if_msghdr *ifm;
-	struct rt_msghdr *rtm;
-	union wpa_event_data event;
-	struct ieee80211_michael_event *mic;
-	struct ieee80211_leave_event *leave;
-	struct ieee80211_join_event *join;
-	int n;
-
-	n = read(sock, global->event_buf, global->event_buf_len);
-	if (n < 0) {
-		if (errno != EINTR && errno != EAGAIN)
-			wpa_printf(MSG_ERROR, "%s read() failed: %s",
-				   __func__, strerror(errno));
-		return;
-	}
-
-	rtm = (struct rt_msghdr *) global->event_buf;
-	if (rtm->rtm_version != RTM_VERSION) {
-		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
-			   rtm->rtm_version);
-		return;
-	}
-	os_memset(&event, 0, sizeof(event));
-	switch (rtm->rtm_type) {
-	case RTM_IFANNOUNCE:
-		ifan = (struct if_announcemsghdr *) rtm;
-		switch (ifan->ifan_what) {
-		case IFAN_DEPARTURE:
-			drv = bsd_get_drvindex(global, ifan->ifan_index);
-			if (drv)
-				drv->if_removed = 1;
-			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
-			break;
-		case IFAN_ARRIVAL:
-			drv = bsd_get_drvname(global, ifan->ifan_name);
-			if (drv) {
-				drv->ifindex = ifan->ifan_index;
-				drv->if_removed = 0;
-			}
-			event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-			break;
-		default:
-			wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
-			return;
-		}
-		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
-			   ifan->ifan_name,
-			   ifan->ifan_what == IFAN_DEPARTURE ?
-				"removed" : "added");
-		os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
-			   sizeof(event.interface_status.ifname));
-		if (drv) {
-			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
-					     &event);
-			/*
-			 * Set ifindex to zero after sending the event as the
-			 * event might query the driver to ensure a match.
-			 */
-			if (ifan->ifan_what == IFAN_DEPARTURE)
-				drv->ifindex = 0;
-		} else {
-			wpa_supplicant_event_global(global->ctx,
-						    EVENT_INTERFACE_STATUS,
-						    &event);
-		}
-		break;
-	case RTM_IEEE80211:
-		ifan = (struct if_announcemsghdr *) rtm;
-		drv = bsd_get_drvindex(global, ifan->ifan_index);
-		if (drv == NULL)
-			return;
-		switch (ifan->ifan_what) {
-		case RTM_IEEE80211_ASSOC:
-		case RTM_IEEE80211_REASSOC:
-			if (drv->is_ap)
-				break;
-			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-			break;
-		case RTM_IEEE80211_DISASSOC:
-			if (drv->is_ap)
-				break;
-			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-			break;
-		case RTM_IEEE80211_SCAN:
-			if (drv->is_ap)
-				break;
-			wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
-					     NULL);
-			break;
-		case RTM_IEEE80211_LEAVE:
-			leave = (struct ieee80211_leave_event *) &ifan[1];
-			drv_event_disassoc(drv->ctx, leave->iev_addr);
-			break;
-		case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
-		case RTM_IEEE80211_REJOIN:
-#endif
-			join = (struct ieee80211_join_event *) &ifan[1];
-			bsd_new_sta(drv, drv->ctx, join->iev_addr);
-			break;
-		case RTM_IEEE80211_REPLAY:
-			/* ignore */
-			break;
-		case RTM_IEEE80211_MICHAEL:
-			mic = (struct ieee80211_michael_event *) &ifan[1];
-			wpa_printf(MSG_DEBUG,
-				"Michael MIC failure wireless event: "
-				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
-				MAC2STR(mic->iev_src));
-
-			os_memset(&event, 0, sizeof(event));
-			event.michael_mic_failure.unicast =
-				!IEEE80211_IS_MULTICAST(mic->iev_dst);
-			wpa_supplicant_event(drv->ctx,
-					     EVENT_MICHAEL_MIC_FAILURE, &event);
-			break;
-		}
-		break;
-	case RTM_IFINFO:
-		ifm = (struct if_msghdr *) rtm;
-		drv = bsd_get_drvindex(global, ifm->ifm_index);
-		if (drv == NULL)
-			return;
-		if ((ifm->ifm_flags & IFF_UP) == 0 &&
-		    (drv->flags & IFF_UP) != 0) {
-			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
-				   drv->ifname);
-			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
-					     NULL);
-		} else if ((ifm->ifm_flags & IFF_UP) != 0 &&
-		    (drv->flags & IFF_UP) == 0) {
-			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
-				   drv->ifname);
-			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
-					     NULL);
-		}
-		drv->flags = ifm->ifm_flags;
-		break;
-	}
-}
-
-static void
 wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
 			      struct ieee80211req_scan_result *sr)
 {
@@ -1570,12 +1456,6 @@
 	if (drv == NULL)
 		return NULL;
 
-	/*
-	 * NB: We require the interface name be mappable to an index.
-	 *     This implies we do not support having wpa_supplicant
-	 *     wait for an interface to appear.  This seems ok; that
-	 *     doesn't belong here; it's really the job of devd.
-	 */
 	drv->ifindex = if_nametoindex(ifname);
 	if (drv->ifindex == 0) {
 		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
@@ -1607,7 +1487,7 @@
 		goto fail;
 
 	/* Down interface during setup. */
-	if (bsd_ctrl_iface(drv, 0) < 0)
+	if (bsd_get_iface_flags(drv) < 0)
 		goto fail;
 
 	drv->opmode = get80211opmode(drv);
@@ -1628,9 +1508,6 @@
 	if (drv->ifindex != 0 && !drv->if_removed) {
 		wpa_driver_bsd_set_wpa(drv, 0);
 
-		/* NB: mark interface down */
-		bsd_ctrl_iface(drv, 0);
-
 		wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
 						drv->prev_privacy);
 
@@ -1664,9 +1541,7 @@
 #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
 	unsigned char msgfilter[] = {
 		RTM_IEEE80211,
-#ifndef HOSTAPD
 		RTM_IFINFO, RTM_IFANNOUNCE,
-#endif
 	};
 #endif
 #ifdef ROUTE_MSGFILTER
@@ -1709,22 +1584,9 @@
 			   strerror(errno));
 #endif
 
-	global->event_buf_len = rtbuf_len();
-	global->event_buf = os_malloc(global->event_buf_len);
-	if (global->event_buf == NULL) {
-		wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
-		goto fail;
-	}
-
-#ifdef HOSTAPD
 	eloop_register_read_sock(global->route, bsd_wireless_event_receive,
 				 NULL, global);
 
-#else /* HOSTAPD */
-	eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
-				 NULL, global);
-#endif /* HOSTAPD */
-
 	return global;
 
 fail:
@@ -1761,7 +1623,6 @@
 	.sta_disassoc		= bsd_sta_disassoc,
 	.sta_deauth		= bsd_sta_deauth,
 	.sta_set_flags		= bsd_set_sta_authorized,
-	.commit			= bsd_commit,
 #else /* HOSTAPD */
 	.init2			= wpa_driver_bsd_init,
 	.deinit			= wpa_driver_bsd_deinit,
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 731c6a3..63846db 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -89,6 +89,7 @@
 	E2S(INTERFACE_MAC_CHANGED);
 	E2S(WDS_STA_INTERFACE_STATUS);
 	E2S(UPDATE_DH);
+	E2S(UNPROT_BEACON);
 	}
 
 	return "UNKNOWN";
@@ -308,6 +309,14 @@
 	DF2S(OCE_AP);
 	DF2S(OCE_STA_CFON);
 	DF2S(MFP_OPTIONAL);
+	DF2S(SELF_MANAGED_REGULATORY);
+	DF2S(FTM_RESPONDER);
+	DF2S(CONTROL_PORT);
+	DF2S(VLAN_OFFLOAD);
+	DF2S(UPDATE_FT_IES);
+	DF2S(SAFE_PTK0_REKEYS);
+	DF2S(BEACON_PROTECTION);
+	DF2S(EXTENDED_KEY_ID);
 	}
 	return "UNKNOWN";
 #undef DF2S
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 186eccb..b9c42e4 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -263,7 +263,8 @@
 
 static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
 			    unsigned int freq,
-			    const u16 *csa_offs, size_t csa_offs_len)
+			    const u16 *csa_offs, size_t csa_offs_len,
+			    int no_encrypt, unsigned int wait)
 {
 	struct hostap_driver_data *drv = priv;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -312,7 +313,7 @@
 	pos += 2;
 	memcpy(pos, data, data_len);
 
-	res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0);
+	res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0, 0);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
 			   "failed: %d (%s)",
@@ -395,17 +396,20 @@
 }
 
 
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
-				     enum wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx,
-				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
+static int wpa_driver_hostap_set_key(void *priv,
+				     struct wpa_driver_set_key_params *params)
 {
 	struct hostap_driver_data *drv = priv;
 	struct prism2_hostapd_param *param;
 	u8 *buf;
 	size_t blen;
 	int ret = 0;
+	enum wpa_alg alg = params->alg;
+	const u8 *addr = params->addr;
+	int key_idx = params->key_idx;
+	int set_tx = params->set_tx;
+	const u8 *key = params->key;
+	size_t key_len = params->key_len;
 
 	blen = sizeof(*param) + key_len;
 	buf = os_zalloc(blen);
@@ -1051,7 +1055,7 @@
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.deauth.reason_code = host_to_le16(reason);
 	return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				sizeof(mgmt.u.deauth), 0, 0, NULL, 0);
+				sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0, 0);
 }
 
 
@@ -1089,7 +1093,7 @@
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.disassoc.reason_code = host_to_le16(reason);
 	return  hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				 sizeof(mgmt.u.disassoc), 0, 0, NULL, 0);
+				 sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0, 0);
 }
 
 
@@ -1169,7 +1173,7 @@
 	os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
 	os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
-	hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0);
+	hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0, 0);
 }
 
 
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index e922503..5319ba2 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -54,8 +54,6 @@
 	struct nl_sock *sk;
 	struct macsec_genl_ctx ctx;
 
-	struct netlink_data *netlink;
-	struct nl_handle *nl;
 	char ifname[IFNAMSIZ + 1];
 	int ifi;
 	int parent_ifi;
@@ -321,14 +319,14 @@
 	if (err < 0) {
 		wpa_printf(MSG_ERROR, DRV_PREFIX
 			   "Unable to connect NETLINK_ROUTE socket: %s",
-			   strerror(errno));
+			   nl_geterror(err));
 		goto sock;
 	}
 
 	err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
 	if (err < 0) {
 		wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
-			   strerror(errno));
+			   nl_geterror(err));
 		goto sock;
 	}
 
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 5b4b924..529fc3b 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -1034,6 +1034,18 @@
 
 
 static int
+wpa_driver_ndis_set_key_wrapper(void *priv,
+				struct wpa_driver_set_key_params *params)
+{
+	return wpa_driver_ndis_set_key(params->ifname, priv,
+				       params->alg, params->addr,
+				       params->key_idx, params->set_tx,
+				       params->seq, params->seq_len,
+				       params->key, params->key_len);
+}
+
+
+static int
 wpa_driver_ndis_associate(void *priv,
 			  struct wpa_driver_associate_params *params)
 {
@@ -3195,7 +3207,7 @@
 	wpa_driver_ndis_ops.desc = ndis_drv_desc;
 	wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
 	wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
-	wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+	wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key_wrapper;
 	wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
 	wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
 	wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b7efb6a..3b7c31c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -66,48 +66,6 @@
 #define SOL_NETLINK 270
 #endif
 
-#ifndef CONFIG_LIBNL20
-/*
- * libnl 1.1 has a bug, it tries to allocate socket numbers densely
- * but when you free a socket again it will mess up its bitmap and
- * and use the wrong number the next time it needs a socket ID.
- * Therefore, we wrap the handle alloc/destroy and add our own pid
- * accounting.
- */
-static uint32_t port_bitmap[32] = { 0 };
-
-static struct nl_handle *nl80211_handle_alloc(void *cb)
-{
-	struct nl_handle *handle;
-	uint32_t pid = getpid() & 0x3FFFFF;
-	int i;
-
-	handle = nl_handle_alloc_cb(cb);
-
-	for (i = 0; i < 1024; i++) {
-		if (port_bitmap[i / 32] & (1 << (i % 32)))
-			continue;
-		port_bitmap[i / 32] |= 1 << (i % 32);
-		pid += i << 22;
-		break;
-	}
-
-	nl_socket_set_local_port(handle, pid);
-
-	return handle;
-}
-
-static void nl80211_handle_destroy(struct nl_handle *handle)
-{
-	uint32_t port = nl_socket_get_local_port(handle);
-
-	port >>= 22;
-	port_bitmap[port / 32] &= ~(1 << (port % 32));
-
-	nl_handle_destroy(handle);
-}
-#endif /* CONFIG_LIBNL20 */
-
 
 #ifdef ANDROID
 /* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
@@ -117,11 +75,11 @@
 #endif /* ANDROID */
 
 
-static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
 {
-	struct nl_handle *handle;
+	struct nl_sock *handle;
 
-	handle = nl80211_handle_alloc(cb);
+	handle = nl_socket_alloc_cb(cb);
 	if (handle == NULL) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
 			   "callbacks (%s)", dbg);
@@ -131,7 +89,7 @@
 	if (genl_connect(handle)) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
 			   "netlink (%s)", dbg);
-		nl80211_handle_destroy(handle);
+		nl_socket_free(handle);
 		return NULL;
 	}
 
@@ -139,11 +97,11 @@
 }
 
 
-static void nl_destroy_handles(struct nl_handle **handle)
+static void nl_destroy_handles(struct nl_sock **handle)
 {
 	if (*handle == NULL)
 		return;
-	nl80211_handle_destroy(*handle);
+	nl_socket_free(*handle);
 	*handle = NULL;
 }
 
@@ -154,11 +112,10 @@
 #define ELOOP_SOCKET_INVALID	(intptr_t) 0x88888889ULL
 #endif
 
-static void nl80211_register_eloop_read(struct nl_handle **handle,
+static void nl80211_register_eloop_read(struct nl_sock **handle,
 					eloop_sock_handler handler,
 					void *eloop_data, int persist)
 {
-#ifdef CONFIG_LIBNL20
 	/*
 	 * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
 	 * by default. It is possible to hit that limit in some cases where
@@ -166,13 +123,15 @@
 	 * to hostapd and STA entry deletion. Try to increase the buffer to make
 	 * this less likely to occur.
 	 */
-	if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+	int err;
+
+	err = nl_socket_set_buffer_size(*handle, 262144, 0);
+	if (err < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Could not set nl_socket RX buffer size: %s",
-			   strerror(errno));
+			   nl_geterror(err));
 		/* continue anyway with the default (smaller) buffer */
 	}
-#endif /* CONFIG_LIBNL20 */
 
 	nl_socket_set_nonblocking(*handle);
 	eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
@@ -183,7 +142,7 @@
 }
 
 
-static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist)
+static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
 {
 	if (!persist)
 		*handle = (void *) (((intptr_t) *handle) ^
@@ -206,7 +165,8 @@
 				   const char *driver_params);
 static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  unsigned int freq, unsigned int wait,
-				  const u8 *buf, size_t buf_len, u64 *cookie,
+				  const u8 *buf, size_t buf_len,
+				  int save_cookie,
 				  int no_cck, int no_ack, int offchanok,
 				  const u16 *csa_offs, size_t csa_offs_len);
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
@@ -391,7 +351,7 @@
 
 
 static int send_and_recv(struct nl80211_global *global,
-			 struct nl_handle *nl_handle, struct nl_msg *msg,
+			 struct nl_sock *nl_handle, struct nl_msg *msg,
 			 int (*valid_handler)(struct nl_msg *, void *),
 			 void *valid_data)
 {
@@ -416,8 +376,16 @@
 		   NETLINK_CAP_ACK, &opt, sizeof(opt));
 
 	err = nl_send_auto_complete(nl_handle, msg);
-	if (err < 0)
+	if (err < 0) {
+		wpa_printf(MSG_INFO,
+			   "nl80211: nl_send_auto_complete() failed: %s",
+			   nl_geterror(err));
+		/* Need to convert libnl error code to an errno value. For now,
+		 * just hardcode this to EBADF; the real error reason is shown
+		 * in that error print above. */
+		err = -EBADF;
 		goto out;
+	}
 
 	err = 1;
 
@@ -431,10 +399,24 @@
 
 	while (err > 0) {
 		int res = nl_recvmsgs(nl_handle, cb);
-		if (res < 0) {
+
+		if (res == -NLE_DUMP_INTR) {
+			/* Most likely one of the nl80211 dump routines hit a
+			 * case where internal results changed while the dump
+			 * was being sent. The most common known case for this
+			 * is scan results fetching while associated were every
+			 * received Beacon frame from the AP may end up
+			 * incrementing bss_generation. This
+			 * NL80211_CMD_GET_SCAN case tries again in the caller;
+			 * other cases (of which there are no known common ones)
+			 * will stop and return an error. */
+			wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
+				   nl_geterror(res));
+			err = -EAGAIN;
+		} else if (res < 0) {
 			wpa_printf(MSG_INFO,
-				   "nl80211: %s->nl_recvmsgs failed: %d",
-				   __func__, res);
+				   "nl80211: %s->nl_recvmsgs failed: %d (%s)",
+				   __func__, res, nl_geterror(res));
 		}
 	}
  out:
@@ -1065,7 +1047,7 @@
 	while (RTA_OK(attr, attrlen)) {
 		switch (attr->rta_type) {
 		case IFLA_IFNAME:
-			if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+			if (RTA_PAYLOAD(attr) > IFNAMSIZ)
 				break;
 			os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
 			ifname[RTA_PAYLOAD(attr)] = '\0';
@@ -1240,7 +1222,7 @@
 	while (RTA_OK(attr, attrlen)) {
 		switch (attr->rta_type) {
 		case IFLA_IFNAME:
-			if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+			if (RTA_PAYLOAD(attr) > IFNAMSIZ)
 				break;
 			os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
 			ifname[RTA_PAYLOAD(attr)] = '\0';
@@ -1369,12 +1351,25 @@
 	struct nl_msg *msg;
 	int ret;
 	struct nl80211_get_assoc_freq_arg arg;
+	int count = 0;
 
+try_again:
 	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	os_memset(&arg, 0, sizeof(arg));
 	arg.drv = drv;
 	ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
 				 &arg);
+	if (ret == -EAGAIN) {
+		count++;
+		if (count >= 10) {
+			wpa_printf(MSG_INFO,
+				   "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
+			goto try_again;
+		}
+	}
 	if (ret == 0) {
 		os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
 		return arg.assoc_ssid_len;
@@ -1390,12 +1385,25 @@
 	struct nl_msg *msg;
 	int ret;
 	struct nl80211_get_assoc_freq_arg arg;
+	int count = 0;
 
+try_again:
 	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	os_memset(&arg, 0, sizeof(arg));
 	arg.drv = drv;
 	ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
 				 &arg);
+	if (ret == -EAGAIN) {
+		count++;
+		if (count >= 10) {
+			wpa_printf(MSG_INFO,
+				   "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
+			goto try_again;
+		}
+	}
 	if (ret == 0) {
 		unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
 			arg.ibss_freq : arg.assoc_freq;
@@ -1733,7 +1741,7 @@
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
 			   "membership for scan events: %d (%s)",
-			   ret, strerror(-ret));
+			   ret, nl_geterror(ret));
 		goto err;
 	}
 
@@ -1743,7 +1751,7 @@
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
 			   "membership for mlme events: %d (%s)",
-			   ret, strerror(-ret));
+			   ret, nl_geterror(ret));
 		goto err;
 	}
 
@@ -1753,7 +1761,7 @@
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
 			   "membership for regulatory events: %d (%s)",
-			   ret, strerror(-ret));
+			   ret, nl_geterror(ret));
 		/* Continue without regulatory events */
 	}
 
@@ -1763,7 +1771,7 @@
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
 			   "membership for vendor events: %d (%s)",
-			   ret, strerror(-ret));
+			   ret, nl_geterror(ret));
 		/* Continue without vendor events */
 	}
 
@@ -1789,7 +1797,7 @@
 
 static void nl80211_check_global(struct nl80211_global *global)
 {
-	struct nl_handle *handle;
+	struct nl_sock *handle;
 	const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
 	int ret;
 	unsigned int i;
@@ -1808,7 +1816,7 @@
 		if (ret < 0) {
 			wpa_printf(MSG_INFO,
 				   "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
-				   groups[i], ret, strerror(-ret));
+				   groups[i], ret, nl_geterror(ret));
 		}
 	}
 }
@@ -2087,7 +2095,7 @@
 
 
 static int nl80211_register_frame(struct i802_bss *bss,
-				  struct nl_handle *nl_handle,
+				  struct nl_sock *nl_handle,
 				  u16 type, const u8 *match, size_t match_len)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2100,7 +2108,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
 		   type, fc2str(type), nl_handle, buf);
 
-	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) ||
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
 	    nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
 	    nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
 		nlmsg_free(msg);
@@ -2174,6 +2182,7 @@
 static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
+	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
 	int ret = 0;
 
 	if (nl80211_alloc_mgmt_handle(bss))
@@ -2181,13 +2190,14 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
 		   "handle %p", bss->nl_mgmt);
 
-	if (drv->nlmode == NL80211_IFTYPE_ADHOC ||
-	    ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
-	     !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) {
-		u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
-
+	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
 		/* register for any AUTH message */
 		nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+	} else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+		   !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+		/* register for SAE Authentication frames */
+		nl80211_register_frame(bss, bss->nl_mgmt, type,
+				       (u8 *) "\x03\x00", 2);
 	}
 
 #ifdef CONFIG_INTERWORKING
@@ -2757,7 +2767,7 @@
 	}
 
 	if (drv->rtnl_sk)
-		nl80211_handle_destroy(drv->rtnl_sk);
+		nl_socket_free(drv->rtnl_sk);
 
 	if (bss->added_bridge) {
 		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
@@ -2873,7 +2883,6 @@
 	case WPA_ALG_KRK:
 		return RSN_CIPHER_SUITE_KRK;
 	case WPA_ALG_NONE:
-	case WPA_ALG_PMK:
 		wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
 			   alg);
 		return 0;
@@ -2934,6 +2943,40 @@
 }
 
 
+static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
+				  int max_suites)
+{
+	int num_suites = 0;
+
+#define __AKM(a, b) \
+	if (num_suites < max_suites && \
+	    (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
+		suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
+	__AKM(IEEE8021X, UNSPEC_802_1X);
+	__AKM(PSK, PSK_OVER_802_1X);
+	__AKM(FT_IEEE8021X, FT_802_1X);
+	__AKM(FT_PSK, FT_PSK);
+	__AKM(IEEE8021X_SHA256, 802_1X_SHA256);
+	__AKM(PSK_SHA256, PSK_SHA256);
+	__AKM(SAE, SAE);
+	__AKM(FT_SAE, FT_SAE);
+	__AKM(CCKM, CCKM);
+	__AKM(OSEN, OSEN);
+	__AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
+	__AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
+	__AKM(FILS_SHA256, FILS_SHA256);
+	__AKM(FILS_SHA384, FILS_SHA384);
+	__AKM(FT_FILS_SHA256, FT_FILS_SHA256);
+	__AKM(FT_FILS_SHA384, FT_FILS_SHA384);
+	__AKM(OWE, OWE);
+	__AKM(DPP, DPP);
+	__AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
+#undef __AKM
+
+	return num_suites;
+}
+
+
 #ifdef CONFIG_DRIVER_NL80211_QCA
 static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
 				  const u8 *key, size_t key_len)
@@ -3003,18 +3046,26 @@
 }
 
 
-static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
-				      enum wpa_alg alg, const u8 *addr,
-				      int key_idx, int set_tx,
-				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
+static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
+				      struct wpa_driver_set_key_params *params)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifindex;
 	struct nl_msg *msg;
 	struct nl_msg *key_msg;
 	int ret;
-	int tdls = 0;
+	int skip_set_key = 1;
+	const char *ifname = params->ifname;
+	enum wpa_alg alg = params->alg;
+	const u8 *addr = params->addr;
+	int key_idx = params->key_idx;
+	int set_tx = params->set_tx;
+	const u8 *seq = params->seq;
+	size_t seq_len = params->seq_len;
+	const u8 *key = params->key;
+	size_t key_len = params->key_len;
+	int vlan_id = params->vlan_id;
+	enum key_flag key_flag = params->key_flag;
 
 	/* Ignore for P2P Device */
 	if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
@@ -3022,18 +3073,17 @@
 
 	ifindex = if_nametoindex(ifname);
 	wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
-		   "set_tx=%d seq_len=%lu key_len=%lu",
+		   "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
 		   __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-#ifdef CONFIG_TDLS
-	if (key_idx == -1) {
-		key_idx = 0;
-		tdls = 1;
+		   (unsigned long) seq_len, (unsigned long) key_len, key_flag);
+
+	if (check_key_flag(key_flag)) {
+		wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
+		return -EINVAL;
 	}
-#endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_DRIVER_NL80211_QCA
-	if (alg == WPA_ALG_PMK &&
+	if ((key_flag & KEY_FLAG_PMK) &&
 	    (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
 		wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
 			   __func__);
@@ -3042,15 +3092,33 @@
 	}
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
-	if (alg == WPA_ALG_PMK &&
-	    (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
-		return nl80211_set_pmk(drv, key, key_len, addr);
+	if (key_flag & KEY_FLAG_PMK) {
+		if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
+			return nl80211_set_pmk(drv, key, key_len, addr);
+		/* The driver does not have any offload mechanism for PMK, so
+		 * there is no need to configure this key. */
+		return 0;
+	}
 
+	ret = -ENOBUFS;
 	key_msg = nlmsg_alloc();
 	if (!key_msg)
-		return -ENOBUFS;
+		return ret;
 
-	if (alg == WPA_ALG_NONE) {
+	if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+	    KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: SET_KEY (pairwise RX/TX modify)");
+		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+		if (!msg)
+			goto fail2;
+	} else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
+		wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
+			   __func__);
+		ret = -EINVAL;
+		goto fail2;
+	} else if (alg == WPA_ALG_NONE) {
+		wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
 		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
 		if (!msg)
 			goto fail2;
@@ -3058,8 +3126,11 @@
 		u32 suite;
 
 		suite = wpa_alg_to_cipher_suite(alg, key_len);
-		if (!suite)
+		if (!suite) {
+			ret = -EINVAL;
 			goto fail2;
+		}
+		wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
 		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
 		if (!msg)
 			goto fail2;
@@ -3067,12 +3138,13 @@
 		    nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
 			goto fail;
 		wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
-	}
 
-	if (seq && seq_len) {
-		if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
-			goto fail;
-		wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
+		if (seq && seq_len) {
+			if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
+				goto fail;
+			wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
+				    seq, seq_len);
+		}
 	}
 
 	if (addr && !is_broadcast_ether_addr(addr)) {
@@ -3080,22 +3152,42 @@
 		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
 			goto fail;
 
-		if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
+		if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+		    KEY_FLAG_PAIRWISE_RX ||
+		    (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+		    KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+			if (nla_put_u8(key_msg, NL80211_KEY_MODE,
+				       key_flag == KEY_FLAG_PAIRWISE_RX ?
+				       NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
+				goto fail;
+		} else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
+			   KEY_FLAG_GROUP_RX) {
 			wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
 			if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
 					NL80211_KEYTYPE_GROUP))
 				goto fail;
-		}
-	} else if (addr && is_broadcast_ether_addr(addr)) {
-		struct nlattr *types;
-
-		wpa_printf(MSG_DEBUG, "   broadcast key");
-
-		types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
-		if (!types ||
-		    nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+		} else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
+			wpa_printf(MSG_DEBUG,
+				   "   key_flag missing PAIRWISE when setting a pairwise key");
+			ret = -EINVAL;
 			goto fail;
-		nla_nest_end(key_msg, types);
+		} else if (alg == WPA_ALG_WEP &&
+			   (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
+			wpa_printf(MSG_DEBUG, "   unicast WEP key");
+			skip_set_key = 0;
+		} else {
+			wpa_printf(MSG_DEBUG, "   pairwise key");
+		}
+	} else if ((key_flag & KEY_FLAG_PAIRWISE) ||
+		   !(key_flag & KEY_FLAG_GROUP)) {
+		wpa_printf(MSG_DEBUG,
+			   "   invalid key_flag for a broadcast key");
+		ret = -EINVAL;
+		goto fail;
+	} else {
+		wpa_printf(MSG_DEBUG, "   broadcast key");
+		if (key_flag & KEY_FLAG_DEFAULT)
+			skip_set_key = 0;
 	}
 	if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
 	    nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
@@ -3104,26 +3196,31 @@
 	nlmsg_free(key_msg);
 	key_msg = NULL;
 
+	if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+		wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
+		if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+			goto fail;
+	}
+
 	ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
 	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
 		ret = 0;
 	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
+		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
 			   ret, strerror(-ret));
 
 	/*
-	 * If we failed or don't need to set the default TX key (below),
+	 * If we failed or don't need to set the key as default (below),
 	 * we're done here.
 	 */
-	if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
+	if (ret || skip_set_key)
 		return ret;
-	if (is_ap_interface(drv->nlmode) && addr &&
-	    !is_broadcast_ether_addr(addr))
-		return ret;
+	wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
 
+	ret = -ENOBUFS;
 	key_msg = nlmsg_alloc();
 	if (!key_msg)
-		return -ENOBUFS;
+		return ret;
 
 	msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
 	if (!msg)
@@ -3134,8 +3231,10 @@
 				   alg == WPA_ALG_BIP_GMAC_128 ||
 				   alg == WPA_ALG_BIP_GMAC_256 ||
 				   alg == WPA_ALG_BIP_CMAC_256) ?
-				   NL80211_KEY_DEFAULT_MGMT :
-				   NL80211_KEY_DEFAULT))
+			 (key_idx == 6 || key_idx == 7 ?
+			  NL80211_KEY_DEFAULT_BEACON :
+			  NL80211_KEY_DEFAULT_MGMT) :
+			 NL80211_KEY_DEFAULT))
 		goto fail;
 	if (addr && is_broadcast_ether_addr(addr)) {
 		struct nlattr *types;
@@ -3161,12 +3260,18 @@
 	nlmsg_free(key_msg);
 	key_msg = NULL;
 
+	if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+		wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
+			   vlan_id);
+		if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+			goto fail;
+	}
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret == -ENOENT)
-		ret = 0;
 	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
-			   "err=%d %s)", ret, strerror(-ret));
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: set_key default failed; err=%d %s",
+			   ret, strerror(-ret));
 	return ret;
 
 fail:
@@ -3175,7 +3280,7 @@
 fail2:
 	nl80211_nlmsg_clear(key_msg);
 	nlmsg_free(key_msg);
-	return -ENOBUFS;
+	return ret;
 }
 
 
@@ -3271,7 +3376,7 @@
 int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 			    const u8 *addr, int cmd, u16 reason_code,
 			    int local_state_change,
-			    struct nl_handle *nl_connect)
+			    struct nl_sock *nl_connect)
 {
 	int ret;
 	struct nl_msg *msg;
@@ -3300,7 +3405,7 @@
 
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
 					 u16 reason_code,
-					 struct nl_handle *nl_connect)
+					 struct nl_sock *nl_connect)
 {
 	int ret;
 	int drv_associated = drv->associated;
@@ -3332,7 +3437,7 @@
 		return nl80211_leave_ibss(drv, 1);
 	}
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
-		struct nl_handle *nl_connect = NULL;
+		struct nl_sock *nl_connect = NULL;
 
 		if (bss->use_nl_connect)
 			nl_connect = bss->nl_connect;
@@ -3450,6 +3555,7 @@
 	enum nl80211_iftype nlmode;
 	int count = 0;
 	int is_retry;
+	struct wpa_driver_set_key_params p;
 
 	nl80211_unmask_11b_rates(bss);
 
@@ -3478,14 +3584,20 @@
 	if (!msg)
 		goto fail;
 
+	os_memset(&p, 0, sizeof(p));
+	p.ifname = bss->ifname;
+	p.alg = WPA_ALG_WEP;
 	for (i = 0; i < 4; i++) {
 		if (!params->wep_key[i])
 			continue;
-		wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
-					   NULL, i,
-					   i == params->wep_tx_keyidx, NULL, 0,
-					   params->wep_key[i],
-					   params->wep_key_len[i]);
+		p.key_idx = i;
+		p.set_tx = i == params->wep_tx_keyidx;
+		p.key = params->wep_key[i];
+		p.key_len = params->wep_key_len[i];
+		p.key_flag = i == params->wep_tx_keyidx ?
+			KEY_FLAG_GROUP_RX_TX_DEFAULT :
+			KEY_FLAG_GROUP_RX_TX;
+		wpa_driver_nl80211_set_key(bss, &p);
 		if (params->wep_tx_keyidx != i)
 			continue;
 		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
@@ -3647,80 +3759,27 @@
 }
 
 
-static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
-					 const void *data, size_t len,
-					 int encrypt, int noack,
-					 unsigned int freq, int no_cck,
-					 int offchanok, unsigned int wait_time,
-					 const u16 *csa_offs,
-					 size_t csa_offs_len)
-{
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	u64 cookie;
-	int res;
-
-	if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
-		freq = nl80211_get_assoc_freq(drv);
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: send_frame - Use assoc_freq=%u for IBSS",
-			   freq);
-	}
-	if (freq == 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
-			   bss->freq);
-		freq = bss->freq;
-	}
-
-	if (drv->use_monitor) {
-		wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
-			   freq, bss->freq);
-		return nl80211_send_monitor(drv, data, len, encrypt, noack);
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
-	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
-				     &cookie, no_cck, noack, offchanok,
-				     csa_offs, csa_offs_len);
-	if (res == 0 && !noack) {
-		const struct ieee80211_mgmt *mgmt;
-		u16 fc;
-
-		mgmt = (const struct ieee80211_mgmt *) data;
-		fc = le_to_host16(mgmt->frame_control);
-		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
-			wpa_printf(MSG_MSGDUMP,
-				   "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
-				   (long long unsigned int)
-				   drv->send_action_cookie,
-				   (long long unsigned int) cookie);
-			drv->send_action_cookie = cookie;
-		}
-	}
-
-	return res;
-}
-
-
 static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 					size_t data_len, int noack,
 					unsigned int freq, int no_cck,
 					int offchanok,
 					unsigned int wait_time,
 					const u16 *csa_offs,
-					size_t csa_offs_len)
+					size_t csa_offs_len, int no_encrypt)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct ieee80211_mgmt *mgmt;
-	int encrypt = 1;
+	int encrypt = !no_encrypt;
 	u16 fc;
+	int use_cookie = 1;
+	int res;
 
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
-	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR
-		   " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x (%s) nlmode=%d",
+	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
+		   " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
 		   MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
-		   fc, fc2str(fc), drv->nlmode);
+		   no_encrypt, fc, fc2str(fc), drv->nlmode);
 
 	if ((is_sta_interface(drv->nlmode) ||
 	     drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
@@ -3736,9 +3795,11 @@
 				   drv->last_mgmt_freq);
 			freq = drv->last_mgmt_freq;
 		}
-		return nl80211_send_frame_cmd(bss, freq, 0,
-					      data, data_len, NULL, 1, noack,
-					      1, csa_offs, csa_offs_len);
+		wait_time = 0;
+		use_cookie = 0;
+		no_cck = 1;
+		offchanok = 1;
+		goto send_frame_cmd;
 	}
 
 	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
@@ -3747,13 +3808,9 @@
 				   bss->freq);
 			freq = bss->freq;
 		}
-		return nl80211_send_frame_cmd(bss, freq,
-					      (int) freq == bss->freq ? 0 :
-					      wait_time,
-					      data, data_len,
-					      &drv->send_action_cookie,
-					      no_cck, noack, offchanok,
-					      csa_offs, csa_offs_len);
+		if ((int) freq == bss->freq)
+			wait_time = 0;
+		goto send_frame_cmd;
 	}
 
 	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3770,11 +3827,60 @@
 			encrypt = 0;
 	}
 
-	wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
-	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
-					     noack, freq, no_cck, offchanok,
-					     wait_time, csa_offs,
-					     csa_offs_len);
+	if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION &&
+	    (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+		freq = nl80211_get_assoc_freq(drv);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: send_mlme - Use assoc_freq=%u for external auth",
+			   freq);
+	}
+
+	if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
+		freq = nl80211_get_assoc_freq(drv);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
+			   freq);
+	}
+	if (freq == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
+			   bss->freq);
+		freq = bss->freq;
+	}
+
+	if (drv->use_monitor) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
+			   freq, bss->freq);
+		return nl80211_send_monitor(drv, data, data_len, encrypt,
+					    noack);
+	}
+
+	if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
+		use_cookie = 0;
+send_frame_cmd:
+#ifdef CONFIG_TESTING_OPTIONS
+	if (no_encrypt && !encrypt && !drv->use_monitor) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
+		if (nl80211_create_monitor_interface(drv) < 0)
+			return -1;
+		res = nl80211_send_monitor(drv, data, data_len, encrypt,
+					   noack);
+		nl80211_remove_monitor_interface(drv);
+		return res;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
+	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
+				     use_cookie, no_cck, noack, offchanok,
+				     csa_offs, csa_offs_len);
+
+	return res;
 }
 
 
@@ -4076,8 +4182,7 @@
 	int ret = -ENOBUFS;
 	int beacon_set;
 	int num_suites;
-	int smps_mode;
-	u32 suites[10], suite;
+	u32 suites[20], suite;
 	u32 ver;
 #ifdef CONFIG_MESH
 	struct wpa_driver_mesh_bss_params mesh_params;
@@ -4171,14 +4276,15 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
 		   params->key_mgmt_suites);
-	num_suites = 0;
-	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
-		suites[num_suites++] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
-	if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
-		suites[num_suites++] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
-	if (num_suites &&
-	    nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
-		    suites))
+	num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
+					    suites, ARRAY_SIZE(suites));
+	if (num_suites > NL80211_MAX_NR_AKM_SUITES)
+		wpa_printf(MSG_WARNING,
+			   "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
+			   num_suites);
+	else if (num_suites &&
+		 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+			 suites))
 		goto fail;
 
 	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
@@ -4209,27 +4315,6 @@
 	    nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
 		goto fail;
 
-	if (params->ht_opmode != -1) {
-		switch (params->smps_mode) {
-		case HT_CAP_INFO_SMPS_DYNAMIC:
-			wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
-			smps_mode = NL80211_SMPS_DYNAMIC;
-			break;
-		case HT_CAP_INFO_SMPS_STATIC:
-			wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
-			smps_mode = NL80211_SMPS_STATIC;
-			break;
-		default:
-			/* invalid - fallback to smps off */
-		case HT_CAP_INFO_SMPS_DISABLED:
-			wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
-			smps_mode = NL80211_SMPS_OFF;
-			break;
-		}
-		if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
-			goto fail;
-	}
-
 	if (params->beacon_ies) {
 		wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
 				params->beacon_ies);
@@ -4314,7 +4399,8 @@
 		spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
 		wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
 
-		if (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+		if (!spr ||
+		    nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
 			       params->he_spr_srg_obss_pd_min_offset) ||
 		    nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
 			       params->he_spr_srg_obss_pd_max_offset))
@@ -4322,6 +4408,28 @@
 
 		nla_nest_end(msg, spr);
 	}
+
+	if (params->freq && params->freq->he_enabled) {
+		struct nlattr *bss_color;
+
+		bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
+		if (!bss_color ||
+		    (params->he_bss_color_disabled &&
+		     nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
+		    (params->he_bss_color_partial &&
+		     nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
+		    nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
+			       params->he_bss_color))
+			goto fail;
+		nla_nest_end(msg, bss_color);
+	}
+
+	if (params->twt_responder) {
+		wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
+			   params->twt_responder);
+		if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
+			goto fail;
+	}
 #endif /* CONFIG_IEEE80211AX */
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -5101,6 +5209,40 @@
 }
 
 
+static int nl80211_tx_control_port(void *priv, const u8 *dest,
+				   u16 proto, const u8 *buf, size_t len,
+				   int no_encrypt)
+{
+	struct i802_bss *bss = priv;
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Send over control port dest=" MACSTR
+		   " proto=0x%04x len=%u no_encrypt=%d",
+		   MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
+
+	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
+	if (!msg ||
+	    nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
+	    nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
+	    (no_encrypt &&
+	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
+
+	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+	if (ret)
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: tx_control_port failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+
+	return ret;
+}
+
+
 static int nl80211_send_eapol_data(struct i802_bss *bss,
 				   const u8 *addr, const u8 *data,
 				   size_t data_len)
@@ -5143,6 +5285,10 @@
 	int res;
 	int qos = flags & WPA_STA_WMM;
 
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+		return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
+					       data, data_len, !encrypt);
+
 	if (drv->device_ap_sme || !drv->use_monitor)
 		return nl80211_send_eapol_data(bss, addr, data, data_len);
 
@@ -5183,12 +5329,11 @@
 	pos += 2;
 	memcpy(pos, data, data_len);
 
-	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
-					    0, 0, 0, 0, NULL, 0);
+	res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
 	if (res < 0) {
-		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
-			   "failed: %d (%s)",
-			   (unsigned long) len, errno, strerror(errno));
+		wpa_printf(MSG_ERROR,
+			   "hapd_send_eapol - packet len: %lu - failed",
+			   (unsigned long) len);
 	}
 	os_free(hdr);
 
@@ -5775,7 +5920,7 @@
 static int wpa_driver_nl80211_try_connect(
 	struct wpa_driver_nl80211_data *drv,
 	struct wpa_driver_associate_params *params,
-	struct nl_handle *nl_connect)
+	struct nl_sock *nl_connect)
 {
 	struct nl_msg *msg;
 	enum nl80211_auth_type type;
@@ -5866,7 +6011,7 @@
 static int wpa_driver_nl80211_connect(
 	struct wpa_driver_nl80211_data *drv,
 	struct wpa_driver_associate_params *params,
-	struct nl_handle *nl_connect)
+	struct nl_sock *nl_connect)
 {
 	int ret;
 
@@ -5914,7 +6059,7 @@
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
 		enum nl80211_iftype nlmode = params->p2p ?
 			NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
-		struct nl_handle *nl_connect = NULL;
+		struct nl_sock *nl_connect = NULL;
 
 		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 			return -1;
@@ -6646,6 +6791,8 @@
 		   MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
 	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
 	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+	    ((drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
+	     nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
 	    nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
@@ -6718,7 +6865,7 @@
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
 					    sizeof(mgmt.u.deauth), 0, 0, 0, 0,
-					    0, NULL, 0);
+					    0, NULL, 0, 0);
 }
 
 
@@ -6745,7 +6892,7 @@
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
 					    sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
-					    0, NULL, 0);
+					    0, NULL, 0, 0);
 }
 
 
@@ -7078,15 +7225,18 @@
 
 #ifdef CONFIG_LIBNL3_ROUTE
 	if (bss->added_if_into_bridge || bss->already_in_bridge) {
+		int err;
+
 		drv->rtnl_sk = nl_socket_alloc();
 		if (drv->rtnl_sk == NULL) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
 			goto failed;
 		}
 
-		if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) {
+		err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
+		if (err) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
-				   strerror(errno));
+				   nl_geterror(err));
 			goto failed;
 		}
 	}
@@ -7460,7 +7610,7 @@
 static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len,
-				  u64 *cookie_out, int no_cck, int no_ack,
+				  int save_cookie, int no_cck, int no_ack,
 				  int offchanok, const u16 *csa_offs,
 				  size_t csa_offs_len)
 {
@@ -7499,22 +7649,22 @@
 			   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
 			   (long long unsigned int) cookie);
 
-		if (cookie_out)
-			*cookie_out = no_ack ? (u64) -1 : cookie;
+		if (save_cookie)
+			drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
 
-		if (drv->num_send_action_cookies == MAX_SEND_ACTION_COOKIES) {
+		if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
 			wpa_printf(MSG_DEBUG,
-				   "nl80211: Drop oldest pending send action cookie 0x%llx",
+				   "nl80211: Drop oldest pending send frame cookie 0x%llx",
 				   (long long unsigned int)
-				   drv->send_action_cookies[0]);
-			os_memmove(&drv->send_action_cookies[0],
-				   &drv->send_action_cookies[1],
-				   (MAX_SEND_ACTION_COOKIES - 1) *
+				   drv->send_frame_cookies[0]);
+			os_memmove(&drv->send_frame_cookies[0],
+				   &drv->send_frame_cookies[1],
+				   (MAX_SEND_FRAME_COOKIES - 1) *
 				   sizeof(u64));
-			drv->num_send_action_cookies--;
+			drv->num_send_frame_cookies--;
 		}
-		drv->send_action_cookies[drv->num_send_action_cookies] = cookie;
-		drv->num_send_action_cookies++;
+		drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
+		drv->num_send_frame_cookies++;
 	}
 
 fail:
@@ -7535,10 +7685,14 @@
 	int ret = -1;
 	u8 *buf;
 	struct ieee80211_hdr *hdr;
+	int offchanok = 1;
+
+	if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq)
+		offchanok = 0;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
-		   "freq=%u MHz wait=%d ms no_cck=%d)",
-		   drv->ifindex, freq, wait_time, no_cck);
+		   "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
+		   drv->ifindex, freq, wait_time, no_cck, offchanok);
 
 	buf = os_zalloc(24 + data_len);
 	if (buf == NULL)
@@ -7564,13 +7718,12 @@
 	     (int) freq == bss->freq || drv->device_ap_sme ||
 	     !drv->use_monitor))
 		ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
-						   0, freq, no_cck, 1,
-						   wait_time, NULL, 0);
+						   0, freq, no_cck, offchanok,
+						   wait_time, NULL, 0, 0);
 	else
 		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
 					     24 + data_len,
-					     &drv->send_action_cookie,
-					     no_cck, 0, 1, NULL, 0);
+					     1, no_cck, 0, offchanok, NULL, 0);
 
 	os_free(buf);
 	return ret;
@@ -7606,19 +7759,19 @@
 	u64 cookie;
 
 	/* Cancel the last pending TX cookie */
-	nl80211_frame_wait_cancel(bss, drv->send_action_cookie);
+	nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
 
 	/*
 	 * Cancel the other pending TX cookies, if any. This is needed since
 	 * the driver may keep a list of all pending offchannel TX operations
 	 * and free up the radio only once they have expired or cancelled.
 	 */
-	for (i = drv->num_send_action_cookies; i > 0; i--) {
-		cookie = drv->send_action_cookies[i - 1];
-		if (cookie != drv->send_action_cookie)
+	for (i = drv->num_send_frame_cookies; i > 0; i--) {
+		cookie = drv->send_frame_cookies[i - 1];
+		if (cookie != drv->send_frame_cookie)
 			nl80211_frame_wait_cancel(bss, cookie);
 	}
-	drv->num_send_action_cookies = 0;
+	drv->num_send_frame_cookies = 0;
 }
 
 
@@ -7938,15 +8091,6 @@
 }
 
 
-static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
-			      int encrypt)
-{
-	struct i802_bss *bss = priv;
-	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
-					     0, 0, 0, 0, NULL, 0);
-}
-
-
 static int nl80211_set_param(void *priv, const char *param)
 {
 	struct i802_bss *bss = priv;
@@ -7981,6 +8125,12 @@
 		drv->test_use_roc_tx = 1;
 	}
 
+	if (os_strstr(param, "control_port=0"))
+		drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
+
+	if (os_strstr(param, "full_ap_client_state=0"))
+		drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
+
 	return 0;
 }
 
@@ -8081,6 +8231,12 @@
 	    (params->fils_cache_id &&
 	     nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
 		     params->fils_cache_id)) ||
+	    (params->pmk_lifetime &&
+	     nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
+			 params->pmk_lifetime)) ||
+	    (params->pmk_reauth_threshold &&
+	     nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+			params->pmk_reauth_threshold)) ||
 	    (cmd != NL80211_CMD_DEL_PMKSA &&
 	     params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
 	     nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
@@ -8401,7 +8557,7 @@
 	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
 	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
-					 0, 0, NULL, 0) < 0)
+					 0, 0, NULL, 0, 0) < 0)
 		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
 			   "send poll frame");
 }
@@ -8675,15 +8831,12 @@
 #endif /* CONFIG TDLS */
 
 
-static int driver_nl80211_set_key(const char *ifname, void *priv,
-				  enum wpa_alg alg, const u8 *addr,
-				  int key_idx, int set_tx,
-				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+static int driver_nl80211_set_key(void *priv,
+				  struct wpa_driver_set_key_params *params)
 {
 	struct i802_bss *bss = priv;
-	return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
-					  set_tx, seq, seq_len, key, key_len);
+
+	return wpa_driver_nl80211_set_key(bss, params);
 }
 
 
@@ -8742,12 +8895,13 @@
 static int driver_nl80211_send_mlme(void *priv, const u8 *data,
 				    size_t data_len, int noack,
 				    unsigned int freq,
-				    const u16 *csa_offs, size_t csa_offs_len)
+				    const u16 *csa_offs, size_t csa_offs_len,
+				    int no_encrypt, unsigned int wait)
 {
 	struct i802_bss *bss = priv;
 	return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
-					    freq, 0, 0, 0, csa_offs,
-					    csa_offs_len);
+					    freq, 0, 0, wait, csa_offs,
+					    csa_offs_len, no_encrypt);
 }
 
 
@@ -9398,6 +9552,46 @@
 }
 
 
+static int get_wowlan_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	int *wowlan_enabled = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	*wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_wowlan(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int wowlan_enabled;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
+
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
+
+	ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
+		   wowlan_enabled ? "enabled" : "disabled");
+
+	return wowlan_enabled;
+}
+
+
 static int nl80211_set_wowlan(void *priv,
 			      const struct wowlan_triggers *triggers)
 {
@@ -9941,7 +10135,7 @@
 	if (res) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Adding bridge ip neigh failed: %s",
-			   strerror(errno));
+			   nl_geterror(res));
 	}
 errout:
 	if (nl_lladdr)
@@ -10017,7 +10211,7 @@
 	if (res) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Deleting bridge ip neigh failed: %s",
-			   strerror(errno));
+			   nl_geterror(res));
 	}
 errout:
 	if (nl_ipaddr)
@@ -10251,22 +10445,24 @@
 	    nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
 			params->ch_width) ||
 	    add_acs_ch_list(msg, params->freq_list) ||
-	    add_acs_freq_list(msg, params->freq_list)) {
+	    add_acs_freq_list(msg, params->freq_list) ||
+	    (params->edmg_enabled &&
+	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
 	nla_nest_end(msg, data);
 
 	wpa_printf(MSG_DEBUG,
-		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
+		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
 		   params->hw_mode, params->ht_enabled, params->ht40_enabled,
-		   params->vht_enabled, params->ch_width);
+		   params->vht_enabled, params->ch_width, params->edmg_enabled);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Failed to invoke driver ACS function: %s",
-			   strerror(errno));
+			   strerror(-ret));
 	}
 	return ret;
 }
@@ -10313,7 +10509,7 @@
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "nl80211: Driver setband function failed: %s",
-			   strerror(errno));
+			   strerror(-ret));
 	}
 	return ret;
 }
@@ -11204,6 +11400,7 @@
 	.get_hw_feature_data = nl80211_get_hw_feature_data,
 	.sta_add = wpa_driver_nl80211_sta_add,
 	.sta_remove = driver_nl80211_sta_remove,
+	.tx_control_port = nl80211_tx_control_port,
 	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
 	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
 	.sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
@@ -11234,7 +11431,6 @@
 	.signal_monitor = nl80211_signal_monitor,
 	.signal_poll = nl80211_signal_poll,
 	.channel_info = nl80211_channel_info,
-	.send_frame = nl80211_send_frame,
 	.set_param = nl80211_set_param,
 	.get_radio_name = nl80211_get_radio_name,
 	.add_pmkid = nl80211_add_pmkid,
@@ -11269,6 +11465,7 @@
 #endif /* ANDROID */
 	.vendor_cmd = nl80211_vendor_cmd,
 	.set_qos_map = nl80211_set_qos_map,
+	.get_wowlan = nl80211_get_wowlan,
 	.set_wowlan = nl80211_set_wowlan,
 	.set_mac_addr = nl80211_set_mac_addr,
 #ifdef CONFIG_MESH
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 716504c..6e6c872 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -17,12 +17,10 @@
 #include "utils/list.h"
 #include "driver.h"
 
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl80211_handle_alloc nl_socket_alloc_cb
-#define nl80211_handle_destroy nl_socket_free
-#endif /* CONFIG_LIBNL20 */
+#ifndef NL_CAPABILITY_VERSION_3_5_0
+#define nla_nest_start(msg, attrtype) \
+	nla_nest_start(msg, NLA_F_NESTED | (attrtype))
+#endif
 
 struct nl80211_global {
 	void *ctx;
@@ -32,11 +30,11 @@
 	int if_add_wdevid_set;
 	struct netlink_data *netlink;
 	struct nl_cb *nl_cb;
-	struct nl_handle *nl;
+	struct nl_sock *nl;
 	int nl80211_id;
 	int ioctl_sock; /* socket for ioctl() use */
 
-	struct nl_handle *nl_event;
+	struct nl_sock *nl_event;
 };
 
 struct nl80211_wiphy_data {
@@ -44,7 +42,7 @@
 	struct dl_list bsss;
 	struct dl_list drvs;
 
-	struct nl_handle *nl_beacons;
+	struct nl_sock *nl_beacons;
 	struct nl_cb *nl_cb;
 
 	int wiphy_idx;
@@ -75,7 +73,7 @@
 	int if_dynamic;
 
 	void *ctx;
-	struct nl_handle *nl_preq, *nl_mgmt, *nl_connect;
+	struct nl_sock *nl_preq, *nl_mgmt, *nl_connect;
 	struct nl_cb *nl_cb;
 
 	struct nl80211_wiphy_data *wiphy_data;
@@ -176,10 +174,10 @@
 
 	u64 vendor_scan_cookie;
 	u64 remain_on_chan_cookie;
-	u64 send_action_cookie;
-#define MAX_SEND_ACTION_COOKIES 20
-	u64 send_action_cookies[MAX_SEND_ACTION_COOKIES];
-	unsigned int num_send_action_cookies;
+	u64 send_frame_cookie;
+#define MAX_SEND_FRAME_COOKIES 20
+	u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES];
+	unsigned int num_send_frame_cookies;
 
 	unsigned int last_mgmt_freq;
 
@@ -192,7 +190,7 @@
 
 	int eapol_sock; /* socket for EAPOL frames */
 
-	struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+	struct nl_sock *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
 
 	struct drv_nl80211_if_info default_if_indices[16];
 	struct drv_nl80211_if_info *if_indices;
@@ -256,7 +254,7 @@
 int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 			    const u8 *addr, int cmd, u16 reason_code,
 			    int local_state_change,
-			    struct nl_handle *nl_connect);
+			    struct nl_sock *nl_connect);
 
 int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
 void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
@@ -275,7 +273,7 @@
 const char * nl80211_iftype_str(enum nl80211_iftype mode);
 
 #ifdef ANDROID
-int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_nl_socket_set_nonblocking(struct nl_sock *handle);
 int android_pno_start(struct i802_bss *bss,
 		      struct wpa_driver_scan_params *params);
 int android_pno_stop(struct i802_bss *bss);
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
index ba47888..9431a12 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -182,9 +182,7 @@
 #endif /* ANDROID_P2P */
 
 
-int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+int android_nl_socket_set_nonblocking(struct nl_sock *handle)
 {
 	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
 }
-
-
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 9a82cd1..b4fed9e 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -78,6 +78,7 @@
 	unsigned int wmm_ac_supported:1;
 	unsigned int mac_addr_rand_scan_supported:1;
 	unsigned int mac_addr_rand_sched_scan_supported:1;
+	unsigned int update_ft_ies_supported:1;
 };
 
 
@@ -243,6 +244,9 @@
 		case NL80211_CMD_SET_QOS_MAP:
 			info->set_qos_map_supported = 1;
 			break;
+		case NL80211_CMD_UPDATE_FT_IES:
+			info->update_ft_ies_supported = 1;
+			break;
 		}
 	}
 }
@@ -433,6 +437,26 @@
 	if (ext_feature_isset(ext_features, len,
 			      NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
 		capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
+		capa->flags |= WPA_DRIVER_FLAGS_CONTROL_PORT;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_VLAN_OFFLOAD))
+		capa->flags |= WPA_DRIVER_FLAGS_VLAN_OFFLOAD;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_CAN_REPLACE_PTK0))
+		capa->flags |= WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_BEACON_PROTECTION))
+		capa->flags |= WPA_DRIVER_FLAGS_BEACON_PROTECTION;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_EXT_KEY_ID))
+		capa->flags |= WPA_DRIVER_FLAGS_EXTENDED_KEY_ID;
 }
 
 
@@ -479,12 +503,6 @@
 	if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
 		info->mac_addr_rand_sched_scan_supported = 1;
 
-	if (flags & NL80211_FEATURE_STATIC_SMPS)
-		capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
-
-	if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
-		capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
-
 	if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
 		info->wmm_ac_supported = 1;
 
@@ -904,6 +922,9 @@
 		drv->capa.max_sched_scan_plan_iterations = 0;
 	}
 
+	if (info->update_ft_ies_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES;
+
 	return 0;
 }
 
@@ -1294,6 +1315,12 @@
 		drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: key_mgmt=0x%x enc=0x%x auth=0x%x flags=0x%llx rrm_flags=0x%x probe_resp_offloads=0x%x max_stations=%u max_remain_on_chan=%u max_scan_ssids=%d",
+		   drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth,
+		   (unsigned long long) drv->capa.flags, drv->capa.rrm_flags,
+		   drv->capa.probe_resp_offloads, drv->capa.max_stations,
+		   drv->capa.max_remain_on_chan, drv->capa.max_scan_ssids);
 	return 0;
 }
 
@@ -1360,6 +1387,20 @@
 }
 
 
+static int cw2ecw(unsigned int cw)
+{
+	int bit;
+
+	if (cw == 0)
+		return 0;
+
+	for (bit = 1; cw != 1; bit++)
+		cw >>= 1;
+
+	return bit;
+}
+
+
 static void phy_info_freq(struct hostapd_hw_modes *mode,
 			  struct hostapd_channel_data *chan,
 			  struct nlattr *tb_freq[])
@@ -1432,6 +1473,12 @@
 			[NL80211_WMMR_AIFSN] = { .type = NLA_U8 },
 			[NL80211_WMMR_TXOP] = { .type = NLA_U16 },
 		};
+		static const u8 wmm_map[4] = {
+			[NL80211_AC_BE] = WMM_AC_BE,
+			[NL80211_AC_BK] = WMM_AC_BK,
+			[NL80211_AC_VI] = WMM_AC_VI,
+			[NL80211_AC_VO] = WMM_AC_VO,
+		};
 		struct nlattr *nl_wmm;
 		struct nlattr *tb_wmm[NL80211_WMMR_MAX + 1];
 		int rem_wmm, ac, count = 0;
@@ -1453,16 +1500,19 @@
 				return;
 			}
 			ac = nl_wmm->nla_type;
-			if (ac < 0 || ac >= WMM_AC_NUM) {
+			if ((unsigned int) ac >= ARRAY_SIZE(wmm_map)) {
 				wpa_printf(MSG_DEBUG,
 					   "nl80211: Invalid AC value %d", ac);
 				return;
 			}
 
+			ac = wmm_map[ac];
 			chan->wmm_rules[ac].min_cwmin =
-				nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]);
+				cw2ecw(nla_get_u16(
+					       tb_wmm[NL80211_WMMR_CW_MIN]));
 			chan->wmm_rules[ac].min_cwmax =
-				nla_get_u16(tb_wmm[NL80211_WMMR_CW_MAX]);
+				cw2ecw(nla_get_u16(
+					       tb_wmm[NL80211_WMMR_CW_MAX]));
 			chan->wmm_rules[ac].min_aifs =
 				nla_get_u8(tb_wmm[NL80211_WMMR_AIFSN]);
 			chan->wmm_rules[ac].max_txop =
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 2aecc74..d4ca2eb 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -683,29 +683,42 @@
 				      size_t len, struct nlattr *ack)
 {
 	union wpa_event_data event;
-	const struct ieee80211_hdr *hdr;
-	u16 fc;
+	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
+	u16 fc = le_to_host16(hdr->frame_control);
+	u64 cookie_val = 0;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
-	if (!is_ap_interface(drv->nlmode)) {
-		u64 cookie_val;
+	if (cookie)
+		cookie_val = nla_get_u64(cookie);
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Frame TX status event A1=" MACSTR
+		   " %sstype=%d cookie=0x%llx%s ack=%d",
+		   MAC2STR(hdr->addr1),
+		   WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ? "not-mgmt " : "",
+		   WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val,
+		   cookie ? "" : "(N/A)", ack != NULL);
 
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+		return;
+
+	if (!is_ap_interface(drv->nlmode) &&
+	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
 		if (!cookie)
 			return;
 
-		cookie_val = nla_get_u64(cookie);
-		wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
-			   " cookie=0x%llx%s (ack=%d)",
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Frame TX status: cookie=0x%llx%s (ack=%d)",
 			   (long long unsigned int) cookie_val,
-			   cookie_val == drv->send_action_cookie ?
+			   cookie_val == drv->send_frame_cookie ?
 			   " (match)" : " (unknown)", ack != NULL);
-		if (cookie_val != drv->send_action_cookie)
+		if (cookie_val != drv->send_frame_cookie)
 			return;
+	} else if (!is_ap_interface(drv->nlmode) &&
+		   WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Authentication frame TX status: ack=%d",
+			   !!ack);
 	}
 
-	hdr = (const struct ieee80211_hdr *) frame;
-	fc = le_to_host16(hdr->frame_control);
-
 	os_memset(&event, 0, sizeof(event));
 	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
 	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
@@ -1740,8 +1753,41 @@
 }
 
 
-static unsigned int chan_2ghz_or_5ghz_to_freq(u8 chan)
+static unsigned int chan_to_freq(struct wpa_driver_nl80211_data *drv,
+				 u8 chan, enum hostapd_hw_mode hw_mode)
 {
+	if (hw_mode == NUM_HOSTAPD_MODES) {
+		/* For drivers that do not report ACS_HW_MODE */
+		u16 num_modes, flags;
+		struct hostapd_hw_modes *modes;
+		u8 dfs_domain;
+		int i;
+
+		modes = nl80211_get_hw_feature_data(drv->first_bss, &num_modes,
+						    &flags, &dfs_domain);
+		if (!modes) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Fetching hardware mode failed");
+			goto try_2_4_or_5;
+		}
+		if (num_modes == 1)
+			hw_mode = modes[0].mode;
+
+		for (i = 0; i < num_modes; i++) {
+			os_free(modes[i].channels);
+			os_free(modes[i].rates);
+		}
+
+		os_free(modes);
+	}
+
+	if (hw_mode == HOSTAPD_MODE_IEEE80211AD) {
+		if (chan >= 1 && chan <= 6)
+			return 56160 + (2160 * chan);
+		return 0;
+	}
+
+try_2_4_or_5:
 	if (chan >= 1 && chan <= 13)
 		return 2407 + 5 * chan;
 	if (chan == 14)
@@ -1772,34 +1818,8 @@
 		return;
 
 	os_memset(&event, 0, sizeof(event));
-	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]) {
-		event.acs_selected_channels.pri_freq = nla_get_u32(
-			tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]);
-	} else {
-		chan = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
-		event.acs_selected_channels.pri_freq =
-			chan_2ghz_or_5ghz_to_freq(chan);
-	}
+	event.acs_selected_channels.hw_mode = NUM_HOSTAPD_MODES;
 
-	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]) {
-		event.acs_selected_channels.sec_freq = nla_get_u32(
-			tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]);
-	} else {
-		chan = nla_get_u8(
-			tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
-		event.acs_selected_channels.sec_freq =
-			chan_2ghz_or_5ghz_to_freq(chan);
-	}
-
-	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
-		event.acs_selected_channels.vht_seg0_center_ch =
-			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
-	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
-		event.acs_selected_channels.vht_seg1_center_ch =
-			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
-	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
-		event.acs_selected_channels.ch_width =
-			nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
 	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
 		u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
 
@@ -1814,14 +1834,48 @@
 		}
 	}
 
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]) {
+		event.acs_selected_channels.pri_freq = nla_get_u32(
+			tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]);
+	} else {
+		chan = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+		event.acs_selected_channels.pri_freq =
+			chan_to_freq(drv, chan,
+				     event.acs_selected_channels.hw_mode);
+	}
+
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]) {
+		event.acs_selected_channels.sec_freq = nla_get_u32(
+			tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]);
+	} else {
+		chan = nla_get_u8(
+			tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+		event.acs_selected_channels.sec_freq =
+			chan_to_freq(drv, chan,
+				     event.acs_selected_channels.hw_mode);
+	}
+
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL])
+		event.acs_selected_channels.edmg_channel =
+			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+		event.acs_selected_channels.vht_seg0_center_ch =
+			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL])
+		event.acs_selected_channels.vht_seg1_center_ch =
+			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
+		event.acs_selected_channels.ch_width =
+			nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
 	wpa_printf(MSG_INFO,
-		   "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
+		   "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d",
 		   event.acs_selected_channels.pri_freq,
 		   event.acs_selected_channels.sec_freq,
 		   event.acs_selected_channels.ch_width,
 		   event.acs_selected_channels.vht_seg0_center_ch,
 		   event.acs_selected_channels.vht_seg1_center_ch,
-		   event.acs_selected_channels.hw_mode);
+		   event.acs_selected_channels.hw_mode,
+		   event.acs_selected_channels.edmg_channel);
 
 	/* Ignore ACS channel list check for backwards compatibility */
 
@@ -2448,6 +2502,18 @@
 }
 
 
+static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv,
+				       struct nlattr **tb)
+{
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_FRAME])
+		return;
+
+	drv_event_eapol_rx(drv->ctx, nla_data(tb[NL80211_ATTR_MAC]),
+			   nla_data(tb[NL80211_ATTR_FRAME]),
+			   nla_len(tb[NL80211_ATTR_FRAME]));
+}
+
+
 static void do_process_drv_event(struct i802_bss *bss, int cmd,
 				 struct nlattr **tb)
 {
@@ -2663,6 +2729,9 @@
 	case NL80211_CMD_UPDATE_OWE_INFO:
 		mlme_event_dh_event(drv, bss, tb);
 		break;
+	case NL80211_CMD_CONTROL_PORT_FRAME:
+		nl80211_control_port_frame(drv, tb);
+		break;
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
index f25cd79..7ff55f1 100644
--- a/src/drivers/driver_nl80211_monitor.c
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -71,6 +71,9 @@
 	u16 fc;
 	union wpa_event_data event;
 
+	if (!drv->use_monitor)
+		return;
+
 	hdr = (struct ieee80211_hdr *) buf;
 	fc = le_to_host16(hdr->frame_control);
 
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 9afa5b3..04f6bb8 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -236,6 +236,11 @@
 	params->filter_ssids = NULL;
 	drv->num_filter_ssids = params->num_filter_ssids;
 
+	if (!drv->hostapd && is_ap_interface(drv->nlmode)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_AP");
+		scan_flags |= NL80211_SCAN_FLAG_AP;
+	}
+
 	if (params->only_new_results) {
 		wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
 		scan_flags |= NL80211_SCAN_FLAG_FLUSH;
@@ -928,7 +933,9 @@
 	struct wpa_scan_results *res;
 	int ret;
 	struct nl80211_bss_info_arg arg;
+	int count = 0;
 
+try_again:
 	res = os_zalloc(sizeof(*res));
 	if (res == NULL)
 		return NULL;
@@ -941,6 +948,18 @@
 	arg.drv = drv;
 	arg.res = res;
 	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+	if (ret == -EAGAIN) {
+		count++;
+		if (count >= 10) {
+			wpa_printf(MSG_INFO,
+				   "nl80211: Failed to receive consistent scan result dump");
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Failed to receive consistent scan result dump - try again");
+			wpa_scan_results_free(res);
+			goto try_again;
+		}
+	}
 	if (ret == 0) {
 		struct nl80211_noise_info info;
 
diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c
index 6ff3eae..ccd2d9d 100644
--- a/src/drivers/driver_none.c
+++ b/src/drivers/driver_none.c
@@ -43,13 +43,6 @@
 }
 
 
-static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
-				  u16 proto, const u8 *data, size_t data_len)
-{
-	return 0;
-}
-
-
 static void * none_driver_init(void *ctx, const char *ifname)
 {
 	struct none_driver_data *drv;
@@ -79,7 +72,6 @@
 	.desc = "no driver (RADIUS server/WPS ER)",
 	.hapd_init = none_driver_hapd_init,
 	.hapd_deinit = none_driver_hapd_deinit,
-	.send_ether = none_driver_send_ether,
 	.init = none_driver_init,
 	.deinit = none_driver_deinit,
 };
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index c06e75c..bfc2311 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -69,14 +69,16 @@
 
 
 static int
-wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
-	    size_t seq_len, const u8 *key, size_t key_len)
+wpa_driver_openbsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
 {
 	struct openbsd_driver_data *drv = priv;
 	struct ieee80211_keyavail keyavail;
+	enum key_flag key_flag = params->key_flag;
+	const u8 *key = params->key;
+	size_t key_len = params->key_len;
 
-	if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+	if (key_len > IEEE80211_PMK_LEN ||
+	    (key_flag & KEY_FLAG_PMK_MASK) != KEY_FLAG_PMK) {
 		return -1;
 
 	memset(&keyavail, 0, sizeof(keyavail));
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 55cf618..d6735b4 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -205,14 +205,19 @@
 }
 
 
-static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
-				      enum wpa_alg alg, const u8 *addr,
-				      int key_idx, int set_tx,
-				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
+static int wpa_driver_privsep_set_key(void *priv,
+				      struct wpa_driver_set_key_params *params)
 {
 	struct wpa_driver_privsep_data *drv = priv;
 	struct privsep_cmd_set_key cmd;
+	enum wpa_alg alg = params->alg;
+	const u8 *addr = params->addr;
+	int key_idx = params->key_idx;
+	int set_tx = params->set_tx;
+	const u8 *seq = params->seq;
+	size_t seq_len = params->seq_len;
+	const u8 *key = params->key;
+	size_t key_len = params->key_len;
 
 	wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
 		   __func__, priv, alg, key_idx, set_tx);
@@ -225,6 +230,7 @@
 		os_memset(cmd.addr, 0xff, ETH_ALEN);
 	cmd.key_idx = key_idx;
 	cmd.set_tx = set_tx;
+	cmd.key_flag = params->key_flag;
 	if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
 		os_memcpy(cmd.seq, seq, seq_len);
 		cmd.seq_len = seq_len;
@@ -791,6 +797,8 @@
 	capa->extended_capa = NULL;
 	capa->extended_capa_mask = NULL;
 	capa->extended_capa_len = 0;
+	/* Control port is not yet supported */
+	capa->flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
 	return 0;
 }
 
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 32c2971..978e1cf 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1712,7 +1712,8 @@
 				       const u8 *addr, int key_idx,
 				       int set_tx, const u8 *seq,
 				       size_t seq_len,
-				       const u8 *key, size_t key_len)
+				       const u8 *key, size_t key_len,
+				       enum key_flag key_flag)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	struct iwreq iwr;
@@ -1751,30 +1752,31 @@
 		os_memcpy(ext + 1, key, key_len);
 		ext->key_len = key_len;
 	}
-	switch (alg) {
-	case WPA_ALG_NONE:
-		ext->alg = IW_ENCODE_ALG_NONE;
-		break;
-	case WPA_ALG_WEP:
-		ext->alg = IW_ENCODE_ALG_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		ext->alg = IW_ENCODE_ALG_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		ext->alg = IW_ENCODE_ALG_CCMP;
-		break;
-	case WPA_ALG_PMK:
+	if (key_flag & KEY_FLAG_PMK) {
 		ext->alg = IW_ENCODE_ALG_PMK;
-		break;
-	case WPA_ALG_IGTK:
-		ext->alg = IW_ENCODE_ALG_AES_CMAC;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
-			   __FUNCTION__, alg);
-		os_free(ext);
-		return -1;
+	} else {
+		switch (alg) {
+		case WPA_ALG_NONE:
+			ext->alg = IW_ENCODE_ALG_NONE;
+			break;
+		case WPA_ALG_WEP:
+			ext->alg = IW_ENCODE_ALG_WEP;
+			break;
+		case WPA_ALG_TKIP:
+			ext->alg = IW_ENCODE_ALG_TKIP;
+			break;
+		case WPA_ALG_CCMP:
+			ext->alg = IW_ENCODE_ALG_CCMP;
+			break;
+		case WPA_ALG_IGTK:
+			ext->alg = IW_ENCODE_ALG_AES_CMAC;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
+				   __FUNCTION__, alg);
+			os_free(ext);
+			return -1;
+		}
 	}
 
 	if (seq && seq_len) {
@@ -1803,37 +1805,27 @@
 /**
  * wpa_driver_wext_set_key - Configure encryption key
  * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @priv: Private driver interface data
- * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- *	%WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
- * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
- *	broadcast/default keys
- * @key_idx: key index (0..3), usually 0 for unicast keys
- * @set_tx: Configure this key as the default Tx key (only used when
- *	driver does not support separate unicast/individual key
- * @seq: Sequence number/packet number, seq_len octets, the next
- *	packet number to be used for in replay protection; configured
- *	for Rx keys (in most cases, this is only used with broadcast
- *	keys and set to zero for unicast keys)
- * @seq_len: Length of the seq, depends on the algorithm:
- *	TKIP: 6 octets, CCMP: 6 octets
- * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- *	8-byte Rx Mic Key
- * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
- *	TKIP: 32, CCMP: 16)
+ * @params: Key parameters
  * Returns: 0 on success, -1 on failure
  *
  * This function uses SIOCSIWENCODEEXT by default, but tries to use
  * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
  */
-int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			    const u8 *addr, int key_idx,
-			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len)
+static int wpa_driver_wext_set_key(void *priv,
+				   struct wpa_driver_set_key_params *params)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	struct iwreq iwr;
 	int ret = 0;
+	enum wpa_alg alg = params->alg;
+	enum key_flag key_flag = params->key_flag;
+	const u8 *addr = params->addr;
+	int key_idx = params->key_idx;
+	int set_tx = params->set_tx;
+	const u8 *seq = params->seq;
+	size_t seq_len = params->seq_len;
+	const u8 *key = params->key;
+	size_t key_len = params->key_len;
 
 	wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
 		   "key_len=%lu",
@@ -1841,7 +1833,7 @@
 		   (unsigned long) seq_len, (unsigned long) key_len);
 
 	ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
-					  seq, seq_len, key, key_len);
+					  seq, seq_len, key, key_len, key_flag);
 	if (ret == 0)
 		return 0;
 
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index b4b5960..6214cdf 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -52,10 +52,6 @@
 int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
 int wpa_driver_wext_set_freq(void *priv, int freq);
 int wpa_driver_wext_set_mode(void *priv, int mode);
-int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			    const u8 *addr, int key_idx,
-			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len);
 int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
 struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
 
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index bc2e87e..55a98ef 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -176,7 +176,6 @@
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
   DRV_LIBS += -lnl-genl-3
-  DRV_CFLAGS += -DCONFIG_LIBNL20
   ifdef LIBNL_INC
     DRV_CFLAGS += -I$(LIBNL_INC)
   else
@@ -193,14 +192,8 @@
   else
     ifndef CONFIG_OSX
       DRV_LIBS += -lnl
-    endif
-  endif
-
-  ifdef CONFIG_LIBNL20
-    ifndef CONFIG_LIBNL_TINY
       DRV_LIBS += -lnl-genl
     endif
-    DRV_CFLAGS += -DCONFIG_LIBNL20
   endif
 endif
 endif
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index c3c2c0f..5a32a24 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -160,7 +160,7 @@
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
   DRV_LIBS += -lnl-genl-3
-  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+  DRV_CFLAGS += -I/usr/include/libnl3
 ifdef CONFIG_LIBNL3_ROUTE
   DRV_LIBS += -lnl-route-3
   DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
@@ -170,13 +170,7 @@
     DRV_LIBS += -lnl-tiny
   else
     DRV_LIBS += -lnl
-  endif
-
-  ifdef CONFIG_LIBNL20
-    ifndef CONFIG_LIBNL_TINY
-      DRV_LIBS += -lnl-genl
-    endif
-    DRV_CFLAGS += -DCONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
   endif
 endif
 endif
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 341e0e8..38835b5 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,7 +11,7 @@
  * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
  * Copyright 2008 Colin McCabe <colin@cozybit.com>
  * Copyright 2015-2017	Intel Deutschland GmbH
- * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2018-2020 Intel Corporation
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -265,6 +265,29 @@
  */
 
 /**
+ * DOC: TID configuration
+ *
+ * TID config support can be checked in the %NL80211_ATTR_TID_CONFIG
+ * attribute given in wiphy capabilities.
+ *
+ * The necessary configuration parameters are mentioned in
+ * &enum nl80211_tid_config_attr and it will be passed to the
+ * %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG.
+ *
+ * If the configuration needs to be applied for specific peer then the MAC
+ * address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the
+ * configuration will be applied for all the connected peers in the vif except
+ * any peers that have peer specific configuration for the TID by default; if
+ * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values
+ * will be overwritten.
+ *
+ * All this configuration is valid only for STA's current connection
+ * i.e. the configuration will be reset to default when the STA connects back
+ * after disconnection/roaming, and this configuration will be cleared when
+ * the interface goes down.
+ */
+
+/**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -1125,6 +1148,9 @@
  *	peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame
  *	content. The frame is ethernet data.
  *
+ * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
+ *	is passed using %NL80211_ATTR_TID_CONFIG attribute.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1349,6 +1375,8 @@
 
 	NL80211_CMD_PROBE_MESH_LINK,
 
+	NL80211_CMD_SET_TID_CONFIG,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1604,7 +1632,8 @@
  *	flag is included, then control port frames are sent over NL80211 instead
  *	using %CMD_CONTROL_PORT_FRAME.  If control port routing over NL80211 is
  *	to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
- *	flag.
+ *	flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth
+ *	frames are not forwared over the control port.
  *
  * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
  *	We recommend using nested, driver-specific attributes within this.
@@ -2400,6 +2429,47 @@
  * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
  *	(u16).
  *
+ * @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings.
+ *
+ * @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry
+ *	using attributes from &enum nl80211_iftype_akm_attributes. This
+ *	attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating
+ *	supported AKM suites capability per interface. AKMs advertised in
+ *	%NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not
+ *	advertised for a specific interface type.
+ *
+ * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a
+ *	nested attribute with &enum nl80211_tid_config_attr sub-attributes;
+ *	on output (in wiphy attributes) it contains only the feature sub-
+ *	attributes.
+ *
+ * @NL80211_ATTR_CONTROL_PORT_NO_PREAUTH: disable preauth frame rx on control
+ *	port in order to forward/receive them as ordinary data frames.
+ *
+ * @NL80211_ATTR_PMK_LIFETIME: Maximum lifetime for PMKSA in seconds (u32,
+ *	dot11RSNAConfigPMKReauthThreshold; 0 is not a valid value).
+ *	An optional parameter configured through %NL80211_CMD_SET_PMKSA.
+ *	Drivers that trigger roaming need to know the lifetime of the
+ *	configured PMKSA for triggering the full vs. PMKSA caching based
+ *	authentication. This timeout helps authentication methods like SAE,
+ *	where PMK gets updated only by going through a full (new SAE)
+ *	authentication instead of getting updated during an association for EAP
+ *	authentication. No new full authentication within the PMK expiry shall
+ *	result in a disassociation at the end of the lifetime.
+ *
+ * @NL80211_ATTR_PMK_REAUTH_THRESHOLD: Reauthentication threshold time, in
+ *	terms of percentage of %NL80211_ATTR_PMK_LIFETIME
+ *	(u8, dot11RSNAConfigPMKReauthThreshold, 1..100). This is an optional
+ *	parameter configured through %NL80211_CMD_SET_PMKSA. Requests the
+ *	driver to trigger a full authentication roam (without PMKSA caching)
+ *	after the reauthentication threshold time, but before the PMK lifetime
+ *	has expired.
+ *
+ *	Authentication methods like SAE need to be able to generate a new PMKSA
+ *	entry without having to force a disconnection after the PMK timeout. If
+ *	no roaming occurs between the reauth threshold and PMK expiration,
+ *	disassociation is still forced.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2864,6 +2934,17 @@
 
 	NL80211_ATTR_VLAN_ID,
 
+	NL80211_ATTR_HE_BSS_COLOR,
+
+	NL80211_ATTR_IFTYPE_AKM_SUITES,
+
+	NL80211_ATTR_TID_CONFIG,
+
+	NL80211_ATTR_CONTROL_PORT_NO_PREAUTH,
+
+	NL80211_ATTR_PMK_LIFETIME,
+	NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -3583,6 +3664,8 @@
  * @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations.
  *	This is a nested attribute that contains the wmm limitation per AC.
  *	(see &enum nl80211_wmm_rule)
+ * @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
+ *	in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
  *	currently defined
  * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3612,6 +3695,7 @@
 	NL80211_FREQUENCY_ATTR_NO_20MHZ,
 	NL80211_FREQUENCY_ATTR_NO_10MHZ,
 	NL80211_FREQUENCY_ATTR_WMM,
+	NL80211_FREQUENCY_ATTR_NO_HE,
 
 	/* keep last */
 	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3809,6 +3893,7 @@
  * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
  * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
  * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
+ * @NL80211_RRF_NO_HE: HE operation not allowed
  */
 enum nl80211_reg_rule_flags {
 	NL80211_RRF_NO_OFDM		= 1<<0,
@@ -3826,6 +3911,7 @@
 	NL80211_RRF_NO_HT40PLUS		= 1<<14,
 	NL80211_RRF_NO_80MHZ		= 1<<15,
 	NL80211_RRF_NO_160MHZ		= 1<<16,
+	NL80211_RRF_NO_HE		= 1<<17,
 };
 
 #define NL80211_RRF_PASSIVE_SCAN	NL80211_RRF_NO_IR
@@ -4532,6 +4618,7 @@
  *	See &enum nl80211_key_default_types.
  * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
  *	Defaults to @NL80211_KEY_RX_TX.
+ * @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key
  *
  * @__NL80211_KEY_AFTER_LAST: internal
  * @NL80211_KEY_MAX: highest key attribute
@@ -4547,6 +4634,7 @@
 	NL80211_KEY_TYPE,
 	NL80211_KEY_DEFAULT_TYPES,
 	NL80211_KEY_MODE,
+	NL80211_KEY_DEFAULT_BEACON,
 
 	/* keep last */
 	__NL80211_KEY_AFTER_LAST,
@@ -4703,6 +4791,69 @@
 };
 
 /**
+ * enum nl80211_tid_config - TID config state
+ * @NL80211_TID_CONFIG_ENABLE: Enable config for the TID
+ * @NL80211_TID_CONFIG_DISABLE: Disable config for the TID
+ */
+enum nl80211_tid_config {
+	NL80211_TID_CONFIG_ENABLE,
+	NL80211_TID_CONFIG_DISABLE,
+};
+
+/* enum nl80211_tid_config_attr - TID specific configuration.
+ * @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values
+ * @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported
+ *	for per-vif configuration; doesn't list the ones that are generic
+ *	(%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
+ * @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
+ *	per peer instead.
+ * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribute, if no peer
+ *	is selected, if set indicates that the new configuration overrides
+ *	all previous peer configurations, otherwise previous peer specific
+ *	configurations should be left untouched. If peer is selected then
+ *	it will reset particular TID configuration of that peer and it will
+ *	not accept other TID config attributes along with peer.
+ * @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7)
+ *	Its type is u16.
+ * @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID.
+ *	specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config.
+ *	Its type is u8.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame
+ *	transmission, user-space sets this configuration in
+ *	&NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and
+ *	the max value is advertised by the driver in this attribute on
+ *	output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame
+ *	transmission, user-space sets this configuration in
+ *	&NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
+ *	the max value is advertised by the driver in this attribute on
+ *	output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable aggregation for the TIDs
+ *	specified in %NL80211_TID_CONFIG_ATTR_TIDS. Its type is u8, using
+ *	the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs
+ *	specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using
+ *	the values from &nl80211_tid_config.
+ */
+enum nl80211_tid_config_attr {
+	__NL80211_TID_CONFIG_ATTR_INVALID,
+	NL80211_TID_CONFIG_ATTR_PAD,
+	NL80211_TID_CONFIG_ATTR_VIF_SUPP,
+	NL80211_TID_CONFIG_ATTR_PEER_SUPP,
+	NL80211_TID_CONFIG_ATTR_OVERRIDE,
+	NL80211_TID_CONFIG_ATTR_TIDS,
+	NL80211_TID_CONFIG_ATTR_NOACK,
+	NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
+	NL80211_TID_CONFIG_ATTR_RETRY_LONG,
+	NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
+	NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
+
+	/* keep last */
+	__NL80211_TID_CONFIG_ATTR_AFTER_LAST,
+	NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_packet_pattern_attr - packet pattern attribute
  * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
  * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
@@ -5517,6 +5668,22 @@
  *	with VLAN tagged frames and separate VLAN-specific netdevs added using
  *	vconfig similarly to the Ethernet case.
  *
+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL)
+ *	feature, which prevents bufferbloat by using the expected transmission
+ *	time to limit the amount of data buffered in the hardware.
+ *
+ * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
+ *	and can receive key configuration for BIGTK using key indexes 6 and 7.
+ *
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the
+ *	forwarding of preauth frames over the control port. They are then
+ *	handled as ordinary data frames.
+ *
+ * @NL80211_EXT_FEATURE_PROTECTED_TWT: Driver supports protected TWT frames
+ *
+ * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations
+ *      in IBSS mode, essentially by dropping their state.
+ *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
@@ -5563,6 +5730,11 @@
 	NL80211_EXT_FEATURE_STA_TX_PWR,
 	NL80211_EXT_FEATURE_SAE_OFFLOAD,
 	NL80211_EXT_FEATURE_VLAN_OFFLOAD,
+	NL80211_EXT_FEATURE_AQL,
+	NL80211_EXT_FEATURE_BEACON_PROTECTION,
+	NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH,
+	NL80211_EXT_FEATURE_PROTECTED_TWT,
+	NL80211_EXT_FEATURE_DEL_IBSS_STA,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
@@ -6185,12 +6357,14 @@
  * @NL80211_PREAMBLE_HT: HT preamble
  * @NL80211_PREAMBLE_VHT: VHT preamble
  * @NL80211_PREAMBLE_DMG: DMG preamble
+ * @NL80211_PREAMBLE_HE: HE preamble
  */
 enum nl80211_preamble {
 	NL80211_PREAMBLE_LEGACY,
 	NL80211_PREAMBLE_HT,
 	NL80211_PREAMBLE_VHT,
 	NL80211_PREAMBLE_DMG,
+	NL80211_PREAMBLE_HE,
 };
 
 /**
@@ -6383,6 +6557,10 @@
  *	is valid)
  * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating
  *	the maximum FTMs per burst (if not present anything is valid)
+ * @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if
+ *	trigger based ranging measurement is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating
+ *	if non trigger based ranging measurement is supported
  *
  * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal
  * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number
@@ -6398,6 +6576,8 @@
 	NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
 	NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
 	NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+	NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED,
+	NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED,
 
 	/* keep last */
 	NUM_NL80211_PMSR_FTM_CAPA_ATTR,
@@ -6427,6 +6607,20 @@
  * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag)
  * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data
  *	(flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED: request trigger based ranging
+ *	measurement (flag).
+ *	This attribute and %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED are
+ *	mutually exclusive.
+ *      if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ *	%NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ *	ranging will be used.
+ * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based
+ *	ranging measurement (flag)
+ *	This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are
+ *	mutually exclusive.
+ *      if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ *	%NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ *	ranging will be used.
  *
  * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
  * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6443,6 +6637,8 @@
 	NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES,
 	NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI,
 	NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
+	NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
+	NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
 
 	/* keep last */
 	NUM_NL80211_PMSR_FTM_REQ_ATTR,
@@ -6582,5 +6778,51 @@
 	NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
 };
 
+/**
+ * enum nl80211_bss_color_attributes - BSS Color attributes
+ * @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color.
+ * @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled.
+ * @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used..
+ *
+ * @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal
+ * @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute.
+ */
+enum nl80211_bss_color_attributes {
+	__NL80211_HE_BSS_COLOR_ATTR_INVALID,
+
+	NL80211_HE_BSS_COLOR_ATTR_COLOR,
+	NL80211_HE_BSS_COLOR_ATTR_DISABLED,
+	NL80211_HE_BSS_COLOR_ATTR_PARTIAL,
+
+	/* keep last */
+	__NL80211_HE_BSS_COLOR_ATTR_LAST,
+	NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_iftype_akm_attributes - interface type AKM attributes
+ * @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid
+ *
+ * @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag
+ *	attribute for each interface type that supports AKM suites specified in
+ *	%NL80211_IFTYPE_AKM_ATTR_SUITES
+ * @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported
+ *	AKM suites for the specified interface types.
+ *
+ * @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal
+ * @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute.
+ */
+enum nl80211_iftype_akm_attributes {
+	__NL80211_IFTYPE_AKM_ATTR_INVALID,
+
+	NL80211_IFTYPE_AKM_ATTR_IFTYPES,
+	NL80211_IFTYPE_AKM_ATTR_SUITES,
+
+	/* keep last */
+	__NL80211_IFTYPE_AKM_ATTR_LAST,
+	NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1,
+};
 
 #endif /* __LINUX_NL80211_H */
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 5a2ba26..2e79614 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -648,6 +648,8 @@
 
 
 
+#ifdef CONFIG_WEP
+
 /* Authenticator Key Transmit state machine */
 
 SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
@@ -726,6 +728,8 @@
 	}
 }
 
+#endif /* CONFIG_WEP */
+
 
 
 /* Controlled Directions state machine */
@@ -813,10 +817,12 @@
 
 	sm->portControl = Auto;
 
+#ifdef CONFIG_WEP
 	if (!eapol->conf.wpa &&
 	    (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
 		sm->keyTxEnabled = TRUE;
 	else
+#endif /* CONFIG_WEP */
 		sm->keyTxEnabled = FALSE;
 	if (eapol->conf.wpa)
 		sm->portValid = FALSE;
@@ -910,10 +916,12 @@
 		SM_STEP_RUN(BE_AUTH);
 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
 		SM_STEP_RUN(REAUTH_TIMER);
+#ifdef CONFIG_WEP
 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
 		SM_STEP_RUN(AUTH_KEY_TX);
 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
 		SM_STEP_RUN(KEY_RX);
+#endif /* CONFIG_WEP */
 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
 		SM_STEP_RUN(CTRL_DIR);
 
@@ -1167,7 +1175,9 @@
 	dst->ctx = src->ctx;
 	dst->eap_reauth_period = src->eap_reauth_period;
 	dst->wpa = src->wpa;
+#ifdef CONFIG_WEP
 	dst->individual_wep_key_len = src->individual_wep_key_len;
+#endif /* CONFIG_WEP */
 	os_free(dst->eap_req_id_text);
 	if (src->eap_req_id_text) {
 		dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
@@ -1221,10 +1231,12 @@
 		return NULL;
 	}
 
+#ifdef CONFIG_WEP
 	if (conf->individual_wep_key_len > 0) {
 		/* use key0 in individual key and key1 in broadcast key */
 		eapol->default_wep_key_idx = 1;
 	}
+#endif /* CONFIG_WEP */
 
 	eapol->cb.eapol_send = cb->eapol_send;
 	eapol->cb.aaa_send = cb->aaa_send;
@@ -1249,6 +1261,8 @@
 		return;
 
 	eapol_auth_conf_free(&eapol->conf);
+#ifdef CONFIG_WEP
 	os_free(eapol->default_wep_key);
+#endif /* CONFIG_WEP */
 	os_free(eapol);
 }
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index f1ca0a8..7f04b01 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -200,6 +200,15 @@
 }
 
 
+static int eapol_sm_confirm_auth(struct eapol_sm *sm)
+{
+	if (!sm->ctx->confirm_auth_cb)
+		return 0;
+
+	return sm->ctx->confirm_auth_cb(sm->ctx->ctx);
+}
+
+
 static void eapol_enable_timer_tick(struct eapol_sm *sm)
 {
 	if (sm->timer_tick_enabled)
@@ -316,6 +325,11 @@
 
 SM_STATE(SUPP_PAE, RESTART)
 {
+	if (eapol_sm_confirm_auth(sm)) {
+		/* Don't process restart, we are already reconnecting */
+		return;
+	}
+
 	SM_ENTRY(SUPP_PAE, RESTART);
 	sm->eapRestart = TRUE;
 	if (sm->altAccept) {
@@ -678,6 +692,7 @@
 
 static void eapol_sm_processKey(struct eapol_sm *sm)
 {
+#ifdef CONFIG_WEP
 #ifndef CONFIG_FIPS
 	struct ieee802_1x_hdr *hdr;
 	struct ieee802_1x_eapol_key *key;
@@ -828,7 +843,7 @@
 
 	if (sm->ctx->set_wep_key &&
 	    sm->ctx->set_wep_key(sm->ctx->ctx,
-				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
+				 !!(key->key_index & IEEE8021X_KEY_INDEX_FLAG),
 				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
 				 datakey, key_len) < 0) {
 		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
@@ -852,6 +867,7 @@
 		}
 	}
 #endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
 }
 
 
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index c9d7522..67f82c6 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -298,6 +298,15 @@
 	 * @len: Length of anonymous identity in octets
 	 */
 	void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+
+	/**
+	 * confirm_auth_cb - Callback confirming if we can install a new PTK
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * Returns: 0 when authentication can continue, -1 when reconnecting
+	 *
+	 * Automatically triggers a reconnect when not.
+	 */
+	int (*confirm_auth_cb)(void *ctx);
 };
 
 
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 79de09c..2dae6c6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -36,7 +36,7 @@
 /**
  * P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
  */
-#define P2P_MAX_REG_CLASS_CHANNELS 20
+#define P2P_MAX_REG_CLASS_CHANNELS 60
 
 /**
  * struct p2p_channels - List of supported channels
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 07240ea..be16e27 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -609,7 +609,7 @@
 {
 	if (msg->attr_used >= msg->attr_size) {
 		size_t *nattr_pos;
-		int nlen = msg->attr_size * 2;
+		size_t nlen = msg->attr_size * 2;
 
 		nattr_pos = os_realloc_array(msg->attr_pos, nlen,
 					     sizeof(*msg->attr_pos));
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index a3db404..2b7a604 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -457,7 +457,7 @@
 	}
 
 	/* retransmit; remove entry if too many attempts */
-	if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
+	if (entry->accu_attempts >= RADIUS_CLIENT_MAX_FAILOVER *
 	    RADIUS_CLIENT_NUM_FAILOVER * num_servers) {
 		wpa_printf(MSG_INFO,
 			   "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
@@ -507,7 +507,7 @@
 		if (now.sec >= entry->next_try) {
 			s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
 				radius->acct_sock;
-			if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
+			if (entry->attempts >= RADIUS_CLIENT_NUM_FAILOVER ||
 			    (s < 0 && entry->attempts > 0)) {
 				if (entry->msg_type == RADIUS_ACCT ||
 				    entry->msg_type == RADIUS_ACCT_INTERIM)
@@ -1116,7 +1116,7 @@
 		    (!auth && entry->msg_type != RADIUS_ACCT))
 			continue;
 		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
-		entry->attempts = 1;
+		entry->attempts = 0;
 		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
 	}
 
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index fa5215c..e46c89a 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -270,7 +270,9 @@
 	wpas_notify_pmk_cache_added((struct wpa_supplicant *)pmksa->sm->ctx->ctx, entry);
 	wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid,
 			 entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
-			 entry->pmk, entry->pmk_len);
+			 entry->pmk, entry->pmk_len,
+			 pmksa->sm->dot11RSNAConfigPMKLifetime,
+			 pmksa->sm->dot11RSNAConfigPMKReauthThreshold);
 
 	return entry;
 }
@@ -374,9 +376,12 @@
 {
 	struct rsn_pmksa_cache_entry *new_entry;
 	os_time_t old_expiration = old_entry->expiration;
+	const u8 *pmkid = NULL;
 
+	if (wpa_key_mgmt_sae(old_entry->akmp))
+		pmkid = old_entry->pmkid;
 	new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
-				    NULL, NULL, 0,
+				    pmkid, NULL, 0,
 				    aa, pmksa->sm->own_addr,
 				    old_entry->network_ctx, old_entry->akmp,
 				    old_entry->fils_cache_id_set ?
@@ -416,6 +421,20 @@
 	while (entry) {
 		if (entry->network_ctx == network_ctx &&
 		    (!akmp || entry->akmp == akmp)) {
+			struct os_reltime now;
+
+			if (wpa_key_mgmt_sae(entry->akmp) &&
+			    os_get_reltime(&now) == 0 &&
+			    entry->reauth_time < now.sec) {
+				wpa_printf(MSG_DEBUG,
+					   "RSN: Do not clone PMKSA cache entry for "
+					   MACSTR
+					   " since its reauth threshold has passed",
+					   MAC2STR(entry->aa));
+				entry = entry->next;
+				continue;
+			}
+
 			entry = pmksa_cache_clone_entry(pmksa, entry, aa);
 			if (entry) {
 				wpa_printf(MSG_DEBUG, "RSN: added "
@@ -519,6 +538,20 @@
 							      network_ctx,
 							      fils_cache_id);
 	if (sm->cur_pmksa) {
+		struct os_reltime now;
+
+		if (wpa_key_mgmt_sae(sm->cur_pmksa->akmp) &&
+		    os_get_reltime(&now) == 0 &&
+		    sm->cur_pmksa->reauth_time < now.sec) {
+			wpa_printf(MSG_DEBUG,
+				   "RSN: Do not allow PMKSA cache entry for "
+				   MACSTR
+				   " to be used for SAE since its reauth threshold has passed",
+				   MAC2STR(sm->cur_pmksa->aa));
+			sm->cur_pmksa = NULL;
+			return -1;
+		}
+
 		wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
 			    sm->cur_pmksa->pmkid, PMKID_LEN);
 		return 0;
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d0c43f4..a101921 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -49,6 +49,15 @@
 }
 
 
+static int rsn_preauth_key_mgmt(int akmp)
+{
+	return !!(akmp & (WPA_KEY_MGMT_IEEE8021X |
+			  WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			  WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+			  WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+}
+
+
 static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
 				const u8 *buf, size_t len)
 {
@@ -311,10 +320,7 @@
 	if (sm->preauth_eapol ||
 	    sm->proto != WPA_PROTO_RSN ||
 	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
-	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
-	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
-	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
-	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
+	    !rsn_preauth_key_mgmt(sm->key_mgmt)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
 			"state for new pre-authentication");
 		return; /* invalid state for new pre-auth */
@@ -343,7 +349,7 @@
 		 * PMKIDs again, so report the existing data now. */
 		if (p) {
 			wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
-					 NULL, p->pmk, p->pmk_len);
+					 NULL, p->pmk, p->pmk_len, 0, 0);
 		}
 
 		dl_list_del(&candidate->list);
@@ -488,6 +494,9 @@
 		      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
 		return;
 
+	if (!rsn_preauth_key_mgmt(ie.key_mgmt))
+		return;
+
 	/* Give less priority to candidates found from normal scan results. */
 	pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
 			    ie.capabilities & WPA_CAPABILITY_PREAUTH);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 704c95e..7b47e3a 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -178,7 +178,7 @@
 static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 {
 	if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
-			   0, 0, NULL, 0, NULL, 0) < 0) {
+			   0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) {
 		wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
 			   "the driver");
 		return -1;
@@ -227,8 +227,9 @@
 
 	wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
 		   MAC2STR(peer->addr));
-	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
-			   rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+	if (wpa_sm_set_key(sm, alg, peer->addr, 0, 1, rsc, sizeof(rsc),
+			   peer->tpk.tk, key_len,
+			   KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
 			   "driver");
 		return -1;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 892eece..166d6ee 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -183,6 +183,14 @@
 	int key_info, ver;
 	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_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: PTK0 rekey not allowed, reconnecting");
+		wpa_sm_reconnect(sm);
+		return;
+	}
+
 	if (wpa_use_akm_defined(sm->key_mgmt))
 		ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
 	else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
@@ -570,6 +578,7 @@
 {
 	const u8 *z = NULL;
 	size_t z_len = 0;
+	int akmp;
 
 #ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->key_mgmt))
@@ -583,13 +592,67 @@
 	}
 #endif /* CONFIG_DPP2 */
 
+	akmp = sm->key_mgmt;
+#ifdef CONFIG_OWE
+	if (sm->owe_ptk_workaround && akmp == WPA_KEY_MGMT_OWE &&
+	    sm->pmk_len > 32) {
+		wpa_printf(MSG_DEBUG,
+			   "OWE: Force SHA256 for PTK derivation");
+		akmp |= WPA_KEY_MGMT_PSK_SHA256;
+	}
+#endif /* CONFIG_OWE */
 	return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
 			      sm->own_addr, sm->bssid, sm->snonce,
-			      key->key_nonce, ptk, sm->key_mgmt,
+			      key->key_nonce, ptk, akmp,
 			      sm->pairwise_cipher, z, z_len);
 }
 
 
+static int wpa_handle_ext_key_id(struct wpa_sm *sm,
+				 struct wpa_eapol_ie_parse *kde)
+{
+	if (sm->ext_key_id) {
+		u16 key_id;
+
+		if (!kde->key_id) {
+			wpa_msg(sm->ctx->msg_ctx,
+				sm->use_ext_key_id ? MSG_INFO : MSG_DEBUG,
+				"RSN: No Key ID in Extended Key ID handshake");
+			sm->keyidx_active = 0;
+			return sm->use_ext_key_id ? -1 : 0;
+		}
+
+		key_id = kde->key_id[0] & 0x03;
+		if (key_id > 1) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"RSN: Invalid Extended Key ID: %d", key_id);
+			return -1;
+		}
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: Using Extended Key ID %d", key_id);
+		sm->keyidx_active = key_id;
+		sm->use_ext_key_id = 1;
+	} else {
+		if (kde->key_id && (kde->key_id[0] & 0x03)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"RSN: Non-zero Extended Key ID Key ID in PTK0 handshake");
+			return -1;
+		}
+
+		if (kde->key_id) {
+			/* This is not supposed to be included here, but ignore
+			 * the case of matching Key ID 0 just in case. */
+			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"RSN: Extended Key ID Key ID 0 in PTK0 handshake");
+		}
+		sm->keyidx_active = 0;
+		sm->use_ext_key_id = 0;
+	}
+
+	return 0;
+}
+
+
 static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
 					  const unsigned char *src_addr,
 					  const struct wpa_eapol_key *key,
@@ -608,6 +671,14 @@
 		return;
 	}
 
+	if (sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
+	    wpa_sm_get_state(sm) == WPA_COMPLETED) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: PTK0 rekey not allowed, reconnecting");
+		wpa_sm_reconnect(sm);
+		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);
@@ -789,7 +860,8 @@
 
 
 static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
-				      const struct wpa_eapol_key *key)
+				      const struct wpa_eapol_key *key,
+				      enum key_flag key_flag)
 {
 	int keylen, rsclen;
 	enum wpa_alg alg;
@@ -833,12 +905,14 @@
 		wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
 	}
 
-	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
-			   sm->ptk.tk, keylen) < 0) {
+	if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc,
+			   rsclen, sm->ptk.tk, keylen,
+			   KEY_FLAG_PAIRWISE | key_flag) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-			"WPA: Failed to set PTK to the "
-			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
-			alg, keylen, MAC2STR(sm->bssid));
+			"WPA: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
+			MACSTR " idx=%d key_flag=0x%x)",
+			alg, keylen, MAC2STR(sm->bssid),
+			sm->keyidx_active, key_flag);
 		return -1;
 	}
 
@@ -852,7 +926,23 @@
 		eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
 				       sm, NULL);
 	}
+	return 0;
+}
 
+
+static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
+{
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Activate PTK (idx=%d bssid=" MACSTR ")",
+		sm->keyidx_active, MAC2STR(sm->bssid));
+
+	if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, 0, NULL, 0,
+			   NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to activate PTK for TX (idx=%d bssid="
+			MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
+		return -1;
+	}
 	return 0;
 }
 
@@ -927,7 +1017,8 @@
 	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
 		if (wpa_sm_set_key(sm, gd->alg, NULL,
 				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
-				   _gtk, gd->gtk_len) < 0) {
+				   _gtk, gd->gtk_len,
+				   KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Failed to set GTK to the driver "
 				"(Group only)");
@@ -936,7 +1027,7 @@
 		}
 	} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
 				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
-				  _gtk, gd->gtk_len) < 0) {
+				  _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Failed to set GTK to "
 			"the driver (alg=%d keylen=%d keyidx=%d)",
@@ -1090,7 +1181,7 @@
 	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
 			   broadcast_ether_addr,
 			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
-			   igtk->igtk, len) < 0) {
+			   igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) {
 		if (keyidx == 0x0400 || keyidx == 0x0500) {
 			/* Assume the AP has broken PMF implementation since it
 			 * seems to have swapped the KeyID bytes. The AP cannot
@@ -1127,14 +1218,66 @@
 }
 
 
+static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
+				       const struct wpa_bigtk_kde *bigtk,
+				       int wnm_sleep)
+{
+	size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+	u16 keyidx = WPA_GET_LE16(bigtk->keyid);
+
+	/* Detect possible key reinstallation */
+	if ((sm->bigtk.bigtk_len == len &&
+	     os_memcmp(sm->bigtk.bigtk, bigtk->bigtk,
+		       sm->bigtk.bigtk_len) == 0) ||
+	    (sm->bigtk_wnm_sleep.bigtk_len == len &&
+	     os_memcmp(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+		       sm->bigtk_wnm_sleep.bigtk_len) == 0)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)",
+			keyidx);
+		return  0;
+	}
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: BIGTK keyid %d pn " COMPACT_MACSTR,
+		keyidx, MAC2STR(bigtk->pn));
+	wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len);
+	if (keyidx < 6 || keyidx > 7) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Invalid BIGTK KeyID %d", keyidx);
+		return -1;
+	}
+	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+			   broadcast_ether_addr,
+			   keyidx, 0, bigtk->pn, sizeof(bigtk->pn),
+			   bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to configure BIGTK to the driver");
+		return -1;
+	}
+
+	if (wnm_sleep) {
+		sm->bigtk_wnm_sleep.bigtk_len = len;
+		os_memcpy(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+			  sm->bigtk_wnm_sleep.bigtk_len);
+	} else {
+		sm->bigtk.bigtk_len = len;
+		os_memcpy(sm->bigtk.bigtk, bigtk->bigtk, sm->bigtk.bigtk_len);
+	}
+
+	return 0;
+}
+
+
 static int ieee80211w_set_keys(struct wpa_sm *sm,
 			       struct wpa_eapol_ie_parse *ie)
 {
+	size_t len;
+
 	if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
 		return 0;
 
 	if (ie->igtk) {
-		size_t len;
 		const struct wpa_igtk_kde *igtk;
 
 		len = wpa_cipher_key_len(sm->mgmt_group_cipher);
@@ -1146,6 +1289,18 @@
 			return -1;
 	}
 
+	if (ie->bigtk && sm->beacon_prot) {
+		const struct wpa_bigtk_kde *bigtk;
+
+		len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+		if (ie->bigtk_len != WPA_BIGTK_KDE_PREFIX_LEN + len)
+			return -1;
+
+		bigtk = (const struct wpa_bigtk_kde *) ie->bigtk;
+		if (wpa_supplicant_install_bigtk(sm, bigtk, 0) < 0)
+			return -1;
+	}
+
 	return 0;
 }
 
@@ -1332,11 +1487,10 @@
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Could not find AP from "
 				"the scan results");
-		} else {
-			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
-				"WPA: Found the current AP from "
-				"updated scan results");
+			return -1;
 		}
+		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: Found the current AP from updated scan results");
 	}
 
 	if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
@@ -1380,6 +1534,11 @@
 	      os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+		wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+			    sm->ap_rsnxe, sm->ap_rsnxe_len);
+		wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
+			    ie->rsnxe, ie->rsnxe_len);
+		wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
 		return -1;
 	}
 
@@ -1486,6 +1645,9 @@
 	if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
 		goto failed;
 
+	if (wpa_handle_ext_key_id(sm, &ie))
+		goto failed;
+
 	if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: ANonce from message 1 of 4-Way Handshake "
@@ -1531,6 +1693,10 @@
 	}
 #endif /* CONFIG_OCV */
 
+	if (sm->use_ext_key_id &&
+	    wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX))
+		goto failed;
+
 	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
 				       &sm->ptk) < 0) {
 		goto failed;
@@ -1542,7 +1708,14 @@
 	sm->renew_snonce = 1;
 
 	if (key_info & WPA_KEY_INFO_INSTALL) {
-		if (wpa_supplicant_install_ptk(sm, key))
+		int res;
+
+		if (sm->use_ext_key_id)
+			res = wpa_supplicant_activate_ptk(sm);
+		else
+			res = wpa_supplicant_install_ptk(sm, key,
+							 KEY_FLAG_RX_TX);
+		if (res)
 			goto failed;
 	}
 
@@ -1598,6 +1771,8 @@
 			sm->cur_pmksa = sa;
 	}
 
+	if (ie.transition_disable)
+		wpa_sm_transition_disable(sm, ie.transition_disable[0]);
 	sm->msg_3_of_4_ok = 1;
 	return;
 
@@ -2784,6 +2959,8 @@
 #ifdef CONFIG_P2P
 	os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
 #endif /* CONFIG_P2P */
+
+	sm->keyidx_active = 0;
 }
 
 
@@ -2815,6 +2992,7 @@
 
 	/* Keys are not needed in the WPA state machine anymore */
 	wpa_sm_drop_sa(sm);
+	sm->keyidx_active = 0;
 
 	sm->msg_3_of_4_ok = 0;
 	os_memset(sm->bssid, 0, ETH_ALEN);
@@ -2910,7 +3088,7 @@
 
 
 /**
- * wpa_sm_set_config - Notification of current configration change
+ * wpa_sm_set_config - Notification of current configuration change
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
  * @config: Pointer to current network configuration
  *
@@ -2937,6 +3115,7 @@
 		sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
 		sm->p2p = config->p2p;
 		sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
+		sm->owe_ptk_workaround = config->owe_ptk_workaround;
 #ifdef CONFIG_FILS
 		if (config->fils_cache_id) {
 			sm->fils_cache_id_set = 1;
@@ -2946,6 +3125,7 @@
 			sm->fils_cache_id_set = 0;
 		}
 #endif /* CONFIG_FILS */
+		sm->beacon_prot = config->beacon_prot;
 	} else {
 		sm->network_ctx = NULL;
 		sm->allowed_pairwise_cipher = 0;
@@ -2956,6 +3136,8 @@
 		sm->wpa_ptk_rekey = 0;
 		sm->p2p = 0;
 		sm->wpa_rsc_relaxation = 0;
+		sm->owe_ptk_workaround = 0;
+		sm->beacon_prot = 0;
 	}
 }
 
@@ -3061,6 +3243,15 @@
 	case WPA_PARAM_SAE_PWE:
 		sm->sae_pwe = value;
 		break;
+	case WPA_PARAM_DENY_PTK0_REKEY:
+		sm->wpa_deny_ptk0_rekey = value;
+		break;
+	case WPA_PARAM_EXT_KEY_ID:
+		sm->ext_key_id = value;
+		break;
+	case WPA_PARAM_USE_EXT_KEY_ID:
+		sm->use_ext_key_id = value;
+		break;
 	default:
 		break;
 	}
@@ -3135,6 +3326,18 @@
 }
 
 
+int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+	return sm ? sm->ext_key_id : 0;
+}
+
+
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+	return sm ? sm->use_ext_key_id : 0;
+}
+
+
 int wpa_sm_ocv_enabled(struct wpa_sm *sm)
 {
 	struct wpa_ie_data rsn;
@@ -3510,6 +3713,14 @@
 }
 
 
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
+{
+	if (!sm)
+		return 0;
+	return sm->ptk.installed;
+}
+
+
 void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
 {
 	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
@@ -3570,6 +3781,13 @@
 		igtk = (const struct wpa_igtk_kde *) (buf + 2);
 		if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
 			return -1;
+	} else if (subelem_id == WNM_SLEEP_SUBELEM_BIGTK) {
+		const struct wpa_bigtk_kde *bigtk;
+
+		bigtk = (const struct wpa_bigtk_kde *) (buf + 2);
+		if (sm->beacon_prot &&
+		    wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0)
+			return -1;
 	} else {
 		wpa_printf(MSG_DEBUG, "Unknown element id");
 		return -1;
@@ -3753,13 +3971,13 @@
 	wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
 	wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
 
-	/* FILS Wrapped Data */
+	/* Wrapped Data */
 	sm->fils_erp_pmkid_set = 0;
 	if (erp_msg) {
 		wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
 		wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
 		/* Element ID Extension */
-		wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+		wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
 		wpabuf_put_buf(buf, erp_msg);
 		/* Calculate pending PMKID here so that we do not need to
 		 * maintain a copy of the EAP-Initiate/Reauth message. */
@@ -3964,16 +4182,16 @@
 		goto fail;
 	}
 
-	/* FILS Wrapped Data */
-	if (!sm->cur_pmksa && elems.fils_wrapped_data) {
+	/* Wrapped Data */
+	if (!sm->cur_pmksa && elems.wrapped_data) {
 		u8 rmsk[ERP_MAX_KEY_LEN];
 		size_t rmsk_len;
 
 		wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
-			    elems.fils_wrapped_data,
-			    elems.fils_wrapped_data_len);
-		eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
-					    elems.fils_wrapped_data_len);
+			    elems.wrapped_data,
+			    elems.wrapped_data_len);
+		eapol_sm_process_erp_finish(sm->eapol, elems.wrapped_data,
+					    elems.wrapped_data_len);
 		if (eapol_sm_failed(sm->eapol))
 			goto fail;
 
@@ -4135,6 +4353,8 @@
 		capab |= WPA_CAPABILITY_MFPR;
 	if (sm->ocv)
 		capab |= WPA_CAPABILITY_OCVC;
+	if (sm->ext_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
 	wpabuf_put_le16(buf, capab);
 
 	/* PMKID Count */
@@ -4562,11 +4782,12 @@
 			   keylen, (long unsigned int) sm->ptk.tk_len);
 		goto fail;
 	}
+
 	rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
 	wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
 			sm->ptk.tk, keylen);
 	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
-			   sm->ptk.tk, keylen) < 0) {
+			   sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
 			MACSTR ")",
@@ -4590,6 +4811,9 @@
 	sm->fils_completed = 1;
 	forced_memzero(&gd, sizeof(gd));
 
+	if (kde.transition_disable)
+		wpa_sm_transition_disable(sm, kde.transition_disable[0]);
+
 	return 0;
 fail:
 	forced_memzero(&gd, sizeof(gd));
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f1fbb1b..796f392 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -27,10 +27,11 @@
 	void (*set_state)(void *ctx, enum wpa_states state);
 	enum wpa_states (*get_state)(void *ctx);
 	void (*deauthenticate)(void * ctx, u16 reason_code);
+	void (*reconnect)(void *ctx);
 	int (*set_key)(void *ctx, enum wpa_alg alg,
 		       const u8 *addr, int key_idx, int set_tx,
 		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
+		       const u8 *key, size_t key_len, enum key_flag key_flag);
 	void * (*get_network_ctx)(void *ctx);
 	int (*get_bssid)(void *ctx, u8 *bssid);
 	int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
@@ -41,7 +42,8 @@
 			    size_t *msg_len, void **data_pos);
 	int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
 			 const u8 *pmkid, const u8 *fils_cache_id,
-			 const u8 *pmk, size_t pmk_len);
+			 const u8 *pmk, size_t pmk_len, u32 pmk_lifetime,
+			 u8 pmk_reauth_threshold);
 	int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
 			    const u8 *pmkid, const u8 *fils_cache_id);
 	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
@@ -84,6 +86,7 @@
 	void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
 			    const u8 *pkt, size_t pkt_len);
 	int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+	void (*transition_disable)(void *ctx, u8 bitmap);
 };
 
 
@@ -100,6 +103,9 @@
 	WPA_PARAM_MFP,
 	WPA_PARAM_OCV,
 	WPA_PARAM_SAE_PWE,
+	WPA_PARAM_DENY_PTK0_REKEY,
+	WPA_PARAM_EXT_KEY_ID,
+	WPA_PARAM_USE_EXT_KEY_ID,
 };
 
 struct rsn_supp_config {
@@ -111,9 +117,12 @@
 	const u8 *ssid;
 	size_t ssid_len;
 	int wpa_ptk_rekey;
+	int wpa_deny_ptk0_rekey;
 	int p2p;
 	int wpa_rsc_relaxation;
+	int owe_ptk_workaround;
 	const u8 *fils_cache_id;
+	int beacon_prot;
 };
 
 #ifndef CONFIG_NO_WPA
@@ -149,6 +158,8 @@
 int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
 		      int verbose);
 int wpa_sm_pmf_enabled(struct wpa_sm *sm);
+int wpa_sm_ext_key_id(struct wpa_sm *sm);
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm);
 int wpa_sm_ocv_enabled(struct wpa_sm *sm);
 
 void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -172,6 +183,7 @@
 			const void *network_ctx);
 void wpa_sm_drop_sa(struct wpa_sm *sm);
 int wpa_sm_has_ptk(struct wpa_sm *sm);
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
 
 void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
 
@@ -294,6 +306,16 @@
 	return 0;
 }
 
+static inline int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+static inline int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+	return 0;
+}
+
 static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
 {
 	return 0;
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 2b8b41f..203a61c 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -82,23 +82,30 @@
 	if (sm == NULL)
 		return 0;
 
+	if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) {
+		os_free(sm->assoc_resp_ies);
+		sm->assoc_resp_ies = NULL;
+		sm->assoc_resp_ies_len = 0;
+		os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+		os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN);
+		sm->r0kh_id_len = 0;
+		os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+		return 0;
+	}
+
 	use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
 	if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
 		return -1;
 
-	if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
+	if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
 		return -1;
 
-	if (ft.mdie) {
-		wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
-			    ft.mdie, MOBILITY_DOMAIN_ID_LEN);
-		os_memcpy(sm->mobility_domain, ft.mdie,
-			  MOBILITY_DOMAIN_ID_LEN);
-		sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
-		wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
-			   sm->mdie_ft_capab);
-	} else
-		os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
+		    ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+	os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+	sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
+	wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
+		   sm->mdie_ft_capab);
 
 	if (ft.r0kh_id) {
 		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
@@ -125,10 +132,10 @@
 	sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
 	if (sm->assoc_resp_ies) {
 		u8 *pos = sm->assoc_resp_ies;
-		if (ft.mdie) {
-			os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
-			pos += ft.mdie_len + 2;
-		}
+
+		os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
+		pos += ft.mdie_len + 2;
+
 		if (ft.ftie) {
 			os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
 			pos += ft.ftie_len + 2;
@@ -155,6 +162,7 @@
  * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
  * @ric_ies_len: Length of ric_ies buffer in octets
  * @ap_mdie: Mobility Domain IE from the target AP
+ * @omit_rsnxe: Whether RSNXE is omitted from Reassociation Request frame
  * Returns: Pointer to buffer with IEs or %NULL on failure
  *
  * Caller is responsible for freeing the returned buffer with os_free();
@@ -164,16 +172,16 @@
 			       const u8 *kck, size_t kck_len,
 			       const u8 *target_ap,
 			       const u8 *ric_ies, size_t ric_ies_len,
-			       const u8 *ap_mdie)
+			       const u8 *ap_mdie, int omit_rsnxe)
 {
 	size_t buf_len;
 	u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
 	struct rsn_mdie *mdie;
 	struct rsn_ie_hdr *rsnie;
-	u16 capab;
 	int mdie_len;
 	u8 rsnxe[10];
 	size_t rsnxe_len;
+	int rsnxe_used;
 	int res;
 
 	sm->ft_completed = 0;
@@ -249,14 +257,7 @@
 	pos += RSN_SELECTOR_LEN;
 
 	/* RSN Capabilities */
-	capab = 0;
-	if (sm->mfp)
-		capab |= WPA_CAPABILITY_MFPC;
-	if (sm->mfp == 2)
-		capab |= WPA_CAPABILITY_MFPR;
-	if (sm->ocv)
-		capab |= WPA_CAPABILITY_OCVC;
-	WPA_PUT_LE16(pos, capab);
+	WPA_PUT_LE16(pos, rsn_supp_capab(sm));
 	pos += 2;
 
 	/* PMKID Count */
@@ -302,10 +303,13 @@
 	ftie_pos = pos;
 	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
 	ftie_len = pos++;
+	rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && anonce &&
+		(sm->sae_pwe == 1 || sm->sae_pwe == 2);
 	if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
 		struct rsn_ftie_sha384 *ftie;
 
 		ftie = (struct rsn_ftie_sha384 *) pos;
+		ftie->mic_control[0] = !!rsnxe_used;
 		fte_mic = ftie->mic;
 		elem_count = &ftie->mic_control[1];
 		pos += sizeof(*ftie);
@@ -316,6 +320,7 @@
 		struct rsn_ftie *ftie;
 
 		ftie = (struct rsn_ftie *) pos;
+		ftie->mic_control[0] = !!rsnxe_used;
 		fte_mic = ftie->mic;
 		elem_count = &ftie->mic_control[1];
 		pos += sizeof(*ftie);
@@ -363,12 +368,16 @@
 		pos += ric_ies_len;
 	}
 
-	res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
-	if (res < 0) {
-		os_free(buf);
-		return NULL;
+	if (omit_rsnxe) {
+		rsnxe_len = 0;
+	} else {
+		res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
+		if (res < 0) {
+			os_free(buf);
+			return NULL;
+		}
+		rsnxe_len = res;
 	}
-	rsnxe_len = res;
 
 	if (kck) {
 		/*
@@ -422,8 +431,9 @@
 	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
 	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
 
-	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
-			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
+	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc),
+			   (u8 *) sm->ptk.tk, keylen,
+			   KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
 		return -1;
 	}
@@ -450,7 +460,7 @@
 	}
 
 	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-				    NULL, 0, sm->bssid, NULL, 0, mdie);
+				    NULL, 0, sm->bssid, NULL, 0, mdie, 0);
 	if (ft_ies) {
 		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
 				     ft_ies, ft_ies_len);
@@ -646,7 +656,8 @@
 				    sm->pmk_r1_name,
 				    kck, kck_len, bssid,
 				    ric_ies, ric_ies_len,
-				    parse.mdie ? parse.mdie - 2 : NULL);
+				    parse.mdie ? parse.mdie - 2 : NULL,
+				    !sm->ap_rsnxe);
 	if (ft_ies) {
 		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
 				     ft_ies, ft_ies_len);
@@ -773,7 +784,8 @@
 		os_memcpy(gtk + 24, tmp, 8);
 	}
 	if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
-			   gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+			   gtk_elem + 3, rsc_len, gtk, keylen,
+			   KEY_FLAG_GROUP_RX) < 0) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
 			   "driver.");
 		return -1;
@@ -840,7 +852,8 @@
 			igtk_len);
 	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
 			   broadcast_ether_addr, keyidx, 0,
-			   igtk_elem + 2, 6, igtk, igtk_len) < 0) {
+			   igtk_elem + 2, 6, igtk, igtk_len,
+			   KEY_FLAG_GROUP_RX) < 0) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
 			   "driver.");
 		forced_memzero(igtk, sizeof(igtk));
@@ -852,6 +865,74 @@
 }
 
 
+static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem,
+				       size_t bigtk_elem_len)
+{
+	u8 bigtk[WPA_BIGTK_MAX_LEN];
+	size_t bigtk_len;
+	u16 keyidx;
+	const u8 *kek;
+	size_t kek_len;
+
+	if (!sm->beacon_prot || !bigtk_elem ||
+	    (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC &&
+	     sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_128 &&
+	     sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256 &&
+	     sm->mgmt_group_cipher != WPA_CIPHER_BIP_CMAC_256))
+		return 0;
+
+	if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+		kek = sm->ptk.kek2;
+		kek_len = sm->ptk.kek2_len;
+	} else {
+		kek = sm->ptk.kek;
+		kek_len = sm->ptk.kek_len;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: Received BIGTK in Reassoc Resp",
+			bigtk_elem, bigtk_elem_len);
+
+	bigtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+	if (bigtk_elem_len != 2 + 6 + 1 + bigtk_len + 8) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: Invalid BIGTK sub-elem length %lu",
+			   (unsigned long) bigtk_elem_len);
+		return -1;
+	}
+	if (bigtk_elem[8] != bigtk_len) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: Invalid BIGTK sub-elem Key Length %d",
+			   bigtk_elem[8]);
+		return -1;
+	}
+
+	if (aes_unwrap(kek, kek_len, bigtk_len / 8, bigtk_elem + 9, bigtk)) {
+		wpa_printf(MSG_WARNING,
+			   "FT: AES unwrap failed - could not decrypt BIGTK");
+		return -1;
+	}
+
+	/* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+	keyidx = WPA_GET_LE16(bigtk_elem);
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk,
+			bigtk_len);
+	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+			   broadcast_ether_addr, keyidx, 0,
+			   bigtk_elem + 2, 6, bigtk, bigtk_len,
+			   KEY_FLAG_GROUP_RX) < 0) {
+		wpa_printf(MSG_WARNING,
+			   "WPA: Failed to set BIGTK to the driver");
+		forced_memzero(bigtk, sizeof(bigtk));
+		return -1;
+	}
+	forced_memzero(bigtk, sizeof(bigtk));
+
+	return 0;
+}
+
+
 int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
 				 size_t ies_len, const u8 *src_addr)
 {
@@ -864,6 +945,7 @@
 	int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
 	const u8 *anonce, *snonce, *fte_mic;
 	u8 fte_elem_count;
+	int own_rsnxe_used, rsnxe_used;
 
 	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
 
@@ -902,6 +984,7 @@
 
 		anonce = ftie->anonce;
 		snonce = ftie->snonce;
+		rsnxe_used = ftie->mic_control[0] & 0x01;
 		fte_elem_count = ftie->mic_control[1];
 		fte_mic = ftie->mic;
 	} else {
@@ -915,6 +998,7 @@
 
 		anonce = ftie->anonce;
 		snonce = ftie->snonce;
+		rsnxe_used = ftie->mic_control[0] & 0x01;
 		fte_elem_count = ftie->mic_control[1];
 		fte_mic = ftie->mic;
 	}
@@ -1012,6 +1096,58 @@
 		return -1;
 	}
 
+	if (rsnxe_used && !sm->ap_rsnxe) {
+		wpa_printf(MSG_INFO,
+			   "FT: FTE indicated that AP uses RSNXE, but RSNXE was not included in Beacon/Probe Response frames");
+		return -1;
+	}
+
+	if (!sm->ap_rsn_ie) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"FT: No RSNE for this AP known - trying to get from scan results");
+		if (wpa_sm_get_beacon_ie(sm) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"FT: Could not find AP from the scan results");
+			return -1;
+		}
+		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"FT: Found the current AP from updated scan results");
+	}
+
+	if (sm->ap_rsn_ie &&
+	    wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+			       sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+			       parse.rsn - 2, parse.rsn_len + 2)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+		wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
+			    sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+		wpa_hexdump(MSG_INFO,
+			    "RSNE in FT protocol Reassociation Response frame",
+			    parse.rsn ? parse.rsn - 2 : NULL,
+			    parse.rsn ? parse.rsn_len + 2 : 0);
+		return -1;
+	}
+
+	own_rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) &&
+		(sm->sae_pwe == 1 || sm->sae_pwe == 2);
+	if ((sm->ap_rsnxe && !parse.rsnxe && own_rsnxe_used) ||
+	    (!sm->ap_rsnxe && parse.rsnxe) ||
+	    (sm->ap_rsnxe && parse.rsnxe &&
+	     (sm->ap_rsnxe_len != 2 + parse.rsnxe_len ||
+	      os_memcmp(sm->ap_rsnxe, parse.rsnxe - 2,
+			sm->ap_rsnxe_len) != 0))) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"FT: RSNXE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+		wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+			    sm->ap_rsnxe, sm->ap_rsnxe_len);
+		wpa_hexdump(MSG_INFO,
+			    "RSNXE in FT protocol Reassociation Response frame",
+			    parse.rsnxe ? parse.rsnxe - 2 : NULL,
+			    parse.rsnxe ? parse.rsnxe_len + 2 : 0);
+		return -1;
+	}
+
 #ifdef CONFIG_OCV
 	if (wpa_sm_ocv_enabled(sm)) {
 		struct wpa_channel_info ci;
@@ -1033,10 +1169,9 @@
 
 	sm->ft_reassoc_completed = 1;
 
-	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
-		return -1;
-
-	if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
+	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 ||
+	    wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 ||
+	    wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0)
 		return -1;
 
 	if (sm->set_ptk_after_assoc) {
@@ -1083,7 +1218,7 @@
 	}
 
 	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-				    NULL, 0, target_ap, NULL, 0, mdie);
+				    NULL, 0, target_ap, NULL, 0, mdie, 0);
 	if (ft_ies) {
 		sm->over_the_ds_in_progress = 1;
 		os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 2a43342..1ad75dc 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -33,6 +33,8 @@
 	struct wpa_gtk gtk_wnm_sleep;
 	struct wpa_igtk igtk;
 	struct wpa_igtk igtk_wnm_sleep;
+	struct wpa_bigtk bigtk;
+	struct wpa_bigtk bigtk_wnm_sleep;
 
 	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
 
@@ -61,8 +63,15 @@
 	u8 ssid[32];
 	size_t ssid_len;
 	int wpa_ptk_rekey;
+	int wpa_deny_ptk0_rekey:1;
 	int p2p;
 	int wpa_rsc_relaxation;
+	int owe_ptk_workaround;
+	int beacon_prot;
+	int ext_key_id; /* whether Extended Key ID is enabled */
+	int use_ext_key_id; /* whether Extended Key ID has been detected
+			     * to be used */
+	int keyidx_active; /* Key ID for the active TK */
 
 	u8 own_addr[ETH_ALEN];
 	const char *ifname;
@@ -198,11 +207,18 @@
 static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
 				 const u8 *addr, int key_idx, int set_tx,
 				 const u8 *seq, size_t seq_len,
-				 const u8 *key, size_t key_len)
+				 const u8 *key, size_t key_len,
+				 enum key_flag key_flag)
 {
 	WPA_ASSERT(sm->ctx->set_key);
 	return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
-				seq, seq_len, key, key_len);
+				seq, seq_len, key, key_len, key_flag);
+}
+
+static inline void wpa_sm_reconnect(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->reconnect);
+	sm->ctx->reconnect(sm->ctx->ctx);
 }
 
 static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
@@ -248,11 +264,13 @@
 static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
 				   const u8 *bssid, const u8 *pmkid,
 				   const u8 *cache_id, const u8 *pmk,
-				   size_t pmk_len)
+				   size_t pmk_len, u32 pmk_lifetime,
+				   u8 pmk_reauth_threshold)
 {
 	WPA_ASSERT(sm->ctx->add_pmkid);
 	return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
-				  cache_id, pmk, pmk_len);
+				  cache_id, pmk, pmk_len, pmk_lifetime,
+				  pmk_reauth_threshold);
 }
 
 static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
@@ -410,6 +428,12 @@
 	return sm->ctx->channel_info(sm->ctx->ctx, ci);
 }
 
+static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap)
+{
+	if (sm->ctx->transition_disable)
+		sm->ctx->transition_disable(sm->ctx->ctx, bitmap);
+}
+
 
 int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
 		       int ver, const u8 *dest, u16 proto,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 03c0d7e..9068781 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -105,6 +105,23 @@
 }
 
 
+u16 rsn_supp_capab(struct wpa_sm *sm)
+{
+	u16 capab = 0;
+
+	if (sm->mfp)
+		capab |= WPA_CAPABILITY_MFPC;
+	if (sm->mfp == 2)
+		capab |= WPA_CAPABILITY_MFPR;
+	if (sm->ocv)
+		capab |= WPA_CAPABILITY_OCVC;
+	if (sm->ext_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+	return capab;
+}
+
+
 static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
 			      int pairwise_cipher, int group_cipher,
 			      int key_mgmt, int mgmt_group_cipher,
@@ -112,7 +129,6 @@
 {
 	u8 *pos;
 	struct rsn_ie_hdr *hdr;
-	u16 capab;
 	u32 suite;
 
 	if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
@@ -214,14 +230,7 @@
 	pos += RSN_SELECTOR_LEN;
 
 	/* RSN Capabilities */
-	capab = 0;
-	if (sm->mfp)
-		capab |= WPA_CAPABILITY_MFPC;
-	if (sm->mfp == 2)
-		capab |= WPA_CAPABILITY_MFPR;
-	if (sm->ocv)
-		capab |= WPA_CAPABILITY_OCVC;
-	WPA_PUT_LE16(pos, capab);
+	WPA_PUT_LE16(pos, rsn_supp_capab(sm));
 	pos += 2;
 
 	if (sm->cur_pmksa) {
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 6dc6cf5..83a6727 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -13,5 +13,6 @@
 
 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
 int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len);
+u16 rsn_supp_capab(struct wpa_sm *sm);
 
 #endif /* WPA_IE_H */
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index a08c2e1..2da7b4a 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -9,18 +9,99 @@
 #include "includes.h"
 
 #include "common.h"
+#include "utils/wpabuf.h"
 #include "asn1.h"
 
-struct asn1_oid asn1_sha1_oid = {
+const struct asn1_oid asn1_sha1_oid = {
 	.oid = { 1, 3, 14, 3, 2, 26 },
 	.len = 6
 };
 
-struct asn1_oid asn1_sha256_oid = {
+const struct asn1_oid asn1_sha256_oid = {
 	.oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
 	.len = 9
 };
 
+const struct asn1_oid asn1_ec_public_key_oid = {
+	.oid = { 1, 2, 840, 10045, 2, 1 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_prime256v1_oid = {
+	.oid = { 1, 2, 840, 10045, 3, 1, 7 },
+	.len = 7
+};
+
+const struct asn1_oid asn1_secp384r1_oid = {
+	.oid = { 1, 3, 132, 0, 34 },
+	.len = 5
+};
+
+const struct asn1_oid asn1_secp521r1_oid = {
+	.oid = { 1, 3, 132, 0, 35 },
+	.len = 5
+};
+
+const struct asn1_oid asn1_brainpoolP256r1_oid = {
+	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP384r1_oid = {
+	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP512r1_oid = {
+	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 },
+	.len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 },
+	.len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 },
+	.len = 9
+};
+
+const struct asn1_oid asn1_pbkdf2_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 5, 12 },
+	.len = 7
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
+	.oid = { 1, 2, 840, 113549, 2, 9 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
+	.oid = { 1, 2, 840, 113549, 2, 10 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
+	.oid = { 1, 2, 840, 113549, 2, 11 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_dpp_config_params_oid = {
+	.oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = {
+	.oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 },
+	.len = 10
+};
+
 
 static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
 {
@@ -270,3 +351,231 @@
 
 	return 1;
 }
+
+
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
+{
+	struct asn1_hdr hdr;
+	size_t left;
+	const u8 *pos;
+	int value;
+
+	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
+		return -1;
+
+	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG,
+			   "ASN.1: Expected INTEGER - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	*next = hdr.payload + hdr.length;
+	pos = hdr.payload;
+	left = hdr.length;
+	if (left > sizeof(value)) {
+		wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
+			   hdr.length);
+		return -1;
+	}
+	value = 0;
+	while (left) {
+		value <<= 8;
+		value |= *pos++;
+		left--;
+	}
+
+	*integer = value;
+	return 0;
+}
+
+
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+		      const u8 **next)
+{
+	if (asn1_get_next(buf, len, hdr) < 0 ||
+	    hdr->class != ASN1_CLASS_UNIVERSAL ||
+	    hdr->tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG,
+			   "ASN.1: Expected SEQUENCE - found class %d tag 0x%x",
+			   hdr->class, hdr->tag);
+		return -1;
+	}
+
+	if (next)
+		*next = hdr->payload + hdr->length;
+	return 0;
+}
+
+
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+		    const u8 **params, size_t *params_len, const u8 **next)
+{
+	const u8 *pos = buf, *end = buf + len;
+	struct asn1_hdr hdr;
+
+	/*
+	 * AlgorithmIdentifier ::= SEQUENCE {
+	 *     algorithm            OBJECT IDENTIFIER,
+	 *     parameters           ANY DEFINED BY algorithm OPTIONAL}
+	 */
+	if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
+	    asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
+		return -1;
+
+	if (params && params_len) {
+		*params = pos;
+		*params_len = hdr.payload + hdr.length - pos;
+	}
+
+	return 0;
+}
+
+
+void asn1_put_integer(struct wpabuf *buf, int val)
+{
+	u8 bin[4];
+	int zeros;
+
+	WPA_PUT_BE32(bin, val);
+	zeros = 0;
+	while (zeros < 3 && bin[zeros] == 0)
+		zeros++;
+	wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
+	wpabuf_put_u8(buf, 4 - zeros);
+	wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
+}
+
+
+static void asn1_put_len(struct wpabuf *buf, size_t len)
+{
+	if (len <= 0x7f) {
+		wpabuf_put_u8(buf, len);
+	} else if (len <= 0xff) {
+		wpabuf_put_u8(buf, 0x80 | 1);
+		wpabuf_put_u8(buf, len);
+	} else if (len <= 0xffff) {
+		wpabuf_put_u8(buf, 0x80 | 2);
+		wpabuf_put_be16(buf, len);
+	} else if (len <= 0xffffff) {
+		wpabuf_put_u8(buf, 0x80 | 3);
+		wpabuf_put_be24(buf, len);
+	} else {
+		wpabuf_put_u8(buf, 0x80 | 4);
+		wpabuf_put_be32(buf, len);
+	}
+}
+
+
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
+{
+	wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
+	asn1_put_len(buf, wpabuf_len(val));
+	wpabuf_put_buf(buf, val);
+}
+
+
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
+{
+	u8 *len;
+	size_t i;
+
+	if (oid->len < 2)
+		return;
+	wpabuf_put_u8(buf, ASN1_TAG_OID);
+	len = wpabuf_put(buf, 1);
+	wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
+	for (i = 2; i < oid->len; i++) {
+		unsigned long val = oid->oid[i];
+		u8 bytes[8];
+		int idx = 0;
+
+		while (val) {
+			bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
+			idx++;
+			val >>= 7;
+		}
+		if (idx == 0) {
+			bytes[idx] = 0;
+			idx = 1;
+		}
+		while (idx > 0) {
+			idx--;
+			wpabuf_put_u8(buf, bytes[idx]);
+		}
+	}
+	*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+		  size_t len)
+{
+	wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
+	asn1_put_len(buf, len);
+}
+
+
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
+{
+	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
+		     wpabuf_len(payload));
+	wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
+{
+	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
+		     wpabuf_len(payload));
+	wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_utf8string(struct wpabuf *buf, const char *val)
+{
+	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
+		     os_strlen(val));
+	wpabuf_put_str(buf, val);
+}
+
+
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+				  const struct wpabuf *params)
+{
+	struct wpabuf *buf;
+	size_t len;
+
+	/*
+	 * AlgorithmIdentifier ::= SEQUENCE {
+	 *    algorithm		OBJECT IDENTIFIER,
+	 *    parameters	ANY DEFINED BY algorithm OPTIONAL}
+	 */
+
+	len = 100;
+	if (params)
+		len += wpabuf_len(params);
+	buf = wpabuf_alloc(len);
+	if (!buf)
+		return NULL;
+	asn1_put_oid(buf, oid);
+	if (params)
+		wpabuf_put_buf(buf, params);
+	return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
+{
+	struct wpabuf *res;
+
+	if (!buf)
+		return NULL;
+	res = wpabuf_alloc(10 + wpabuf_len(buf));
+	if (res) {
+		asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
+		wpabuf_put_buf(res, buf);
+	}
+	wpabuf_clear_free(buf);
+	return res;
+}
diff --git a/src/tls/asn1.h b/src/tls/asn1.h
index 6bd7df5..6878a4f 100644
--- a/src/tls/asn1.h
+++ b/src/tls/asn1.h
@@ -65,8 +65,43 @@
 void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len);
 unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
 int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b);
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next);
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+		      const u8 **next);
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+		    const u8 **params, size_t *params_len, const u8 **next);
+void asn1_put_integer(struct wpabuf *buf, int val);
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val);
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid);
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+		  size_t len);
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_utf8string(struct wpabuf *buf, const char *val);
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+				  const struct wpabuf *params);
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag);
 
-extern struct asn1_oid asn1_sha1_oid;
-extern struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_sha1_oid;
+extern const struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_ec_public_key_oid;
+extern const struct asn1_oid asn1_prime256v1_oid;
+extern const struct asn1_oid asn1_secp384r1_oid;
+extern const struct asn1_oid asn1_secp521r1_oid;
+extern const struct asn1_oid asn1_brainpoolP256r1_oid;
+extern const struct asn1_oid asn1_brainpoolP384r1_oid;
+extern const struct asn1_oid asn1_brainpoolP512r1_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_pbkdf2_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid;
+extern const struct asn1_oid asn1_dpp_config_params_oid;
+extern const struct asn1_oid asn1_dpp_asymmetric_key_package_oid;
 
 #endif /* ASN1_H */
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 80874e5..3825a73 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -312,6 +312,14 @@
 	x509_name_string(&cert->subject, subject, sizeof(subject));
 	ev.peer_cert.subject = subject;
 
+	if (cert->extensions_present & X509_EXT_CERTIFICATE_POLICY) {
+		if (cert->certificate_policy & X509_EXT_CERT_POLICY_TOD_STRICT)
+			ev.peer_cert.tod = 1;
+		else if (cert->certificate_policy &
+			 X509_EXT_CERT_POLICY_TOD_TOFU)
+			ev.peer_cert.tod = 2;
+	}
+
 	conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
 	wpabuf_free(cert_buf);
 }
@@ -532,7 +540,7 @@
 		}
 	} else if (conn->cred && conn->cred->cert_probe) {
 		wpa_printf(MSG_DEBUG,
-			   "TLSv1: Reject server certificate on probe-only rune");
+			   "TLSv1: Reject server certificate on probe-only run");
 		if (conn->event_cb) {
 			union tls_event_data ev;
 			char buf[128];
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 1bd5aa0..5c8ac56 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -1120,6 +1120,133 @@
 }
 
 
+static int x509_id_cert_policy_any_oid(struct asn1_oid *oid)
+{
+	return oid->len == 5 &&
+		oid->oid[0] == 2 /* iso/itu-t */ &&
+		oid->oid[1] == 5 /* X.500 Directory Services */ &&
+		oid->oid[2] == 29 /* id-ce */ &&
+		oid->oid[3] == 32 /* id-ce-certificate-policies */ &&
+		oid->oid[4] == 0 /* anyPolicy */;
+}
+
+
+static int x509_id_wfa_oid(struct asn1_oid *oid)
+{
+	return oid->len >= 7 &&
+		oid->oid[0] == 1 /* iso */ &&
+		oid->oid[1] == 3 /* identified-organization */ &&
+		oid->oid[2] == 6 /* dod */ &&
+		oid->oid[3] == 1 /* internet */ &&
+		oid->oid[4] == 4 /* private */ &&
+		oid->oid[5] == 1 /* enterprise */ &&
+		oid->oid[6] == 40808 /* WFA */;
+}
+
+
+static int x509_id_wfa_tod_oid(struct asn1_oid *oid)
+{
+	return oid->len >= 9 &&
+		x509_id_wfa_oid(oid) &&
+		oid->oid[7] == 1 &&
+		oid->oid[8] == 3;
+}
+
+
+static int x509_id_wfa_tod_strict_oid(struct asn1_oid *oid)
+{
+	return oid->len == 10 &&
+		x509_id_wfa_tod_oid(oid) &&
+		oid->oid[9] == 1;
+}
+
+
+static int x509_id_wfa_tod_tofu_oid(struct asn1_oid *oid)
+{
+	return oid->len == 10 &&
+		x509_id_wfa_tod_oid(oid) &&
+		oid->oid[9] == 2;
+}
+
+
+static int x509_parse_ext_certificate_policies(struct x509_certificate *cert,
+					       const u8 *pos, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *end;
+
+	/*
+	 * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+	 *
+	 * PolicyInformation ::= SEQUENCE {
+	 *      policyIdentifier   CertPolicyId,
+	 *      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+	 *                              PolicyQualifierInfo OPTIONAL }
+	 *
+	 * CertPolicyId ::= OBJECT IDENTIFIER
+	 */
+
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (certificatePolicies) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	if (hdr.length > pos + len - hdr.payload)
+		return -1;
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	wpa_hexdump(MSG_MSGDUMP, "X509: certificatePolicies", pos, end - pos);
+
+	while (pos < end) {
+		const u8 *pol_end;
+		struct asn1_oid oid;
+		char buf[80];
+
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_UNIVERSAL ||
+		    hdr.tag != ASN1_TAG_SEQUENCE) {
+			wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (PolicyInformation) - found class %d tag 0x%x",
+				   hdr.class, hdr.tag);
+			return -1;
+		}
+		if (hdr.length > end - hdr.payload)
+			return -1;
+		pos = hdr.payload;
+		pol_end = pos + hdr.length;
+		wpa_hexdump(MSG_MSGDUMP, "X509: PolicyInformation",
+			    pos, pol_end - pos);
+
+		if (asn1_get_oid(pos, pol_end - pos, &oid, &pos))
+			return -1;
+		if (x509_id_cert_policy_any_oid(&oid)) {
+			os_strlcpy(buf, "anyPolicy-STRICT", sizeof(buf));
+			cert->certificate_policy |=
+				X509_EXT_CERT_POLICY_ANY;
+		} else if (x509_id_wfa_tod_strict_oid(&oid)) {
+			os_strlcpy(buf, "TOD-STRICT", sizeof(buf));
+			cert->certificate_policy |=
+				X509_EXT_CERT_POLICY_TOD_STRICT;
+		} else if (x509_id_wfa_tod_tofu_oid(&oid)) {
+			os_strlcpy(buf, "TOD-TOFU", sizeof(buf));
+			cert->certificate_policy |=
+				X509_EXT_CERT_POLICY_TOD_TOFU;
+		} else {
+			asn1_oid_to_str(&oid, buf, sizeof(buf));
+		}
+		wpa_printf(MSG_DEBUG, "policyIdentifier: %s", buf);
+
+		pos = pol_end;
+	}
+
+	cert->extensions_present |= X509_EXT_CERTIFICATE_POLICY;
+
+	return 0;
+}
+
+
 static int x509_id_pkix_oid(struct asn1_oid *oid)
 {
 	return oid->len >= 7 &&
@@ -1234,7 +1361,6 @@
 		return 1;
 
 	/* TODO: add other extensions required by RFC 3280, Ch 4.2:
-	 * certificate policies (section 4.2.1.5)
 	 * name constraints (section 4.2.1.11)
 	 * policy constraints (section 4.2.1.12)
 	 * inhibit any-policy (section 4.2.1.15)
@@ -1248,6 +1374,8 @@
 		return x509_parse_ext_issuer_alt_name(cert, pos, len);
 	case 19: /* id-ce-basicConstraints */
 		return x509_parse_ext_basic_constraints(cert, pos, len);
+	case 32: /* id-ce-certificatePolicies */
+		return x509_parse_ext_certificate_policies(cert, pos, len);
 	case 37: /* id-ce-extKeyUsage */
 		return x509_parse_ext_ext_key_usage(cert, pos, len);
 	default:
diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h
index 7df8e2a..e3b108f 100644
--- a/src/tls/x509v3.h
+++ b/src/tls/x509v3.h
@@ -74,6 +74,7 @@
 #define X509_EXT_SUBJECT_ALT_NAME		(1 << 3)
 #define X509_EXT_ISSUER_ALT_NAME		(1 << 4)
 #define X509_EXT_EXT_KEY_USAGE			(1 << 5)
+#define X509_EXT_CERTIFICATE_POLICY		(1 << 6)
 
 	/* BasicConstraints */
 	int ca; /* cA */
@@ -98,6 +99,12 @@
 #define X509_EXT_KEY_USAGE_CLIENT_AUTH		(1 << 2)
 #define X509_EXT_KEY_USAGE_OCSP			(1 << 3)
 
+	/* CertificatePolicy */
+	unsigned long certificate_policy;
+#define X509_EXT_CERT_POLICY_ANY		(1 << 0)
+#define X509_EXT_CERT_POLICY_TOD_STRICT		(1 << 1)
+#define X509_EXT_CERT_POLICY_TOD_TOFU		(1 << 2)
+
 	/*
 	 * The DER format certificate follows struct x509_certificate. These
 	 * pointers point to that buffer.
diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c
index 71a1652..26c83d6 100644
--- a/src/utils/browser-android.c
+++ b/src/utils/browser-android.c
@@ -62,7 +62,7 @@
 }
 
 
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
 {
 	struct http_server *http;
 	struct in_addr addr;
diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c
index aed3970..d87d97b 100644
--- a/src/utils/browser-system.c
+++ b/src/utils/browser-system.c
@@ -62,7 +62,7 @@
 }
 
 
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
 {
 	struct http_server *http;
 	struct in_addr addr;
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index dfb4b67..d32a85b 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -63,7 +63,7 @@
 }
 
 
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
 {
 	struct http_server *http;
 	struct in_addr addr;
diff --git a/src/utils/browser.c b/src/utils/browser.c
index ad0b382..c0f4380 100644
--- a/src/utils/browser.c
+++ b/src/utils/browser.c
@@ -7,7 +7,11 @@
  */
 
 #include "includes.h"
+#ifdef USE_WEBKIT2
+#include <webkit2/webkit2.h>
+#else /* USE_WEBKIT2 */
 #include <webkit/webkit.h>
+#endif /* USE_WEBKIT2 */
 
 #include "common.h"
 #include "browser.h"
@@ -15,16 +19,20 @@
 
 struct browser_context {
 	GtkWidget *win;
+	WebKitWebView *view;
 	int success;
 	int progress;
 	char *hover_link;
 	char *title;
+	int gtk_main_started;
+	int quit_gtk_main;
 };
 
 static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
 {
 	wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
-	gtk_main_quit();
+	if (ctx->gtk_main_started)
+		gtk_main_quit();
 }
 
 
@@ -50,6 +58,142 @@
 }
 
 
+static void process_request_starting_uri(struct browser_context *ctx,
+					 const char *uri)
+{
+	int quit = 0;
+
+	if (g_str_has_prefix(uri, "osu://")) {
+		ctx->success = atoi(uri + 6);
+		quit = 1;
+	} else if (g_str_has_prefix(uri, "http://localhost:12345")) {
+		/*
+		 * This is used as a special trigger to indicate that the
+		 * user exchange has been completed.
+		 */
+		ctx->success = 1;
+		quit = 1;
+	}
+
+	if (quit) {
+		if (ctx->gtk_main_started) {
+			gtk_main_quit();
+			ctx->gtk_main_started = 0;
+		} else {
+			ctx->quit_gtk_main = 1;
+		}
+	}
+}
+
+
+#ifdef USE_WEBKIT2
+
+static void view_cb_notify_estimated_load_progress(WebKitWebView *view,
+						   GParamSpec *pspec,
+						   struct browser_context *ctx)
+{
+	ctx->progress = 100 * webkit_web_view_get_estimated_load_progress(view);
+	wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
+		   ctx->progress);
+	browser_update_title(ctx);
+}
+
+
+static void view_cb_resource_load_starting(WebKitWebView *view,
+					   WebKitWebResource *res,
+					   WebKitURIRequest *req,
+					   struct browser_context *ctx)
+{
+	const gchar *uri = webkit_uri_request_get_uri(req);
+
+	wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
+	process_request_starting_uri(ctx, uri);
+}
+
+
+static gboolean view_cb_decide_policy(WebKitWebView *view,
+				      WebKitPolicyDecision *policy,
+				      WebKitPolicyDecisionType type,
+				      struct browser_context *ctx)
+{
+	wpa_printf(MSG_DEBUG, "BROWSER:%s type=%d", __func__, type);
+	switch (type) {
+	case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
+		/* This function makes webkit send a download signal for all
+		 * unknown mime types. */
+		WebKitResponsePolicyDecision *response;
+
+		response = WEBKIT_RESPONSE_POLICY_DECISION(policy);
+		if (!webkit_response_policy_decision_is_mime_type_supported(
+			    response)) {
+			webkit_policy_decision_download(policy);
+			return TRUE;
+		}
+		break;
+	}
+	case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
+		WebKitNavigationPolicyDecision *d;
+		WebKitNavigationAction *a;
+		WebKitURIRequest *req;
+		const gchar *uri;
+
+		d = WEBKIT_NAVIGATION_POLICY_DECISION(policy);
+		a = webkit_navigation_policy_decision_get_navigation_action(d);
+		req = webkit_navigation_action_get_request(a);
+		uri = webkit_uri_request_get_uri(req);
+		wpa_printf(MSG_DEBUG, "BROWSER:%s navigation action: uri=%s",
+			   __func__, uri);
+		process_request_starting_uri(ctx, uri);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return FALSE;
+}
+
+
+static void view_cb_mouse_target_changed(WebKitWebView *view,
+					 WebKitHitTestResult *h,
+					 guint modifiers,
+					 struct browser_context *ctx)
+{
+	WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h);
+	const char *uri = NULL;
+
+	if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+		uri = webkit_hit_test_result_get_link_uri(h);
+	else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE)
+		uri = webkit_hit_test_result_get_image_uri(h);
+	else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)
+		uri = webkit_hit_test_result_get_media_uri(h);
+
+	wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri ? uri : "N/A");
+	os_free(ctx->hover_link);
+	if (uri)
+		ctx->hover_link = os_strdup(uri);
+	else
+		ctx->hover_link = NULL;
+
+	browser_update_title(ctx);
+}
+
+
+static void view_cb_notify_title(WebKitWebView *view, GParamSpec *ps,
+				 struct browser_context *ctx)
+{
+	const char *title;
+
+	title = webkit_web_view_get_title(ctx->view);
+	wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
+	os_free(ctx->title);
+	ctx->title = os_strdup(title);
+	browser_update_title(ctx);
+}
+
+#else /* USE_WEBKIT2 */
+
 static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
 				    struct browser_context *ctx)
 {
@@ -66,6 +210,10 @@
 	int status = webkit_web_view_get_load_status(view);
 	wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
 		   __func__, status, webkit_web_view_get_uri(view));
+	if (ctx->quit_gtk_main) {
+		gtk_main_quit();
+		ctx->gtk_main_started = 0;
+	}
 }
 
 
@@ -77,21 +225,12 @@
 					      struct browser_context *ctx)
 {
 	const gchar *uri = webkit_network_request_get_uri(req);
+
 	wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
 	if (g_str_has_suffix(uri, "/favicon.ico"))
 		webkit_network_request_set_uri(req, "about:blank");
-	if (g_str_has_prefix(uri, "osu://")) {
-		ctx->success = atoi(uri + 6);
-		gtk_main_quit();
-	}
-	if (g_str_has_prefix(uri, "http://localhost:12345")) {
-		/*
-		 * This is used as a special trigger to indicate that the
-		 * user exchange has been completed.
-		 */
-		ctx->success = 1;
-		gtk_main_quit();
-	}
+
+	process_request_starting_uri(ctx, uri);
 }
 
 
@@ -147,23 +286,32 @@
 	browser_update_title(ctx);
 }
 
+#endif /* USE_WEBKIT2 */
 
-int hs20_web_browser(const char *url)
+
+int hs20_web_browser(const char *url, int ignore_tls)
 {
 	GtkWidget *scroll;
-	SoupSession *s;
 	WebKitWebView *view;
+#ifdef USE_WEBKIT2
+	WebKitSettings *settings;
+#else /* USE_WEBKIT2 */
 	WebKitWebSettings *settings;
+	SoupSession *s;
+#endif /* USE_WEBKIT2 */
 	struct browser_context ctx;
 
 	memset(&ctx, 0, sizeof(ctx));
 	if (!gtk_init_check(NULL, NULL))
 		return -1;
 
+#ifndef USE_WEBKIT2
 	s = webkit_get_default_session();
 	g_object_set(G_OBJECT(s), "ssl-ca-file",
 		     "/etc/ssl/certs/ca-certificates.crt", NULL);
-	g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+	if (ignore_tls)
+		g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+#endif /* USE_WEBKIT2 */
 
 	ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 	gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
@@ -177,10 +325,24 @@
 			 G_CALLBACK(win_cb_destroy), &ctx);
 
 	view = WEBKIT_WEB_VIEW(webkit_web_view_new());
-	g_signal_connect(G_OBJECT(view), "notify::progress",
-			 G_CALLBACK(view_cb_notify_progress), &ctx);
+	ctx.view = view;
+#ifdef USE_WEBKIT2
+	g_signal_connect(G_OBJECT(view), "notify::estimated-load-progress",
+			 G_CALLBACK(view_cb_notify_estimated_load_progress),
+			 &ctx);
+	g_signal_connect(G_OBJECT(view), "resource-load-started",
+			 G_CALLBACK(view_cb_resource_load_starting), &ctx);
+	g_signal_connect(G_OBJECT(view), "decide-policy",
+			 G_CALLBACK(view_cb_decide_policy), &ctx);
+	g_signal_connect(G_OBJECT(view), "mouse-target-changed",
+			 G_CALLBACK(view_cb_mouse_target_changed), &ctx);
+	g_signal_connect(G_OBJECT(view), "notify::title",
+			 G_CALLBACK(view_cb_notify_title), &ctx);
+#else /* USE_WEBKIT2 */
 	g_signal_connect(G_OBJECT(view), "notify::load-status",
 			 G_CALLBACK(view_cb_notify_load_status), &ctx);
+	g_signal_connect(G_OBJECT(view), "notify::progress",
+			 G_CALLBACK(view_cb_notify_progress), &ctx);
 	g_signal_connect(G_OBJECT(view), "resource-request-starting",
 			 G_CALLBACK(view_cb_resource_request_starting), &ctx);
 	g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
@@ -191,6 +353,7 @@
 			 G_CALLBACK(view_cb_hovering_over_link), &ctx);
 	g_signal_connect(G_OBJECT(view), "title-changed",
 			 G_CALLBACK(view_cb_title_changed), &ctx);
+#endif /* USE_WEBKIT2 */
 
 	gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
 	gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
@@ -205,8 +368,19 @@
 		     "hs20-client/1.0", NULL);
 	g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
 
+#ifdef USE_WEBKIT2
+	if (ignore_tls) {
+		WebKitWebContext *wkctx;
+
+		wkctx = webkit_web_context_get_default();
+		webkit_web_context_set_tls_errors_policy(
+			wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+	}
+#endif /* USE_WEBKIT2 */
+
 	webkit_web_view_load_uri(view, url);
 
+	ctx.gtk_main_started = 1;
 	gtk_main();
 	gtk_widget_destroy(ctx.win);
 	while (gtk_events_pending())
diff --git a/src/utils/browser.h b/src/utils/browser.h
index aaa0eed..3af13b9 100644
--- a/src/utils/browser.h
+++ b/src/utils/browser.h
@@ -10,12 +10,12 @@
 #define BROWSER_H
 
 #ifdef CONFIG_NO_BROWSER
-static inline int hs20_web_browser(const char *url)
+static inline int hs20_web_browser(const char *url, int ignore_tls)
 {
 	return -1;
 }
 #else /* CONFIG_NO_BROWSER */
-int hs20_web_browser(const char *url);
+int hs20_web_browser(const char *url, int ignore_tls);
 #endif /* CONFIG_NO_BROWSER */
 
 #endif /* BROWSER_H */
diff --git a/src/utils/common.c b/src/utils/common.c
index 27bf435..2c12751 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -7,6 +7,7 @@
  */
 
 #include "includes.h"
+#include <limits.h>
 
 #include "common/ieee802_11_defs.h"
 #include "common.h"
@@ -790,6 +791,10 @@
 	 */
 	pos = value;
 	while (pos && pos[0]) {
+		if (count == UINT_MAX) {
+			os_free(freq);
+			return -1;
+		}
 		n = os_realloc_array(freq, count + 1,
 				     sizeof(struct wpa_freq_range));
 		if (n == NULL) {
@@ -874,9 +879,10 @@
 }
 
 
-int int_array_len(const int *a)
+size_t int_array_len(const int *a)
 {
-	int i;
+	size_t i;
+
 	for (i = 0; a && a[i]; i++)
 		;
 	return i;
@@ -885,12 +891,21 @@
 
 void int_array_concat(int **res, const int *a)
 {
-	int reslen, alen, i;
+	size_t reslen, alen, i, max_size;
 	int *n;
 
 	reslen = int_array_len(*res);
 	alen = int_array_len(a);
-
+	max_size = (size_t) -1;
+	if (alen >= max_size - reslen) {
+		/* This should not really happen, but if it did, something
+		 * would overflow. Do not try to merge the arrays; instead, make
+		 * this behave like memory allocation failure to avoid messing
+		 * up memory. */
+		os_free(*res);
+		*res = NULL;
+		return;
+	}
 	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
 	if (n == NULL) {
 		os_free(*res);
@@ -918,8 +933,7 @@
 
 void int_array_sort_unique(int *a)
 {
-	int alen;
-	int i, j;
+	size_t alen, i, j;
 
 	if (a == NULL)
 		return;
@@ -944,7 +958,7 @@
 
 void int_array_add_unique(int **res, int a)
 {
-	int reslen;
+	size_t reslen, max_size;
 	int *n;
 
 	for (reslen = 0; *res && (*res)[reslen]; reslen++) {
@@ -952,6 +966,16 @@
 			return; /* already in the list */
 	}
 
+	max_size = (size_t) -1;
+	if (reslen > max_size - 2) {
+		/* This should not really happen in practice, but if it did,
+		 * something would overflow. Do not try to add the new value;
+		 * instead, make this behave like memory allocation failure to
+		 * avoid messing up memory. */
+		os_free(*res);
+		*res = NULL;
+		return;
+	}
 	n = os_realloc_array(*res, reslen + 2, sizeof(int));
 	if (n == NULL) {
 		os_free(*res);
diff --git a/src/utils/common.h b/src/utils/common.h
index 833469a..8e5cfe1 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -547,7 +547,7 @@
 			     unsigned int freq);
 char * freq_range_list_str(const struct wpa_freq_range_list *list);
 
-int int_array_len(const int *a);
+size_t int_array_len(const int *a);
 void int_array_concat(int **res, const int *a);
 void int_array_sort_unique(int *a);
 void int_array_add_unique(int **res, int a);
diff --git a/src/utils/crc32.c b/src/utils/crc32.c
new file mode 100644
index 0000000..12d9e2a
--- /dev/null
+++ b/src/utils/crc32.c
@@ -0,0 +1,85 @@
+/*
+ * 32-bit CRC for FCS calculation
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/crc32.h"
+
+/*
+ * IEEE 802.11 FCS CRC32
+ * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 +
+ *        x^5 + x^4 + x^2 + x + 1
+ */
+static const u32 crc32_table[256] = {
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+	0x2d02ef8d
+};
+
+
+u32 crc32(const u8 *frame, size_t frame_len)
+{
+	size_t i;
+	u32 crc;
+
+	crc = 0xFFFFFFFF;
+	for (i = 0; i < frame_len; i++)
+		crc = crc32_table[(crc ^ frame[i]) & 0xff] ^ (crc >> 8);
+
+	return ~crc;
+}
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index bb375be..b353ab0 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -68,7 +68,7 @@
 };
 
 struct eloop_sock_table {
-	int count;
+	size_t count;
 	struct eloop_sock *table;
 	eloop_event_type type;
 	int changed;
@@ -77,10 +77,10 @@
 struct eloop_data {
 	int max_sock;
 
-	int count; /* sum of all table counts */
+	size_t count; /* sum of all table counts */
 #ifdef CONFIG_ELOOP_POLL
-	int max_pollfd_map; /* number of pollfds_map currently allocated */
-	int max_poll_fds; /* number of pollfds currently allocated */
+	size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+	size_t max_poll_fds; /* number of pollfds currently allocated */
 	struct pollfd *pollfds;
 	struct pollfd **pollfds_map;
 #endif /* CONFIG_ELOOP_POLL */
@@ -90,12 +90,12 @@
 #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 #ifdef CONFIG_ELOOP_EPOLL
 	int epollfd;
-	int epoll_max_event_num;
+	size_t epoll_max_event_num;
 	struct epoll_event *epoll_events;
 #endif /* CONFIG_ELOOP_EPOLL */
 #ifdef CONFIG_ELOOP_KQUEUE
 	int kqueuefd;
-	int kqueue_nevents;
+	size_t kqueue_nevents;
 	struct kevent *kqueue_events;
 #endif /* CONFIG_ELOOP_KQUEUE */
 	struct eloop_sock_table readers;
@@ -104,7 +104,7 @@
 
 	struct dl_list timeout;
 
-	int signal_count;
+	size_t signal_count;
 	struct eloop_signal *signals;
 	int signaled;
 	int pending_terminate;
@@ -125,7 +125,8 @@
 
 static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
 {
-	int i;
+	size_t i;
+
 	if (table == NULL || table->table == NULL)
 		return;
 	for (i = 0; i < table->count; i++) {
@@ -139,7 +140,8 @@
 
 static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
 {
-	int i;
+	size_t i;
+
 	if (table == NULL || table->table == NULL)
 		return;
 	for (i = 0; i < table->count; i++) {
@@ -266,7 +268,7 @@
 #endif /* CONFIG_ELOOP_EPOLL */
 #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
 	struct eloop_sock *temp_table;
-	int next;
+	size_t next;
 #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 	struct eloop_sock *tmp;
 	int new_max_sock;
@@ -280,7 +282,7 @@
 		return -1;
 
 #ifdef CONFIG_ELOOP_POLL
-	if (new_max_sock >= eloop.max_pollfd_map) {
+	if ((size_t) new_max_sock >= eloop.max_pollfd_map) {
 		struct pollfd **nmap;
 		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
 					sizeof(struct pollfd *));
@@ -293,7 +295,8 @@
 
 	if (eloop.count + 1 > eloop.max_poll_fds) {
 		struct pollfd *n;
-		int nmax = eloop.count + 1 + 50;
+		size_t nmax = eloop.count + 1 + 50;
+
 		n = os_realloc_array(eloop.pollfds, nmax,
 				     sizeof(struct pollfd));
 		if (n == NULL)
@@ -385,7 +388,7 @@
 #ifdef CONFIG_ELOOP_KQUEUE
 	struct kevent ke;
 #endif /* CONFIG_ELOOP_KQUEUE */
-	int i;
+	size_t i;
 
 	if (table == NULL || table->table == NULL || table->count == 0)
 		return;
@@ -444,7 +447,7 @@
 				    struct pollfd **pollfds_map,
 				    int max_pollfd_map)
 {
-	int i;
+	size_t i;
 	int nxt = 0;
 	int fd;
 	struct pollfd *pfd;
@@ -519,7 +522,7 @@
 					   int max_pollfd_map,
 					   short int revents)
 {
-	int i;
+	size_t i;
 	struct pollfd *pfd;
 
 	if (!table || !table->table)
@@ -572,7 +575,7 @@
 static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
 				     fd_set *fds)
 {
-	int i;
+	size_t i;
 
 	FD_ZERO(fds);
 
@@ -589,7 +592,7 @@
 static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
 				      fd_set *fds)
 {
-	int i;
+	size_t i;
 
 	if (table == NULL || table->table == NULL)
 		return;
@@ -653,7 +656,8 @@
 
 static int eloop_sock_table_requeue(struct eloop_sock_table *table)
 {
-	int i, r;
+	size_t i;
+	int r;
 
 	r = 0;
 	for (i = 0; i < table->count && table->table; i++) {
@@ -694,7 +698,8 @@
 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
 {
 	if (table) {
-		int i;
+		size_t i;
+
 		for (i = 0; i < table->count && table->table; i++) {
 			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
 				   "sock=%d eloop_data=%p user_data=%p "
@@ -968,7 +973,7 @@
 
 static void eloop_handle_signal(int sig)
 {
-	int i;
+	size_t i;
 
 #ifndef CONFIG_NATIVE_WINDOWS
 	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
@@ -992,7 +997,7 @@
 
 static void eloop_process_pending_signals(void)
 {
-	int i;
+	size_t i;
 
 	if (eloop.signaled == 0)
 		return;
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index 9c8b12b..74eaa33 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -54,7 +54,7 @@
 
 	struct dl_list timeout;
 
-	int signal_count;
+	size_t signal_count;
 	struct eloop_signal *signals;
 	int signaled;
 	int pending_terminate;
@@ -422,7 +422,7 @@
 #if 0
 static void eloop_handle_signal(int sig)
 {
-	int i;
+	size_t i;
 
 	eloop.signaled++;
 	for (i = 0; i < eloop.signal_count; i++) {
@@ -437,7 +437,7 @@
 
 static void eloop_process_pending_signals(void)
 {
-	int i;
+	size_t i;
 
 	if (eloop.signaled == 0)
 		return;
@@ -517,7 +517,7 @@
 
 	eloop.term_signal.handler = handler;
 	eloop.term_signal.user_data = user_data;
-		
+
 	return 0;
 }
 
diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h
index 8d4399a..d9fc925 100644
--- a/src/utils/http-utils.h
+++ b/src/utils/http-utils.h
@@ -28,11 +28,11 @@
 
 struct http_cert {
 	char **dnsname;
-	unsigned int num_dnsname;
+	size_t num_dnsname;
 	struct http_othername *othername;
-	unsigned int num_othername;
+	size_t num_othername;
 	struct http_logo *logo;
-	unsigned int num_logo;
+	size_t num_logo;
 };
 
 int soap_init_client(struct http_ctx *ctx, const char *address,
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 494bf4c..ae2f802 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -339,6 +339,8 @@
 
 int os_program_init(void)
 {
+	unsigned int seed;
+
 #ifdef ANDROID
 	struct __user_cap_header_struct header;
 	struct __user_cap_data_struct cap;
@@ -391,6 +393,9 @@
 	capset(&header, &cap);
 #endif /* ANDROID */
 
+	if (os_get_random((unsigned char *) &seed, sizeof(seed)) == 0)
+		srandom(seed);
+
 	return 0;
 }
 
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 4084343..8f12da8 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -146,6 +146,17 @@
 	unsigned int line;
 };
 
+/*
+ * binutils removed the bfd parameter and renamed things but
+ * those were macros so we can detect their absence.
+ * Cf. https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=fd3619828e94a24a92cddec42cbc0ab33352eeb4;hp=5dfda3562a69686c43aad4fb0269cc9d5ec010d5
+ */
+#ifndef bfd_get_section_vma
+#define bfd_get_section_vma(bfd, section) bfd_section_vma(section)
+#endif
+#ifndef bfd_get_section_size
+#define bfd_get_section_size bfd_section_size
+#endif
 
 static void find_addr_sect(bfd *abfd, asection *section, void *obj)
 {
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index b09225d..365f21f 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -226,7 +226,7 @@
 	int test3[] = { 1, 1, 1, -1, 2, 3, 4, 1, 2, 0 };
 	int test3_res[] = { -1, 1, 2, 3, 4, 0 };
 	int errors = 0;
-	int len;
+	size_t len;
 
 	wpa_printf(MSG_INFO, "int_array tests");
 
@@ -930,7 +930,7 @@
 		{ 0, 0 },
 		{ 1, 0 },
 		{ 2, 0 },
-		{ 1 << (sizeof(unsigned int) * 8 - 1), ~0 },
+		{ 1U << (sizeof(unsigned int) * 8 - 1), ~0 },
 		{ ~0 - 1, ~0 },
 		{ ~0, ~0 }
 	};
@@ -941,7 +941,7 @@
 		{ 0, ~0 },
 		{ 1, 0 },
 		{ 2, 0 },
-		{ 1 << (sizeof(unsigned int) * 8 - 1), 0 },
+		{ 1U << (sizeof(unsigned int) * 8 - 1), 0 },
 		{ ~0 - 1, 0 },
 		{ ~0, 0 }
 	};
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index c336e53..a338a20 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -12,8 +12,6 @@
 
 #ifdef CONFIG_DEBUG_SYSLOG
 #include <syslog.h>
-
-int wpa_debug_syslog = 0;
 #endif /* CONFIG_DEBUG_SYSLOG */
 
 #ifdef CONFIG_DEBUG_LINUX_TRACING
@@ -32,6 +30,10 @@
 int wpa_debug_level = MSG_INFO;
 int wpa_debug_show_keys = 0;
 int wpa_debug_timestamp = 0;
+int wpa_debug_syslog = 0;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static FILE *out_file = NULL;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
 
 #ifdef CONFIG_ANDROID_LOG
@@ -61,8 +63,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-
-static FILE *out_file = NULL;
 #endif /* CONFIG_DEBUG_FILE */
 
 
@@ -76,12 +76,12 @@
 
 	os_get_time(&tv);
 #ifdef CONFIG_DEBUG_FILE
-	if (out_file) {
+	if (out_file)
 		fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
 			(unsigned int) tv.usec);
-	} else
 #endif /* CONFIG_DEBUG_FILE */
-	printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+	if (!out_file && !wpa_debug_syslog)
+		printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
 #endif /* CONFIG_ANDROID_LOG */
 }
 
@@ -210,35 +210,37 @@
 {
 	va_list ap;
 
-	va_start(ap, fmt);
 	if (level >= wpa_debug_level) {
 #ifdef CONFIG_ANDROID_LOG
+		va_start(ap, fmt);
 		__android_log_vprint(wpa_to_android_level(level),
 				     ANDROID_LOG_NAME, fmt, ap);
+		va_end(ap);
 #else /* CONFIG_ANDROID_LOG */
 #ifdef CONFIG_DEBUG_SYSLOG
 		if (wpa_debug_syslog) {
+			va_start(ap, fmt);
 			vsyslog(syslog_priority(level), fmt, ap);
-		} else {
+			va_end(ap);
+		}
 #endif /* CONFIG_DEBUG_SYSLOG */
 		wpa_debug_print_timestamp();
 #ifdef CONFIG_DEBUG_FILE
 		if (out_file) {
+			va_start(ap, fmt);
 			vfprintf(out_file, fmt, ap);
 			fprintf(out_file, "\n");
-		} else {
-#endif /* CONFIG_DEBUG_FILE */
-		vprintf(fmt, ap);
-		printf("\n");
-#ifdef CONFIG_DEBUG_FILE
+			va_end(ap);
 		}
 #endif /* CONFIG_DEBUG_FILE */
-#ifdef CONFIG_DEBUG_SYSLOG
+		if (!wpa_debug_syslog && !out_file) {
+			va_start(ap, fmt);
+			vprintf(fmt, ap);
+			printf("\n");
+			va_end(ap);
 		}
-#endif /* CONFIG_DEBUG_SYSLOG */
 #endif /* CONFIG_ANDROID_LOG */
 	}
-	va_end(ap);
 
 #ifdef CONFIG_DEBUG_LINUX_TRACING
 	if (wpa_debug_tracing_file != NULL) {
@@ -254,7 +256,7 @@
 
 
 static void _wpa_hexdump(int level, const char *title, const u8 *buf,
-			 size_t len, int show)
+			 size_t len, int show, int only_syslog)
 {
 	size_t i;
 
@@ -345,7 +347,8 @@
 		syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
 		       title, (unsigned long) len, display);
 		bin_clear_free(strbuf, 1 + 3 * len);
-		return;
+		if (only_syslog)
+			return;
 	}
 #endif /* CONFIG_DEBUG_SYSLOG */
 	wpa_debug_print_timestamp();
@@ -362,33 +365,32 @@
 			fprintf(out_file, " [REMOVED]");
 		}
 		fprintf(out_file, "\n");
-	} else {
-#endif /* CONFIG_DEBUG_FILE */
-	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
-	if (buf == NULL) {
-		printf(" [NULL]");
-	} else if (show) {
-		for (i = 0; i < len; i++)
-			printf(" %02x", buf[i]);
-	} else {
-		printf(" [REMOVED]");
-	}
-	printf("\n");
-#ifdef CONFIG_DEBUG_FILE
 	}
 #endif /* CONFIG_DEBUG_FILE */
+	if (!wpa_debug_syslog && !out_file) {
+		printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+		if (buf == NULL) {
+			printf(" [NULL]");
+		} else if (show) {
+			for (i = 0; i < len; i++)
+				printf(" %02x", buf[i]);
+		} else {
+			printf(" [REMOVED]");
+		}
+		printf("\n");
+	}
 #endif /* CONFIG_ANDROID_LOG */
 }
 
 void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
 {
-	_wpa_hexdump(level, title, buf, len, 1);
+	_wpa_hexdump(level, title, buf, len, 1, 0);
 }
 
 
 void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
 {
-	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
+	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys, 0);
 }
 
 
@@ -421,13 +423,11 @@
 	if (level < wpa_debug_level)
 		return;
 #ifdef CONFIG_ANDROID_LOG
-	_wpa_hexdump(level, title, buf, len, show);
+	_wpa_hexdump(level, title, buf, len, show, 0);
 #else /* CONFIG_ANDROID_LOG */
 #ifdef CONFIG_DEBUG_SYSLOG
-	if (wpa_debug_syslog) {
-		_wpa_hexdump(level, title, buf, len, show);
-		return;
-	}
+	if (wpa_debug_syslog)
+		_wpa_hexdump(level, title, buf, len, show, 1);
 #endif /* CONFIG_DEBUG_SYSLOG */
 	wpa_debug_print_timestamp();
 #ifdef CONFIG_DEBUG_FILE
@@ -436,13 +436,13 @@
 			fprintf(out_file,
 				"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
 				title, (unsigned long) len);
-			return;
+			goto file_done;
 		}
 		if (buf == NULL) {
 			fprintf(out_file,
 				"%s - hexdump_ascii(len=%lu): [NULL]\n",
 				title, (unsigned long) len);
-			return;
+			goto file_done;
 		}
 		fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
 			title, (unsigned long) len);
@@ -466,42 +466,43 @@
 			pos += llen;
 			len -= llen;
 		}
-	} else {
+	}
+file_done:
 #endif /* CONFIG_DEBUG_FILE */
-	if (!show) {
-		printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
-		       title, (unsigned long) len);
-		return;
-	}
-	if (buf == NULL) {
-		printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
-		       title, (unsigned long) len);
-		return;
-	}
-	printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
-	while (len) {
-		llen = len > line_len ? line_len : len;
-		printf("    ");
-		for (i = 0; i < llen; i++)
-			printf(" %02x", pos[i]);
-		for (i = llen; i < line_len; i++)
-			printf("   ");
-		printf("   ");
-		for (i = 0; i < llen; i++) {
-			if (isprint(pos[i]))
-				printf("%c", pos[i]);
-			else
-				printf("_");
+	if (!wpa_debug_syslog && !out_file) {
+		if (!show) {
+			printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+			       title, (unsigned long) len);
+			return;
 		}
-		for (i = llen; i < line_len; i++)
-			printf(" ");
-		printf("\n");
-		pos += llen;
-		len -= llen;
+		if (buf == NULL) {
+			printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
+			       title, (unsigned long) len);
+			return;
+		}
+		printf("%s - hexdump_ascii(len=%lu):\n", title,
+		       (unsigned long) len);
+		while (len) {
+			llen = len > line_len ? line_len : len;
+			printf("    ");
+			for (i = 0; i < llen; i++)
+				printf(" %02x", pos[i]);
+			for (i = llen; i < line_len; i++)
+				printf("   ");
+			printf("   ");
+			for (i = 0; i < llen; i++) {
+				if (isprint(pos[i]))
+					printf("%c", pos[i]);
+				else
+					printf("_");
+			}
+			for (i = llen; i < line_len; i++)
+				printf(" ");
+			printf("\n");
+			pos += llen;
+			len -= llen;
+		}
 	}
-#ifdef CONFIG_DEBUG_FILE
-	}
-#endif /* CONFIG_DEBUG_FILE */
 #endif /* CONFIG_ANDROID_LOG */
 }
 
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index c94c439..c6d5cc6 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -14,9 +14,7 @@
 extern int wpa_debug_level;
 extern int wpa_debug_show_keys;
 extern int wpa_debug_timestamp;
-#ifdef CONFIG_DEBUG_SYSLOG
 extern int wpa_debug_syslog;
-#endif /* CONFIG_DEBUG_SYSLOG */
 
 /* Debugging function - conditional printf and hex dump. Driver wrappers can
  * use these for debugging purposes. */
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 9963c46..93888b0 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -98,6 +98,7 @@
 	u16 config_methods;
 	struct wpabuf *vendor_ext_m1;
 	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+	struct wpabuf *application_ext;
 
 	int p2p;
 	u8 multi_ap_ext;
@@ -344,6 +345,14 @@
 				 const char *dev_name);
 
 	/**
+	 * lookup_pskfile_cb - Callback for searching for PSK in wpa_psk_file
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @addr: Enrollee's MAC address
+	 * @psk: Pointer to found PSK (output arg)
+	 */
+	int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
+
+	/**
 	 * cb_ctx: Higher layer context data for Registrar callbacks
 	 */
 	void *cb_ctx;
@@ -386,11 +395,6 @@
 	int disable_auto_conf;
 
 	/**
-	 * static_wep_only - Whether the BSS supports only static WEP
-	 */
-	int static_wep_only;
-
-	/**
 	 * dualband - Whether this is a concurrent dualband AP
 	 */
 	int dualband;
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index b209fea..c2e949c 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -242,6 +242,21 @@
 }
 
 
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	if (!dev->application_ext)
+		return 0;
+
+	wpa_hexdump_buf(MSG_DEBUG, "WPS:  * Application Extension",
+			dev->application_ext);
+	wpabuf_put_be16(msg, ATTR_APPLICATION_EXT);
+	wpabuf_put_be16(msg, wpabuf_len(dev->application_ext));
+	wpabuf_put_buf(msg, dev->application_ext);
+
+	return 0;
+}
+
+
 static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
 				    size_t str_len)
 {
@@ -424,4 +439,6 @@
 	dev->model_number = NULL;
 	os_free(dev->serial_number);
 	dev->serial_number = NULL;
+	wpabuf_free(dev->application_ext);
+	dev->application_ext = NULL;
 }
diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h
index a4b4173..81fdd5f 100644
--- a/src/wps/wps_dev_attr.h
+++ b/src/wps/wps_dev_attr.h
@@ -33,6 +33,7 @@
 int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
 void wps_device_data_free(struct wps_device_data *dev);
 int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
 			   unsigned int num_req_dev_types,
 			   const u8 *req_dev_types);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 671f5fe..9ee89ae 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -17,6 +17,7 @@
 #include "crypto/sha256.h"
 #include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
 #include "wps_i.h"
 #include "wps_dev_attr.h"
 #include "wps_upnp.h"
@@ -159,6 +160,7 @@
 				 const u8 *pri_dev_type, u16 config_methods,
 				 u16 dev_password_id, u8 request_type,
 				 const char *dev_name);
+	int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
 	void *cb_ctx;
 
 	struct dl_list pins;
@@ -171,7 +173,6 @@
 	int sel_reg_union;
 	int sel_reg_dev_password_id_override;
 	int sel_reg_config_methods_override;
-	int static_wep_only;
 	int dualband;
 	int force_per_enrollee_psk;
 
@@ -681,6 +682,7 @@
 	reg->reg_success_cb = cfg->reg_success_cb;
 	reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
 	reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
+	reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb;
 	reg->cb_ctx = cfg->cb_ctx;
 	reg->skip_cred_build = cfg->skip_cred_build;
 	if (cfg->extra_cred) {
@@ -694,7 +696,6 @@
 	reg->disable_auto_conf = cfg->disable_auto_conf;
 	reg->sel_reg_dev_password_id_override = -1;
 	reg->sel_reg_config_methods_override = -1;
-	reg->static_wep_only = cfg->static_wep_only;
 	reg->dualband = cfg->dualband;
 	reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
 
@@ -1290,6 +1291,15 @@
 }
 
 
+static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr,
+				 const u8 **psk)
+{
+	if (!reg->lookup_pskfile_cb)
+		return 0;
+	return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk);
+}
+
+
 static int wps_set_ie(struct wps_registrar *reg)
 {
 	struct wpabuf *beacon;
@@ -1331,7 +1341,8 @@
 	    wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
 	    (reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon, 0)) ||
 	    wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) ||
-	    wps_build_vendor_ext(&reg->wps->dev, beacon)) {
+	    wps_build_vendor_ext(&reg->wps->dev, beacon) ||
+	    wps_build_application_ext(&reg->wps->dev, beacon)) {
 		wpabuf_free(beacon);
 		wpabuf_free(probe);
 		return -1;
@@ -1361,7 +1372,8 @@
 	    wps_build_probe_config_methods(reg, probe) ||
 	    (reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe, 0)) ||
 	    wps_build_wfa_ext(probe, 0, auth_macs, count, 0) ||
-	    wps_build_vendor_ext(&reg->wps->dev, probe)) {
+	    wps_build_vendor_ext(&reg->wps->dev, probe) ||
+	    wps_build_application_ext(&reg->wps->dev, probe)) {
 		wpabuf_free(beacon);
 		wpabuf_free(probe);
 		return -1;
@@ -1376,28 +1388,6 @@
 		return -1;
 	}
 
-	if (reg->static_wep_only) {
-		/*
-		 * Windows XP and Vista clients can get confused about
-		 * EAP-Identity/Request when they probe the network with
-		 * EAPOL-Start. In such a case, they may assume the network is
-		 * using IEEE 802.1X and prompt user for a certificate while
-		 * the correct (non-WPS) behavior would be to ask for the
-		 * static WEP key. As a workaround, use Microsoft Provisioning
-		 * IE to advertise that legacy 802.1X is not supported.
-		 */
-		const u8 ms_wps[7] = {
-			WLAN_EID_VENDOR_SPECIFIC, 5,
-			/* Microsoft Provisioning IE (00:50:f2:5) */
-			0x00, 0x50, 0xf2, 5,
-			0x00 /* no legacy 802.1X or MS WPS */
-		};
-		wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
-			   "into Beacon/Probe Response frames");
-		wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
-		wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
-	}
-
 	return wps_cb_set_ie(reg, beacon, probe);
 }
 
@@ -1642,6 +1632,8 @@
 {
 	struct wpabuf *cred;
 	struct wps_registrar *reg = wps->wps->registrar;
+	const u8 *pskfile_psk;
+	char hex[65];
 
 	if (wps->wps->registrar->skip_cred_build)
 		goto skip_cred_build;
@@ -1757,23 +1749,27 @@
 				      wps->new_psk, wps->new_psk_len);
 		os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
 		wps->cred.key_len = wps->new_psk_len;
+	} else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) {
+		wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file",
+				pskfile_psk, PMK_LEN);
+		wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN);
+		os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+		wps->cred.key_len = PMK_LEN * 2;
 	} else if (!wps->wps->registrar->force_per_enrollee_psk &&
 		   wps->use_psk_key && wps->wps->psk_set) {
-		char hex[65];
 		wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
-		wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
-		os_memcpy(wps->cred.key, hex, 32 * 2);
-		wps->cred.key_len = 32 * 2;
+		wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN);
+		os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+		wps->cred.key_len = PMK_LEN * 2;
 	} else if (!wps->wps->registrar->force_per_enrollee_psk &&
 		   wps->wps->network_key) {
 		os_memcpy(wps->cred.key, wps->wps->network_key,
 			  wps->wps->network_key_len);
 		wps->cred.key_len = wps->wps->network_key_len;
 	} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
-		char hex[65];
 		/* Generate a random per-device PSK */
 		os_free(wps->new_psk);
-		wps->new_psk_len = 32;
+		wps->new_psk_len = PMK_LEN;
 		wps->new_psk = os_malloc(wps->new_psk_len);
 		if (wps->new_psk == NULL)
 			return -1;
@@ -3482,6 +3478,7 @@
 		   "unselect internal Registrar");
 	reg->selected_registrar = 0;
 	reg->pbc = 0;
+	wps_registrar_expire_pins(reg);
 	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 309127e..65c639b 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -124,6 +124,7 @@
 OBJS += src/utils/wpabuf.c
 OBJS += src/utils/bitfield.c
 OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
 OBJS += wmm_ac.c
 OBJS += op_classes.c
 OBJS += rrm.c
@@ -195,6 +196,10 @@
 L_CFLAGS += -DCONFIG_VHT_OVERRIDES
 endif
 
+ifdef CONFIG_HE_OVERRIDES
+L_CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
 ifndef CONFIG_BACKEND
 CONFIG_BACKEND=file
 endif
@@ -282,6 +287,7 @@
 NEED_JSON=y
 NEED_GAS_SERVER=y
 NEED_BASE64=y
+NEED_ASN1=y
 ifdef CONFIG_DPP2
 L_CFLAGS += -DCONFIG_DPP2
 endif
@@ -410,6 +416,10 @@
 endif
 endif
 
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
 
 include $(LOCAL_PATH)/src/drivers/drivers.mk
 
@@ -890,7 +900,6 @@
 OBJS += src/ap/eap_user_db.c
 OBJS += src/ap/neighbor_db.c
 OBJS += src/ap/rrm.c
-ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
 ifdef CONFIG_IEEE80211AC
 OBJS += src/ap/ieee802_11_vht.c
@@ -898,7 +907,6 @@
 ifdef CONFIG_IEEE80211AX
 OBJS += src/ap/ieee802_11_he.c
 endif
-endif
 ifdef CONFIG_WNM_AP
 L_CFLAGS += -DCONFIG_WNM_AP
 OBJS += src/ap/wnm_ap.c
@@ -918,15 +926,12 @@
 OBJS += src/eap_server/eap_server_identity.c
 OBJS += src/eap_server/eap_server_methods.c
 
-ifdef CONFIG_IEEE80211N
-L_CFLAGS += -DCONFIG_IEEE80211N
 ifdef CONFIG_IEEE80211AC
 L_CFLAGS += -DCONFIG_IEEE80211AC
 endif
 ifdef CONFIG_IEEE80211AX
 L_CFLAGS += -DCONFIG_IEEE80211AX
 endif
-endif
 
 ifdef NEED_AP_MLME
 OBJS += src/ap/wmm.c
@@ -1123,7 +1128,7 @@
 OBJS += src/tls/tlsv1_client_write.c
 OBJS += src/tls/tlsv1_client_read.c
 OBJS += src/tls/tlsv1_client_ocsp.c
-OBJS += src/tls/asn1.c
+NEED_ASN1=y
 OBJS += src/tls/rsa.c
 OBJS += src/tls/x509v3.c
 OBJS += src/tls/pkcs1.c
@@ -1413,6 +1418,10 @@
 OBJS += src/crypto/sha512-prf.c
 endif
 
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
 ifdef NEED_DH_GROUPS
 OBJS += src/crypto/dh_groups.c
 endif
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 68ef5a2..45f673e 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -104,6 +104,7 @@
 OBJS += ../src/utils/wpabuf.o
 OBJS += ../src/utils/bitfield.o
 OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
 OBJS += op_classes.o
 OBJS += rrm.o
 OBJS_p = wpa_passphrase.o
@@ -197,6 +198,10 @@
 CFLAGS += -DCONFIG_VHT_OVERRIDES
 endif
 
+ifdef CONFIG_HE_OVERRIDES
+CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
 ifndef CONFIG_BACKEND
 CONFIG_BACKEND=file
 endif
@@ -284,6 +289,7 @@
 NEED_JSON=y
 NEED_GAS_SERVER=y
 NEED_BASE64=y
+NEED_ASN1=y
 ifdef CONFIG_DPP2
 CFLAGS += -DCONFIG_DPP2
 endif
@@ -906,7 +912,6 @@
 OBJS += ../src/ap/eap_user_db.o
 OBJS += ../src/ap/neighbor_db.o
 OBJS += ../src/ap/rrm.o
-ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
 ifdef CONFIG_IEEE80211AC
 OBJS += ../src/ap/ieee802_11_vht.o
@@ -914,7 +919,6 @@
 ifdef CONFIG_IEEE80211AX
 OBJS += ../src/ap/ieee802_11_he.o
 endif
-endif
 ifdef CONFIG_WNM_AP
 CFLAGS += -DCONFIG_WNM_AP
 OBJS += ../src/ap/wnm_ap.o
@@ -934,15 +938,12 @@
 OBJS += ../src/eap_server/eap_server_identity.o
 OBJS += ../src/eap_server/eap_server_methods.o
 
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
 ifdef CONFIG_IEEE80211AC
 CFLAGS += -DCONFIG_IEEE80211AC
 endif
 ifdef CONFIG_IEEE80211AX
 CFLAGS += -DCONFIG_IEEE80211AX
 endif
-endif
 
 ifdef NEED_AP_MLME
 OBJS += ../src/ap/wmm.o
@@ -1156,12 +1157,12 @@
 OBJS += ../src/tls/tlsv1_client_write.o
 OBJS += ../src/tls/tlsv1_client_read.o
 OBJS += ../src/tls/tlsv1_client_ocsp.o
-OBJS += ../src/tls/asn1.o
 OBJS += ../src/tls/rsa.o
 OBJS += ../src/tls/x509v3.o
 OBJS += ../src/tls/pkcs1.o
 OBJS += ../src/tls/pkcs5.o
 OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
 ifdef CONFIG_TLSV12
@@ -1235,12 +1236,12 @@
 OBJS += ../src/tls/tlsv1_client_write.o
 OBJS += ../src/tls/tlsv1_client_read.o
 OBJS += ../src/tls/tlsv1_client_ocsp.o
-OBJS += ../src/tls/asn1.o
 OBJS += ../src/tls/rsa.o
 OBJS += ../src/tls/x509v3.o
 OBJS += ../src/tls/pkcs1.o
 OBJS += ../src/tls/pkcs5.o
 OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
 ifdef CONFIG_TLSV12
@@ -1523,6 +1524,10 @@
 OBJS += ../src/crypto/sha512-prf.o
 endif
 
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
 ifdef NEED_DH_GROUPS
 OBJS += ../src/crypto/dh_groups.o
 endif
@@ -1846,6 +1851,10 @@
 OBJS_nfc += $(FST_OBJS)
 endif
 
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
 ifndef LDO
 LDO=$(CC)
 endif
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
index 457e32e..d378245 100644
--- a/wpa_supplicant/README-DPP
+++ b/wpa_supplicant/README-DPP
@@ -9,40 +9,44 @@
 Introduction to DPP
 -------------------
 
-Device provisioning Protocol allows enrolling of interface-less devices
-in a secure Wi-Fi network using many methods like QR code based
-authentication( detailed below ), PKEX based authentication etc. In DPP
-a Configurator is used to provide network credentials to the devices.
-The three phases of DPP connection are authentication, configuration and
+Device Provisioning Protocol (also known as Wi-Fi Easy Connect) allows
+enrolling of interface-less devices in a secure Wi-Fi network using many
+methods like QR code based authentication (detailed below), PKEX based
+authentication (password with in-band provisioning), etc. In DPP a
+Configurator is used to provide network credentials to the devices. The
+three phases of DPP connection are authentication, configuration and
 network introduction.
 
+More information about Wi-Fi Easy Connect is available from this Wi-Fi
+Alliance web page:
+https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect
+
 Build config setup
 ------------------
 
-The following changes must go in the config file used to compile hostapd
-and wpa_supplicant.
+The following parameters must be included in the config file used to
+compile hostapd and wpa_supplicant.
 
 wpa_supplicant build config
 ---------------------------
 
-Enable DPP and protected management frame in wpa_supplicant build config
-file
+Enable DPP in wpa_supplicant build config file
 
 CONFIG_DPP=y
 
 hostapd build config
 --------------------
 
-Enable DPP and protected management frame in hostapd build config file
+Enable DPP in hostapd build config file
 
 CONFIG_DPP=y
 
 Configurator build config
 -------------------------
 
-Any STA or AP device can act as a Configurator. Enable DPP and protected
-managment frames in build config. For an AP to act as Configurator,
-Interworking needs to be enabled. For wpa_supplicant it is not required.
+Any STA or AP device can act as a Configurator. Enable DPP in build
+config. For an AP to act as a Configurator, Interworking needs to be
+enabled for GAS. For wpa_supplicant it is not required.
 
 CONFIG_INTERWORKING=y
 
@@ -90,41 +94,46 @@
 > dpp_configurator_get_key <id>
 
 
-How to configure an enrollee using Configurator
+How to configure an Enrollee using Configurator
 -----------------------------------------------
 
-On enrollee side:
+On Enrollee side:
 
-Generate QR code for the device. Store the qr code id returned by the
+Generate QR code for the device. Store the QR code id returned by the
 command.
 
-> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/operating-channel> key=<key of the device>
-(returns bootstrapping info id)
+> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/channel> key=<key of the device>
+(Returns bootstrapping info id. If the key parameter is not included, a new key
+is generated automatically. The MAC address is specified without octet
+separating colons. The channel list includes the possible channels on which the
+device is waiting. This uses global operating classes; e.g., 81/1 is the 2.4
+GHz channel 1 on 2412 MHz.)
 
-Get QR Code of device using the bootstrap info id.
+Get URI for the QR Code of device using the bootstrap info id.
 > dpp_bootstrap_get_uri <bootstrap-id>
 
-Make device listen to DPP request (The central frequency of channel 1 is
-2412) in case if enrollee is a client device.
+Make device listen to DPP request. The central frequency of the 2.4 GHz
+band channel 1 is 2412 MHz) in case the Enrollee is a client device. An
+AP as an Enrollee is listening on its operating channel.
 
 > dpp_listen <frequency>
 
 On Configurator side:
 
 Enter the QR Code in the Configurator.
-> dpp_qr_code "<QR-Code-read-from-enrollee>"
+> dpp_qr_code "<URI-from-QR-Code-read-from-enrollee>"
 
 On successfully adding QR Code, a bootstrapping info id is returned.
 
-Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
-AP. conf is sta-dpp if enrollee is a client)
+Send provisioning request to Enrollee. (conf is ap-dpp if Enrollee is an
+AP. conf is sta-dpp if Enrollee is a client)
 > dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> ssid=<SSID hexdump> configurator=<configurator-id>
 or for legacy (PSK/SAE) provisioning for a station Enrollee:
 > dpp_auth_init peer=<qr-code-id> conf=sta-psk ssid=<SSID hexdump> pass=<passphrase hexdump>
 
-The DPP values will be printed in the console. Save this values into the
-config file. If the enrollee is an AP, we need to manually write these
-values to the hostapd config file. If the enrollee is a client device,
+The DPP values will be printed in the console. Save these values into the
+config file. If the Enrollee is an AP, we need to manually write these
+values to the hostapd config file. If the Enrollee is a client device,
 these details can be automatically saved to config file using the
 following command.
 
@@ -156,7 +165,7 @@
 
 > dpp_configurator_add
 (returns configurator id)
-> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> ssid=<SSID hexdump>
 
 
 Sample AP configuration files after provisioning
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index acefc92..5f8c8f6 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -435,11 +435,7 @@
 # either wpa_supplicant or hostapd are run.
 CONFIG_NO_RANDOM_POOL=y
 
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
-
 # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
 #CONFIG_IEEE80211AC=y
 
 # Wireless Network Management (IEEE Std 802.11v-2011)
@@ -552,4 +548,12 @@
 # Note: does not configure WAPI implementation itself.
 #CONFIG_WAPI_INTERFACE=y
 
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
+
 include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index e552306..6241682 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -44,7 +44,6 @@
 #endif /* CONFIG_WPS */
 
 
-#ifdef CONFIG_IEEE80211N
 static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
 			     struct wpa_ssid *ssid,
 			     struct hostapd_config *conf,
@@ -130,7 +129,6 @@
 		conf->channel + conf->secondary_channel * 2;
 	conf->vht_oper_chwidth = CHANWIDTH_USE_HT;
 }
-#endif /* CONFIG_IEEE80211N */
 
 
 int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
@@ -149,7 +147,6 @@
 	/* TODO: enable HT40 if driver supports it;
 	 * drop to 11b if driver does not support 11g */
 
-#ifdef CONFIG_IEEE80211N
 	/*
 	 * Enable HT20 if the driver supports it, by setting conf->ieee80211n
 	 * and a mask of allowed capabilities within conf->ht_capab.
@@ -269,7 +266,6 @@
 			conf->no_pri_sec_switch = 1;
 		}
 	}
-#endif /* CONFIG_IEEE80211N */
 
 	return 0;
 }
@@ -348,7 +344,9 @@
 #endif /* CONFIG_IEEE80211AX */
 
 	bss->isolate = !wpa_s->conf->p2p_intra_bss;
+	bss->extended_key_id = wpa_s->conf->extended_key_id;
 	bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
+	bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
 
 	if (ssid->p2p_group) {
 		os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4);
@@ -393,6 +391,7 @@
 		bss->ssid.wpa_psk_set = 1;
 	} else if (ssid->passphrase) {
 		bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+#ifdef CONFIG_WEP
 	} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
 		   ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
 		struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -408,6 +407,7 @@
 		}
 		wep->idx = ssid->wep_tx_keyidx;
 		wep->keys_set = 1;
+#endif /* CONFIG_WEP */
 	}
 #ifdef CONFIG_SAE
 	if (ssid->sae_password) {
@@ -489,11 +489,12 @@
 	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
 						    bss->rsn_pairwise);
 
-	if (bss->wpa && bss->ieee802_1x)
+	if (bss->wpa && bss->ieee802_1x) {
 		bss->ssid.security_policy = SECURITY_WPA;
-	else if (bss->wpa)
+	} else if (bss->wpa) {
 		bss->ssid.security_policy = SECURITY_WPA_PSK;
-	else if (bss->ieee802_1x) {
+#ifdef CONFIG_WEP
+	} else if (bss->ieee802_1x) {
 		int cipher = WPA_CIPHER_NONE;
 		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
 		bss->ssid.wep.default_len = bss->default_wep_key_len;
@@ -511,6 +512,7 @@
 		bss->wpa_group = cipher;
 		bss->wpa_pairwise = cipher;
 		bss->rsn_pairwise = cipher;
+#endif /* CONFIG_WEP */
 	} else {
 		bss->ssid.security_policy = SECURITY_PLAINTEXT;
 		bss->wpa_group = WPA_CIPHER_NONE;
@@ -605,6 +607,8 @@
 	bss->ftm_responder = wpa_s->conf->ftm_responder;
 	bss->ftm_initiator = wpa_s->conf->ftm_initiator;
 
+	bss->transition_disable = ssid->transition_disable;
+
 	return 0;
 }
 
@@ -839,7 +843,6 @@
 		return -1;
 	hapd_iface->owner = wpa_s;
 	hapd_iface->drv_flags = wpa_s->drv_flags;
-	hapd_iface->smps_modes = wpa_s->drv_smps_modes;
 	hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
 	hapd_iface->extended_capa = wpa_s->extended_capa;
 	hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 943a340..127f43e 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -906,7 +906,7 @@
 		}
 	}
 
-	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
+	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu",
 		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
 }
 
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 3ce8cd3..0716761 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -18,6 +18,7 @@
 #define WPA_BSS_AUTHENTICATED		BIT(4)
 #define WPA_BSS_ASSOCIATED		BIT(5)
 #define WPA_BSS_ANQP_FETCH_TRIED	BIT(6)
+#define WPA_BSS_OWE_TRANSITION		BIT(7)
 
 struct wpa_bss_anqp_elem {
 	struct dl_list list;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2d1c126..e1d9824 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1856,6 +1856,8 @@
 #endif /* IEEE8021X_EAPOL */
 
 
+#ifdef CONFIG_WEP
+
 static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
 				    const char *value, int idx)
 {
@@ -1966,6 +1968,8 @@
 }
 #endif /* NO_CONFIG_WRITE */
 
+#endif /* CONFIG_WEP */
+
 
 #ifdef CONFIG_P2P
 
@@ -2451,11 +2455,13 @@
 	{ STRe(openssl_ciphers, openssl_ciphers) },
 	{ INTe(erp, erp) },
 #endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
 	{ FUNC_KEY(wep_key0) },
 	{ FUNC_KEY(wep_key1) },
 	{ FUNC_KEY(wep_key2) },
 	{ FUNC_KEY(wep_key3) },
 	{ INT(wep_tx_keyidx) },
+#endif /* CONFIG_WEP */
 	{ INT(priority) },
 #ifdef IEEE8021X_EAPOL
 	{ INT(eap_workaround) },
@@ -2495,6 +2501,7 @@
 	{ INT(dot11MeshHoldingTimeout) },
 #endif /* CONFIG_MESH */
 	{ INT(wpa_ptk_rekey) },
+	{ INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) },
 	{ INT(group_rekey) },
 	{ STR(bgscan) },
 	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -2537,6 +2544,9 @@
 	{ INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
 	{ INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
 #endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+	{ INT_RANGE(disable_he, 0, 1)},
+#endif /* CONFIG_HE_OVERRIDES */
 	{ INT(ap_max_inactivity) },
 	{ INT(dtim_period) },
 	{ INT(beacon_int) },
@@ -2563,11 +2573,15 @@
 	{ STR_LEN(dpp_netaccesskey) },
 	{ INT(dpp_netaccesskey_expiry) },
 	{ STR_LEN(dpp_csign) },
+	{ INT_RANGE(dpp_pfs, 0, 2) },
 #endif /* CONFIG_DPP */
 	{ INT_RANGE(owe_group, 0, 65535) },
 	{ INT_RANGE(owe_only, 0, 1) },
+	{ INT_RANGE(owe_ptk_workaround, 0, 1) },
 	{ INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
 	{ INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
+	{ INT_RANGE(beacon_prot, 0, 1) },
+	{ INT_RANGE(transition_disable, 0, 255) },
 };
 
 #undef OFFSET
@@ -2603,7 +2617,7 @@
 int wpa_config_add_prio_network(struct wpa_config *config,
 				struct wpa_ssid *ssid)
 {
-	int prio;
+	size_t prio;
 	struct wpa_ssid *prev, **nlist;
 
 	/*
@@ -3018,6 +3032,7 @@
 	ssid->pairwise_cipher = DEFAULT_PAIRWISE;
 	ssid->group_cipher = DEFAULT_GROUP;
 	ssid->key_mgmt = DEFAULT_KEY_MGMT;
+	ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
 	ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
 	ssid->ht = 1;
 #ifdef IEEE8021X_EAPOL
@@ -4283,6 +4298,7 @@
 	config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
 	config->cert_in_cb = DEFAULT_CERT_IN_CB;
 	config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+	config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
 
 #ifdef CONFIG_MBO
 	config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
@@ -4308,7 +4324,7 @@
  */
 void wpa_config_debug_dump_networks(struct wpa_config *config)
 {
-	int prio;
+	size_t prio;
 	struct wpa_ssid *ssid;
 
 	for (prio = 0; prio < config->num_prio; prio++) {
@@ -4639,7 +4655,7 @@
 	struct wpa_config *config, int line, const char *pos)
 {
 	struct p2p_channel *pref = NULL, *n;
-	unsigned int num = 0;
+	size_t num = 0;
 	const char *pos2;
 	u8 op_class, chan;
 
@@ -4997,7 +5013,7 @@
 	{ INT(okc), 0 },
 	{ INT(pmf), 0 },
 	{ FUNC(sae_groups), 0 },
-	{ INT_RANGE(sae_pwe, 0, 2), 0 },
+	{ INT_RANGE(sae_pwe, 0, 3), 0 },
 	{ INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
 	{ INT(dtim_period), 0 },
 	{ INT(beacon_int), 0 },
@@ -5047,6 +5063,7 @@
 	{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
 #ifdef CONFIG_WNM
 	{ INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
+	{ INT_RANGE(extended_key_id, 0, 1), 0 },
 #endif /* CONFIG_WNM */
 };
 
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index d00c4ec..0ca27cb 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -44,6 +44,7 @@
 #define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
 #define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75
 #define DEFAULT_OCE_SUPPORT OCE_STA
+#define DEFAULT_EXTENDED_KEY_ID 0
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -332,7 +333,7 @@
 	 */
 	unsigned int max_bss_load;
 
-	unsigned int num_req_conn_capab;
+	size_t num_req_conn_capab;
 	u8 *req_conn_capab_proto;
 	int **req_conn_capab_port;
 
@@ -403,7 +404,7 @@
 	 * This indicates how many per-priority network lists are included in
 	 * pssid.
 	 */
-	int num_prio;
+	size_t num_prio;
 
 	/**
 	 * cred - Head of the credential list
@@ -1578,6 +1579,17 @@
 	 * By default BSS transition management is enabled
 	 */
 	int disable_btm;
+
+	/**
+	 * extended_key_id - Extended Key ID support
+	 *
+	 * IEEE Std 802.11-2016 optionally allows to use Key ID 0 and 1 for PTK
+	 * keys with Extended Key ID.
+	 *
+	 * 0 = don't use Extended Key ID
+	 * 1 = use Extended Key ID when possible
+	 */
+	int extended_key_id;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 305291e..52e1372 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -213,8 +213,22 @@
 			}
 		}
 
-		if (wpa_config_set(ssid, pos, pos2, *line) < 0)
+		if (wpa_config_set(ssid, pos, pos2, *line) < 0) {
+#ifndef CONFIG_WEP
+			if (os_strcmp(pos, "wep_key0") == 0 ||
+			    os_strcmp(pos, "wep_key1") == 0 ||
+			    os_strcmp(pos, "wep_key2") == 0 ||
+			    os_strcmp(pos, "wep_key3") == 0 ||
+			    os_strcmp(pos, "wep_tx_keyidx") == 0) {
+				wpa_printf(MSG_ERROR,
+					   "Line %d: unsupported WEP parameter",
+					   *line);
+				ssid->disabled = 1;
+				continue;
+			}
+#endif /* CONFIG_WEP */
 			errors++;
+		}
 	}
 
 	if (!end) {
@@ -653,6 +667,7 @@
 #endif /* IEEE8021X_EAPOL */
 
 
+#ifdef CONFIG_WEP
 static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
 {
 	char field[20], *value;
@@ -667,6 +682,7 @@
 		os_free(value);
 	}
 }
+#endif /* CONFIG_WEP */
 
 
 #ifdef CONFIG_P2P
@@ -741,8 +757,6 @@
 
 static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
 {
-	int i;
-
 #define STR(t) write_str(f, #t, ssid)
 #define INT(t) write_int(f, #t, ssid->t, 0)
 #define INTe(t, m) write_int(f, #t, ssid->eap.m, 0)
@@ -831,9 +845,15 @@
 	STR(openssl_ciphers);
 	INTe(erp, erp);
 #endif /* IEEE8021X_EAPOL */
-	for (i = 0; i < 4; i++)
-		write_wep_key(f, i, ssid);
-	INT(wep_tx_keyidx);
+#ifdef CONFIG_WEP
+	{
+		int i;
+
+		for (i = 0; i < 4; i++)
+			write_wep_key(f, i, ssid);
+		INT(wep_tx_keyidx);
+	}
+#endif /* CONFIG_WEP */
 	INT(priority);
 #ifdef IEEE8021X_EAPOL
 	INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
@@ -900,6 +920,7 @@
 	INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD);
 #endif /* CONFIG_MESH */
 	INT(wpa_ptk_rekey);
+	INT(wpa_deny_ptk0_rekey);
 	INT(group_rekey);
 	INT(ignore_broadcast_ssid);
 #ifdef CONFIG_DPP
@@ -907,11 +928,15 @@
 	STR(dpp_netaccesskey);
 	INT(dpp_netaccesskey_expiry);
 	STR(dpp_csign);
+	INT(dpp_pfs);
 #endif /* CONFIG_DPP */
 	INT(owe_group);
 	INT(owe_only);
+	INT(owe_ptk_workaround);
 	INT(multi_ap_backhaul_sta);
 	INT(ft_eap_pmksa_caching);
+	INT(beacon_prot);
+	INT(transition_disable);
 #ifdef CONFIG_HT_OVERRIDES
 	INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
 	INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
@@ -946,6 +971,9 @@
 	INT_DEF(vht_tx_mcs_nss_7, -1);
 	INT_DEF(vht_tx_mcs_nss_8, -1);
 #endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+	INT(disable_he);
+#endif /* CONFIG_HE_OVERRIDES */
 
 #undef STR
 #undef INT
@@ -1576,6 +1604,9 @@
 			config->bss_no_flush_when_down);
 	if (config->disable_btm)
 		fprintf(f, "disable_btm=1\n");
+	if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID)
+		fprintf(f, "extended_key_id=%d\n",
+			config->extended_key_id);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
@@ -1592,9 +1623,16 @@
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 	int ret = 0;
 	const char *orig_name = name;
-	int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
-	char *tmp_name = os_malloc(tmp_len);
+	int tmp_len;
+	char *tmp_name;
 
+	if (!name) {
+		wpa_printf(MSG_ERROR, "No configuration file for writing");
+		return -1;
+	}
+
+	tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
+	tmp_name = os_malloc(tmp_len);
 	if (tmp_name) {
 		os_snprintf(tmp_name, tmp_len, "%s.tmp", name);
 		name = tmp_name;
@@ -1622,8 +1660,11 @@
 	for (ssid = config->ssid; ssid; ssid = ssid->next) {
 		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
 			continue; /* do not save temporary networks */
-		if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
-		    !ssid->passphrase)
+		if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) &&
+		    !ssid->psk_set && !ssid->passphrase)
+			continue; /* do not save invalid network */
+		if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+		    !ssid->passphrase && !ssid->sae_password)
 			continue; /* do not save invalid network */
 		fprintf(f, "\nnetwork={\n");
 		wpa_config_write_network(f, ssid);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index af8317b..a186ab9 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -299,6 +299,7 @@
 	struct eap_peer_config eap;
 #endif /* IEEE8021X_EAPOL */
 
+#ifdef CONFIG_WEP
 #define NUM_WEP_KEYS 4
 #define MAX_WEP_KEY_LEN 16
 	/**
@@ -315,6 +316,7 @@
 	 * wep_tx_keyidx - Default key index for TX frames using WEP
 	 */
 	int wep_tx_keyidx;
+#endif /* CONFIG_WEP */
 
 	/**
 	 * proactive_key_caching - Enable proactive key caching
@@ -552,6 +554,19 @@
 	 */
 	int wpa_ptk_rekey;
 
+	/** wpa_deny_ptk0_rekey - Control PTK0 rekeying
+	 *
+	 * Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many
+	 * broken implementations and should be avoided when using or
+	 * interacting with one.
+	 *
+	 * 0 = always rekey when configured/instructed
+	 * 1 = only rekey when the local driver is explicitly indicating it can
+	 *	perform this operation without issues
+	 * 2 = never allow PTK0 rekeys
+	 */
+	enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
+
 	/**
 	 * group_rekey - Group rekeying time in seconds
 	 *
@@ -763,6 +778,16 @@
 	    vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
 #endif /* CONFIG_VHT_OVERRIDES */
 
+#ifdef CONFIG_HE_OVERRIDES
+	/**
+	 * disable_he - Disable HE (IEEE 802.11ax) for this network
+	 *
+	 * By default, use it if it is available, but this can be configured
+	 * to 1 to have it disabled.
+	 */
+	int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
 	/**
 	 * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
 	 *
@@ -987,6 +1012,22 @@
 	size_t dpp_csign_len;
 
 	/**
+	 * dpp_pfs - DPP PFS
+	 * 0: allow PFS to be used or not used
+	 * 1: require PFS to be used (note: not compatible with DPP R1)
+	 * 2: do not allow PFS to be used
+	 */
+	int dpp_pfs;
+
+	/**
+	 * dpp_pfs_fallback - DPP PFS fallback selection
+	 *
+	 * This is an internally used variable (i.e., not used in external
+	 * configuration) to track state of the DPP PFS fallback mechanism.
+	 */
+	int dpp_pfs_fallback;
+
+	/**
 	 * owe_group - OWE DH Group
 	 *
 	 * 0 = use default (19) first and then try all supported groups one by
@@ -1008,6 +1049,19 @@
 	int owe_only;
 
 	/**
+	 * owe_ptk_workaround - OWE PTK derivation workaround
+	 *
+	 * Initial OWE implementation used SHA256 when deriving the PTK for all
+	 * OWE groups. This was supposed to change to SHA384 for group 20 and
+	 * SHA512 for group 21. This parameter can be used to enable older
+	 * behavior mainly for testing purposes. There is no impact to group 19
+	 * behavior, but if enabled, this will make group 20 and 21 cases use
+	 * SHA256-based PTK derivation which will not work with the updated
+	 * OWE implementation on the AP side.
+	 */
+	int owe_ptk_workaround;
+
+	/**
 	 * owe_transition_bss_select_count - OWE transition BSS select count
 	 *
 	 * This is an internally used variable (i.e., not used in external
@@ -1033,6 +1087,34 @@
 	 * FT initial mobility domain association.
 	 */
 	int ft_eap_pmksa_caching;
+
+	/**
+	 * beacon_prot - Whether Beacon protection is enabled
+	 *
+	 * This depends on management frame protection (ieee80211w) being
+	 * enabled.
+	 */
+	int beacon_prot;
+
+	/**
+	 * transition_disable - Transition Disable indication
+	 * The AP can notify authenticated stations to disable transition mode
+	 * in their network profiles when the network has completed transition
+	 * steps, i.e., once sufficiently large number of APs in the ESS have
+	 * been updated to support the more secure alternative. When this
+	 * indication is used, the stations are expected to automatically
+	 * disable transition mode and less secure security options. This
+	 * includes use of WEP, TKIP (including use of TKIP as the group
+	 * cipher), and connections without PMF.
+	 * Bitmap bits:
+	 * bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK
+	 *	and only allow SAE to be used)
+	 * bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+	 * bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+	 * bit 3 (0x08): Enhanced Open (disable use of open network; require
+	 *	OWE)
+	 */
+	u8 transition_disable;
 };
 
 #endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 0f2a30a..1b7f96e 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -277,6 +277,15 @@
 	wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
 	wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
 	config->pmf = val;
+	if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"),
+				      &val) == 0) {
+		if (val < 0 || val > 1) {
+			wpa_printf(MSG_ERROR,
+				   "Invalid Extended Key ID setting (%d)", val);
+			errors++;
+		}
+		config->extended_key_id = val;
+	}
 
 	return errors ? -1 : 0;
 }
@@ -823,6 +832,7 @@
 #endif /* IEEE8021X_EAPOL */
 
 
+#ifdef CONFIG_WEP
 static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
 {
 	char field[20], *value;
@@ -834,11 +844,12 @@
 		os_free(value);
 	}
 }
+#endif /* CONFIG_WEP */
 
 
 static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
 {
-	int i, errors = 0;
+	int errors = 0;
 	HKEY nhk, netw;
 	LONG ret;
 	TCHAR name[5];
@@ -924,9 +935,15 @@
 	INTe(engine2, phase2_cert.engine);
 	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
 #endif /* IEEE8021X_EAPOL */
-	for (i = 0; i < 4; i++)
-		write_wep_key(netw, i, ssid);
-	INT(wep_tx_keyidx);
+#ifdef CONFIG_WEP
+	{
+		int i;
+
+		for (i = 0; i < 4; i++)
+			write_wep_key(netw, i, ssid);
+		INT(wep_tx_keyidx);
+	}
+#endif /* CONFIG_WEP */
 	INT(priority);
 #ifdef IEEE8021X_EAPOL
 	INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index be5ea17..7301d50 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -419,6 +419,64 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static int wpas_ctrl_iface_set_dso(struct wpa_supplicant *wpa_s,
+				   const char *val)
+{
+	u8 bssid[ETH_ALEN];
+	const char *pos = val;
+	struct driver_signal_override *dso = NULL, *tmp, parsed;
+
+	if (hwaddr_aton(pos, bssid))
+		return -1;
+	pos = os_strchr(pos, ' ');
+
+	dl_list_for_each(tmp, &wpa_s->drv_signal_override,
+			 struct driver_signal_override, list) {
+		if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
+			dso = tmp;
+			break;
+		}
+	}
+
+	if (!pos) {
+		/* Remove existing entry */
+		if (dso) {
+			dl_list_del(&dso->list);
+			os_free(dso);
+		}
+		return 0;
+	}
+	pos++;
+
+	/* Update an existing entry or add a new one */
+	os_memset(&parsed, 0, sizeof(parsed));
+	if (sscanf(pos, "%d %d %d %d %d",
+		   &parsed.si_current_signal,
+		   &parsed.si_avg_signal,
+		   &parsed.si_avg_beacon_signal,
+		   &parsed.si_current_noise,
+		   &parsed.scan_level) != 5)
+		return -1;
+
+	if (!dso) {
+		dso = os_zalloc(sizeof(*dso));
+		if (!dso)
+			return -1;
+		os_memcpy(dso->bssid, bssid, ETH_ALEN);
+		dl_list_add(&wpa_s->drv_signal_override, &dso->list);
+	}
+	dso->si_current_signal = parsed.si_current_signal;
+	dso->si_avg_signal = parsed.si_avg_signal;
+	dso->si_avg_beacon_signal = parsed.si_avg_beacon_signal;
+	dso->si_current_noise = parsed.si_current_noise;
+	dso->scan_level = parsed.scan_level;
+
+	return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 					 char *cmd)
 {
@@ -663,6 +721,8 @@
 		wpa_s->ignore_assoc_disallow = !!atoi(value);
 		wpa_drv_ignore_assoc_disallow(wpa_s,
 					      wpa_s->ignore_assoc_disallow);
+	} else if (os_strcasecmp(cmd, "disable_sa_query") == 0) {
+		wpa_s->disable_sa_query = !!atoi(value);
 	} else if (os_strcasecmp(cmd, "ignore_sae_h2e_only") == 0) {
 		wpa_s->ignore_sae_h2e_only = !!atoi(value);
 	} else if (os_strcasecmp(cmd, "extra_sae_rejected_groups") == 0) {
@@ -687,6 +747,12 @@
 				break;
 			pos++;
 		}
+	} else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
+		wpabuf_free(wpa_s->rsne_override_eapol);
+		if (os_strcmp(value, "NULL") == 0)
+			wpa_s->rsne_override_eapol = NULL;
+		else
+			wpa_s->rsne_override_eapol = wpabuf_parse_bin(value);
 	} else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) {
 		wpabuf_free(wpa_s->rsnxe_override_assoc);
 		if (os_strcmp(value, "NULL") == 0)
@@ -713,6 +779,8 @@
 			wpa_s->sae_commit_override = NULL;
 		else
 			wpa_s->sae_commit_override = wpabuf_parse_bin(value);
+	} else if (os_strcasecmp(cmd, "driver_signal_override") == 0) {
+		ret = wpas_ctrl_iface_set_dso(wpa_s, value);
 #ifdef CONFIG_DPP
 	} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
 		os_free(wpa_s->dpp_config_obj_override);
@@ -851,6 +919,8 @@
 		return wpa_snprintf_hex(buf, buflen,
 					wpa_sm_get_anonce(wpa_s->wpa),
 					WPA_NONCE_LEN);
+	} else if (os_strcasecmp(cmd, "last_tk_key_idx") == 0) {
+		res = os_snprintf(buf, buflen, "%d", wpa_s->last_tk_key_idx);
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else {
 		res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
@@ -3889,8 +3959,10 @@
 	{ WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
 	{ WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
 	{ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+#ifdef CONFIG_WEP
 	{ WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
 	{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+#endif /* CONFIG_WEP */
 };
 
 static const struct cipher_info ciphers_group_mgmt[] = {
@@ -3952,7 +4024,11 @@
 	if (res < 0) {
 		if (strict)
 			return 0;
+#ifdef CONFIG_WEP
 		len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
+#else /* CONFIG_WEP */
+		len = os_strlcpy(buf, "CCMP TKIP", buflen);
+#endif /* CONFIG_WEP */
 		if (len >= buflen)
 			return -1;
 		return len;
@@ -5285,15 +5361,24 @@
 {
 	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
 	/* MLME-DELETEKEYS.request */
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
 
 	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
-			0);
+			0, KEY_FLAG_PAIRWISE);
+	if (wpa_sm_ext_key_id(wpa_s->wpa))
+		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0,
+				NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
 	/* MLME-SETPROTECTION.request(None) */
 	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
 				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -7130,7 +7215,7 @@
 		return -1;
 	}
 
-	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
 	if (bss == NULL) {
 		wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
 			   MAC2STR(bssid));
@@ -8019,6 +8104,10 @@
 	wpa_s->dpp_resp_wait_time = 0;
 	wpa_s->dpp_resp_max_tries = 0;
 	wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_DPP2
+	wpas_dpp_chirp_stop(wpa_s);
+	wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
 #ifdef CONFIG_TESTING_OPTIONS
 	os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
 	os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
@@ -8038,9 +8127,12 @@
 
 	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
 	wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+	wpa_s->last_michael_mic_error.sec = 0;
 
 	wpa_s->no_keep_alive = 0;
 	wpa_s->own_disconnect_req = 0;
+	wpa_s->own_reconnect_req = 0;
+	wpa_s->deny_ptk0_rekey = 0;
 
 	os_free(wpa_s->disallow_aps_bssid);
 	wpa_s->disallow_aps_bssid = NULL;
@@ -8089,6 +8181,7 @@
 	wpa_s->p2p_go_csa_on_inv = 0;
 	wpa_s->ignore_auth_resp = 0;
 	wpa_s->ignore_assoc_disallow = 0;
+	wpa_s->disable_sa_query = 0;
 	wpa_s->testing_resend_assoc = 0;
 	wpa_s->ignore_sae_h2e_only = 0;
 	wpa_s->reject_btm_req_reason = 0;
@@ -8099,10 +8192,13 @@
 	wpa_s->sae_commit_override = NULL;
 	os_free(wpa_s->extra_sae_rejected_groups);
 	wpa_s->extra_sae_rejected_groups = NULL;
+	wpabuf_free(wpa_s->rsne_override_eapol);
+	wpa_s->rsne_override_eapol = NULL;
 	wpabuf_free(wpa_s->rsnxe_override_assoc);
 	wpa_s->rsnxe_override_assoc = NULL;
 	wpabuf_free(wpa_s->rsnxe_override_eapol);
 	wpa_s->rsnxe_override_eapol = NULL;
+	wpas_clear_driver_signal_override(wpa_s);
 #ifdef CONFIG_DPP
 	os_free(wpa_s->dpp_config_obj_override);
 	wpa_s->dpp_config_obj_override = NULL;
@@ -8117,6 +8213,8 @@
 	wpa_s->disconnected = 0;
 	os_free(wpa_s->next_scan_freqs);
 	wpa_s->next_scan_freqs = NULL;
+	os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
+	wpa_s->next_scan_bssid_wildcard_ssid = 0;
 	os_free(wpa_s->select_network_scan_freqs);
 	wpa_s->select_network_scan_freqs = NULL;
 
@@ -8135,6 +8233,7 @@
 
 #ifdef CONFIG_SME
 	wpa_s->sme.last_unprot_disconnect.sec = 0;
+	wpa_s->sme.auth_alg = 0;
 #endif /* CONFIG_SME */
 
 	wpabuf_free(wpa_s->ric_ies);
@@ -8451,6 +8550,9 @@
 				goto done;
 			}
 			os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
+
+			wpa_s->next_scan_bssid_wildcard_ssid =
+				os_strstr(params, "wildcard_ssid=1") != NULL;
 		}
 
 		pos = params;
@@ -8962,7 +9064,7 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	const struct ether_header *eth;
-	struct iphdr ip;
+	struct ip ip;
 	const u8 *pos;
 	unsigned int i;
 	char extra[30];
@@ -8978,14 +9080,13 @@
 	os_memcpy(&ip, eth + 1, sizeof(ip));
 	pos = &buf[sizeof(*eth) + sizeof(ip)];
 
-	if (ip.ihl != 5 || ip.version != 4 ||
-	    ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+	if (ip.ip_hl != 5 || ip.ip_v != 4 || ntohs(ip.ip_len) > HWSIM_IP_LEN) {
 		wpa_printf(MSG_DEBUG,
 			   "test data: RX - ignore unexpect IP header");
 		return;
 	}
 
-	for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+	for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
 		if (*pos != (u8) i) {
 			wpa_printf(MSG_DEBUG,
 				   "test data: RX - ignore mismatching payload");
@@ -8994,8 +9095,8 @@
 		pos++;
 	}
 	extra[0] = '\0';
-	if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
-		os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+	if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+		os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
 	wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
 		MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
 }
@@ -9047,7 +9148,7 @@
 	u8 tos;
 	u8 buf[2 + HWSIM_PACKETLEN];
 	struct ether_header *eth;
-	struct iphdr *ip;
+	struct ip *ip;
 	u8 *dpos;
 	unsigned int i;
 	size_t send_len = HWSIM_IP_LEN;
@@ -9086,17 +9187,17 @@
 	os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
 	os_memcpy(eth->ether_shost, src, ETH_ALEN);
 	eth->ether_type = htons(ETHERTYPE_IP);
-	ip = (struct iphdr *) (eth + 1);
+	ip = (struct ip *) (eth + 1);
 	os_memset(ip, 0, sizeof(*ip));
-	ip->ihl = 5;
-	ip->version = 4;
-	ip->ttl = 64;
-	ip->tos = tos;
-	ip->tot_len = htons(send_len);
-	ip->protocol = 1;
-	ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
-	ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
-	ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+	ip->ip_hl = 5;
+	ip->ip_v = 4;
+	ip->ip_ttl = 64;
+	ip->ip_tos = tos;
+	ip->ip_len = htons(send_len);
+	ip->ip_p = 1;
+	ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+	ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+	ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
 	dpos = (u8 *) (ip + 1);
 	for (i = 0; i < send_len - sizeof(*ip); i++)
 		*dpos++ = i;
@@ -9289,13 +9390,15 @@
 	 * in the driver. */
 	if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
 			    wpa_s->last_tk_key_idx, 1, zero, 6,
-			    zero, wpa_s->last_tk_len) < 0)
+			    zero, wpa_s->last_tk_len,
+			    KEY_FLAG_PAIRWISE_RX_TX) < 0)
 		return -1;
 
 	/* Set the previously configured key to reset its TSC/RSC */
 	return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
 			       wpa_s->last_tk_key_idx, 1, zero, 6,
-			       wpa_s->last_tk, wpa_s->last_tk_len);
+			       wpa_s->last_tk, wpa_s->last_tk_len,
+			       KEY_FLAG_PAIRWISE_RX_TX);
 }
 
 
@@ -10741,6 +10844,28 @@
 			if (os_snprintf_error(reply_size, reply_len))
 				reply_len = -1;
 		}
+	} else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+		int res;
+
+		res = wpas_dpp_nfc_handover_req(wpa_s, buf + 20);
+		if (res < 0) {
+			reply_len = -1;
+		} else {
+			reply_len = os_snprintf(reply, reply_size, "%d", res);
+			if (os_snprintf_error(reply_size, reply_len))
+				reply_len = -1;
+		}
+	} else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+		int res;
+
+		res = wpas_dpp_nfc_handover_sel(wpa_s, buf + 20);
+		if (res < 0) {
+			reply_len = -1;
+		} else {
+			reply_len = os_snprintf(reply, reply_size, "%d", res);
+			if (os_snprintf_error(reply_size, reply_len))
+				reply_len = -1;
+		}
 	} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
 		int res;
 
@@ -10769,6 +10894,10 @@
 	} else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
 		reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19),
 					       reply, reply_size);
+	} else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+		if (dpp_bootstrap_set(wpa_s->dpp, atoi(buf + 18),
+				      os_strchr(buf + 18, ' ')) < 0)
+			reply_len = -1;
 	} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
 		if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
 			reply_len = -1;
@@ -10822,6 +10951,11 @@
 			reply_len = -1;
 	} else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
 		dpp_controller_stop(wpa_s->dpp);
+	} else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
+		if (wpas_dpp_chirp(wpa_s, buf + 9) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
+		wpas_dpp_chirp_stop(wpa_s);
 #endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
 	} else {
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 8a6057a..1e92b97 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -516,7 +516,7 @@
 		return;
 
 	if (ifname)
-		os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
+		os_snprintf(levelstr, sizeof(levelstr), "IFNAME=%s <%d>",
 			    ifname, level);
 	else
 		os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 4b6dabc..4e17e31 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -991,20 +991,25 @@
 	const struct wpa_dbus_property_desc *property_desc,
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
-	const char *capabilities[11];
+	const char *capabilities[12];
 	size_t num_items = 0;
-#ifdef CONFIG_FILS
 	struct wpa_global *global = user_data;
 	struct wpa_supplicant *wpa_s;
+#ifdef CONFIG_FILS
 	int fils_supported = 0, fils_sk_pfs_supported = 0;
+#endif /* CONFIG_FILS */
+	int ext_key_id_supported = 0;
 
 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+#ifdef CONFIG_FILS
 		if (wpa_is_fils_supported(wpa_s))
 			fils_supported = 1;
 		if (wpa_is_fils_sk_pfs_supported(wpa_s))
 			fils_sk_pfs_supported = 1;
-	}
 #endif /* CONFIG_FILS */
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)
+			ext_key_id_supported = 1;
+	}
 
 #ifdef CONFIG_AP
 	capabilities[num_items++] = "ap";
@@ -1037,6 +1042,8 @@
 #ifdef CONFIG_OWE
 	capabilities[num_items++] = "owe";
 #endif /* CONFIG_OWE */
+	if (ext_key_id_supported)
+		capabilities[num_items++] = "extended_key_id";
 
 	return wpas_dbus_simple_array_property_getter(iter,
 						      DBUS_TYPE_STRING,
@@ -1146,7 +1153,7 @@
 				  DBusMessage **reply)
 {
 	u8 *ies = NULL, *nies;
-	int ies_len = 0;
+	size_t ies_len = 0;
 	DBusMessageIter array_iter, sub_array_iter;
 	char *val;
 	int len;
@@ -1177,7 +1184,7 @@
 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
 
 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
-		if (len == 0) {
+		if (len <= 0) {
 			dbus_message_iter_next(&array_iter);
 			continue;
 		}
@@ -1208,7 +1215,7 @@
 {
 	DBusMessageIter array_iter, sub_array_iter;
 	int *freqs = NULL, *nfreqs;
-	int freqs_num = 0;
+	size_t freqs_num = 0;
 
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
 		wpa_printf(MSG_DEBUG,
@@ -2664,7 +2671,10 @@
 	/***** group cipher */
 	if (res < 0) {
 		const char *args[] = {
-			"ccmp", "tkip", "wep104", "wep40"
+			"ccmp", "tkip",
+#ifdef CONFIG_WEP
+			"wep104", "wep40"
+#endif /* CONFIG_WEP */
 		};
 
 		if (!wpa_dbus_dict_append_string_array(
@@ -2691,12 +2701,14 @@
 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
 		     !wpa_dbus_dict_string_array_add_element(
 			     &iter_array, "tkip")) ||
+#ifdef CONFIG_WEP
 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
 		     !wpa_dbus_dict_string_array_add_element(
 			     &iter_array, "wep104")) ||
 		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
 		     !wpa_dbus_dict_string_array_add_element(
 			     &iter_array, "wep40")) ||
+#endif /* CONFIG_WEP */
 		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
@@ -2793,6 +2805,12 @@
 			goto nomem;
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_SAE
+		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+		    !wpa_dbus_dict_string_array_add_element(&iter_array, "sae"))
+			goto nomem;
+#endif /* CONFIG_SAE */
+
 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
@@ -4733,9 +4751,14 @@
 
 	/* Group */
 	switch (ie_data->group_cipher) {
+#ifdef CONFIG_WEP
 	case WPA_CIPHER_WEP40:
 		group = "wep40";
 		break;
+	case WPA_CIPHER_WEP104:
+		group = "wep104";
+		break;
+#endif /* CONFIG_WEP */
 	case WPA_CIPHER_TKIP:
 		group = "tkip";
 		break;
@@ -4745,9 +4768,6 @@
 	case WPA_CIPHER_GCMP:
 		group = "gcmp";
 		break;
-	case WPA_CIPHER_WEP104:
-		group = "wep104";
-		break;
 	case WPA_CIPHER_CCMP_256:
 		group = "ccmp-256";
 		break;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index db76c6a..ef2339f 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -77,7 +77,7 @@
 #CONFIG_DRIVER_MACSEC_QCA=y
 
 # Driver interface for Linux MACsec drivers
-#CONFIG_DRIVER_MACSEC_LINUX=y
+CONFIG_DRIVER_MACSEC_LINUX=y
 
 # Driver interface for the Broadcom RoboSwitch family
 #CONFIG_DRIVER_ROBOSWITCH=y
@@ -183,7 +183,7 @@
 #CONFIG_EAP_EKE=y
 
 # MACsec
-#CONFIG_MACSEC=y
+CONFIG_MACSEC=y
 
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
@@ -248,7 +248,7 @@
 # Simultaneous Authentication of Equals (SAE), WPA3-Personal
 CONFIG_SAE=y
 
-# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# Disable scan result processing (ap_scan=1) to save code size by about 1 kB.
 # This can be used if ap_scan=1 mode is never enabled.
 #CONFIG_NO_SCAN_PROCESSING=y
 
@@ -471,11 +471,7 @@
 # Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
 #CONFIG_GETRANDOM=y
 
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
-
 # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
 CONFIG_IEEE80211AC=y
 
 # Wireless Network Management (IEEE Std 802.11v-2011)
@@ -612,3 +608,12 @@
 # Configure the building of the interface which allows WAPI configuration.
 # Note: does not configure WAPI implementation itself.
 #CONFIG_WAPI_INTERFACE=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
+
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 73649c2..c75ab47 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1,7 +1,7 @@
 /*
  * wpa_supplicant - DPP
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -107,6 +107,71 @@
 }
 
 
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+	const char *pos;
+	struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+	pos = os_strstr(cmd, " own=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+	if (!own_bi)
+		return -1;
+
+	pos = os_strstr(cmd, " uri=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+	if (!peer_bi) {
+		wpa_printf(MSG_INFO,
+			   "DPP: Failed to parse URI from NFC Handover Request");
+		return -1;
+	}
+
+	if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+		return -1;
+
+	return peer_bi->id;
+}
+
+
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+	const char *pos;
+	struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+	pos = os_strstr(cmd, " own=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+	if (!own_bi)
+		return -1;
+
+	pos = os_strstr(cmd, " uri=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+	if (!peer_bi) {
+		wpa_printf(MSG_INFO,
+			   "DPP: Failed to parse URI from NFC Handover Select");
+		return -1;
+	}
+
+	if (peer_bi->curve != own_bi->curve) {
+		wpa_printf(MSG_INFO,
+			   "DPP: Peer (NFC Handover Selector) used different curve");
+		return -1;
+	}
+
+	return peer_bi->id;
+}
+
+
 static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -689,6 +754,8 @@
 			wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
 		else
 			wpa_s->dpp_netrole = DPP_NETROLE_STA;
+	} else {
+		wpa_s->dpp_netrole = DPP_NETROLE_STA;
 	}
 
 	pos = os_strstr(cmd, " neg_freq=");
@@ -705,12 +772,12 @@
 		wpa_s->dpp_auth = NULL;
 	}
 
-	auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles, neg_freq,
-			     wpa_s->hw.modes, wpa_s->hw.num_modes);
+	auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
+			     neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
 	if (!auth)
 		goto fail;
 	wpas_dpp_set_testing_options(wpa_s, auth);
-	if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) < 0) {
+	if (dpp_set_configurator(auth, cmd) < 0) {
 		dpp_auth_deinit(auth);
 		goto fail;
 	}
@@ -911,6 +978,10 @@
 	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
 		   MAC2STR(src));
 
+#ifdef CONFIG_DPP2
+	wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
+
 	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
 				   &r_bootstrap_len);
 	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
@@ -949,7 +1020,8 @@
 
 	wpa_s->dpp_gas_client = 0;
 	wpa_s->dpp_auth_ok_on_ack = 0;
-	wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
+	wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s,
+					  wpa_s->dpp_allowed_roles,
 					  wpa_s->dpp_qr_mutual,
 					  peer_bi, own_bi, freq, hdr, buf, len);
 	if (!wpa_s->dpp_auth) {
@@ -957,7 +1029,7 @@
 		return;
 	}
 	wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
-	if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
+	if (dpp_set_configurator(wpa_s->dpp_auth,
 				 wpa_s->dpp_configurator_params) < 0) {
 		dpp_auth_deinit(wpa_s->dpp_auth);
 		wpa_s->dpp_auth = NULL;
@@ -1031,8 +1103,10 @@
 	ssid->ssid_len = conf->ssid_len;
 
 	if (conf->connector) {
-		ssid->key_mgmt = WPA_KEY_MGMT_DPP;
-		ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+		if (dpp_akm_dpp(conf->akm)) {
+			ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+			ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+		}
 		ssid->dpp_connector = os_strdup(conf->connector);
 		if (!ssid->dpp_connector)
 			goto fail;
@@ -1061,7 +1135,7 @@
 
 	if (!conf->connector || dpp_akm_psk(conf->akm) ||
 	    dpp_akm_sae(conf->akm)) {
-		if (!conf->connector)
+		if (!conf->connector || !dpp_akm_dpp(conf->akm))
 			ssid->key_mgmt = 0;
 		if (dpp_akm_psk(conf->akm))
 			ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
@@ -1203,6 +1277,32 @@
 }
 
 
+static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
+				   struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+	int res;
+
+	if (!key)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+	while (key) {
+		res = dpp_configurator_from_backup(wpa_s->dpp, key);
+		if (res < 0)
+			return -1;
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+			res);
+		key = key->next;
+	}
+#endif /* CONFIG_DPP2 */
+
+	return 0;
+}
+
+
 static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
 				 enum gas_query_result result,
 				 const struct wpabuf *adv_proto,
@@ -1259,6 +1359,8 @@
 	}
 	if (auth->num_conf_obj)
 		wpas_dpp_post_process_config(wpa_s, auth);
+	if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
+		goto fail;
 
 	status = DPP_STATUS_OK;
 #ifdef CONFIG_TESTING_OPTIONS
@@ -1605,6 +1707,76 @@
 	return res;
 }
 
+
+static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (bi == wpa_s->dpp_chirp_bi)
+		wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+				  const u8 *hdr, const u8 *buf, size_t len,
+				  unsigned int freq)
+{
+	const u8 *r_bootstrap;
+	u16 r_bootstrap_len;
+	struct dpp_bootstrap_info *peer_bi;
+	struct dpp_authentication *auth;
+
+	if (!wpa_s->dpp)
+		return;
+
+	if (wpa_s->dpp_auth) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Ignore Presence Announcement during ongoing Authentication");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+		   MAC2STR(src));
+
+	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+				   &r_bootstrap_len);
+	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Responder Bootstrapping Key Hash attribute");
+		return;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+		    r_bootstrap, r_bootstrap_len);
+	peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
+	if (!peer_bi) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No matching bootstrapping information found");
+		return;
+	}
+
+	auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
+			     DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
+	if (!auth)
+		return;
+	wpas_dpp_set_testing_options(wpa_s, auth);
+	if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
+		dpp_auth_deinit(auth);
+		return;
+	}
+
+	auth->neg_freq = freq;
+
+	if (!is_zero_ether_addr(peer_bi->mac_addr))
+		os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+	wpa_s->dpp_auth = auth;
+	if (wpas_dpp_auth_init_next(wpa_s) < 0) {
+		dpp_auth_deinit(wpa_s->dpp_auth);
+		wpa_s->dpp_auth = NULL;
+	}
+}
+
 #endif /* CONFIG_DPP2 */
 
 
@@ -2069,6 +2241,7 @@
 	if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Authentication initialization failed");
+		offchannel_send_action_done(wpa_s);
 		return;
 	}
 }
@@ -2149,6 +2322,10 @@
 	case DPP_PA_CONNECTION_STATUS_RESULT:
 		wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
 		break;
+	case DPP_PA_PRESENCE_ANNOUNCEMENT:
+		wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
+						  freq);
+		break;
 #endif /* CONFIG_DPP2 */
 	default:
 		wpa_printf(MSG_DEBUG,
@@ -2271,13 +2448,13 @@
 	int ret = -1;
 	char *curve = NULL;
 
-	auth = os_zalloc(sizeof(*auth));
+	auth = dpp_alloc_auth(wpa_s->dpp, wpa_s);
 	if (!auth)
 		return -1;
 
 	curve = get_param(cmd, " curve=");
 	wpas_dpp_set_testing_options(wpa_s, auth);
-	if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
+	if (dpp_set_configurator(auth, cmd) == 0 &&
 	    dpp_configurator_own_config(auth, curve, 0) == 0)
 		ret = wpas_dpp_handle_config_obj(wpa_s, auth,
 						 &auth->conf_obj[0]);
@@ -2549,6 +2726,8 @@
 
 void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->dpp_auth || wpa_s->dpp_pkex)
+		offchannel_send_action_done(wpa_s);
 	dpp_auth_deinit(wpa_s->dpp_auth);
 	wpa_s->dpp_auth = NULL;
 	dpp_pkex_free(wpa_s->dpp_pkex);
@@ -2579,6 +2758,7 @@
 	config.cb_ctx = wpa_s;
 #ifdef CONFIG_DPP2
 	config.process_conf_obj = wpas_dpp_process_conf_obj;
+	config.remove_bi = wpas_dpp_remove_bi;
 #endif /* CONFIG_DPP2 */
 	wpa_s->dpp = dpp_global_init(&config);
 	return wpa_s->dpp ? 0 : -1;
@@ -2610,6 +2790,7 @@
 	eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
 	dpp_pfs_free(wpa_s->dpp_pfs);
 	wpa_s->dpp_pfs = NULL;
+	wpas_dpp_chirp_stop(wpa_s);
 #endif /* CONFIG_DPP2 */
 	offchannel_send_action_done(wpa_s);
 	wpas_dpp_listen_stop(wpa_s);
@@ -2622,6 +2803,7 @@
 
 
 #ifdef CONFIG_DPP2
+
 int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
 {
 	struct dpp_controller_config config;
@@ -2638,4 +2820,270 @@
 	config.configurator_params = wpa_s->dpp_configurator_params;
 	return dpp_controller_start(wpa_s->dpp, &config);
 }
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+	offchannel_send_action_done(wpa_s);
+	wpas_dpp_chirp_next(wpa_s, NULL);
+}
+
+
+static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
+				     unsigned int freq, const u8 *dst,
+				     const u8 *src, const u8 *bssid,
+				     const u8 *data, size_t data_len,
+				     enum offchannel_send_action_result result)
+{
+	if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+		wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
+			   wpa_s->dpp_chirp_freq);
+		if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
+					   wpa_s, NULL) < 0)
+			wpas_dpp_chirp_stop(wpa_s);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
+	if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
+				   wpa_s, NULL) < 0)
+		wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
+{
+	wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(broadcast), wpa_s->dpp_chirp_freq,
+		DPP_PA_PRESENCE_ANNOUNCEMENT);
+	if (offchannel_send_action(
+		    wpa_s, wpa_s->dpp_chirp_freq, broadcast,
+		    wpa_s->own_addr, broadcast,
+		    wpabuf_head(wpa_s->dpp_presence_announcement),
+		    wpabuf_len(wpa_s->dpp_presence_announcement),
+		    2000, wpas_dpp_chirp_tx_status, 0) < 0)
+		wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
+					    struct wpa_scan_results *scan_res)
+{
+	struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
+	unsigned int i;
+	struct hostapd_hw_modes *mode;
+	int c;
+	struct wpa_bss *bss;
+
+	if (!bi)
+		return;
+
+	wpa_s->dpp_chirp_scan_done = 1;
+
+	os_free(wpa_s->dpp_chirp_freqs);
+	wpa_s->dpp_chirp_freqs = NULL;
+
+	/* Channels from own bootstrapping info */
+	for (i = 0; i < bi->num_freq; i++)
+		int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]);
+
+	/* Preferred chirping channels */
+	int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+			HOSTAPD_MODE_IEEE80211A, 0);
+	if (mode) {
+		int chan44 = 0, chan149 = 0;
+
+		for (c = 0; c < mode->num_channels; c++) {
+			struct hostapd_channel_data *chan = &mode->channels[c];
+
+			if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+					  HOSTAPD_CHAN_RADAR))
+				continue;
+			if (chan->freq == 5220)
+				chan44 = 1;
+			if (chan->freq == 5745)
+				chan149 = 1;
+		}
+		if (chan149)
+			int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
+		else if (chan44)
+			int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
+	}
+
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+			HOSTAPD_MODE_IEEE80211AD, 0);
+	if (mode) {
+		for (c = 0; c < mode->num_channels; c++) {
+			struct hostapd_channel_data *chan = &mode->channels[c];
+
+			if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+					   HOSTAPD_CHAN_RADAR)) ||
+			    chan->freq != 60480)
+				continue;
+			int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
+			break;
+		}
+	}
+
+	/* Add channels from scan results for APs that advertise Configurator
+	 * Connectivity element */
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
+			int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+					     bss->freq);
+	}
+
+	if (!wpa_s->dpp_chirp_freqs ||
+	    eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
+		wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	int i;
+
+	if (wpa_s->dpp_chirp_listen)
+		wpas_dpp_listen_stop(wpa_s);
+
+	if (wpa_s->dpp_chirp_freq == 0) {
+		if (wpa_s->dpp_chirp_round % 4 == 0 &&
+		    !wpa_s->dpp_chirp_scan_done) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Update channel list for chirping");
+			wpa_s->scan_req = MANUAL_SCAN_REQ;
+			wpa_s->scan_res_handler =
+				wpas_dpp_chirp_scan_res_handler;
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+			return;
+		}
+		wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
+		wpa_s->dpp_chirp_round++;
+		wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+			   wpa_s->dpp_chirp_round);
+	} else {
+		for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
+			if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
+				break;
+		if (!wpa_s->dpp_chirp_freqs[i]) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Previous chirp freq %d not found",
+				   wpa_s->dpp_chirp_freq);
+			return;
+		}
+		i++;
+		if (wpa_s->dpp_chirp_freqs[i]) {
+			wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
+		} else {
+			wpa_s->dpp_chirp_iter--;
+			if (wpa_s->dpp_chirp_iter <= 0) {
+				wpa_printf(MSG_DEBUG,
+					   "DPP: Chirping iterations completed");
+				wpas_dpp_chirp_stop(wpa_s);
+				return;
+			}
+			wpa_s->dpp_chirp_freq = 0;
+			wpa_s->dpp_chirp_scan_done = 0;
+			if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
+						   wpa_s, NULL) < 0) {
+				wpas_dpp_chirp_stop(wpa_s);
+				return;
+			}
+			if (wpa_s->dpp_chirp_listen) {
+				wpa_printf(MSG_DEBUG,
+					   "DPP: Listen on %d MHz during chirp 30 second wait",
+					wpa_s->dpp_chirp_listen);
+				wpas_dpp_listen_start(wpa_s,
+						      wpa_s->dpp_chirp_listen);
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "DPP: Wait 30 seconds before starting the next chirping round");
+			}
+			return;
+		}
+	}
+
+	wpas_dpp_chirp_start(wpa_s);
+}
+
+
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+	const char *pos;
+	int iter = 1, listen_freq = 0;
+	struct dpp_bootstrap_info *bi;
+
+	pos = os_strstr(cmd, " own=");
+	if (!pos)
+		return -1;
+	pos += 5;
+	bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+	if (!bi) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Identified bootstrap info not found");
+		return -1;
+	}
+
+	pos = os_strstr(cmd, " iter=");
+	if (pos) {
+		iter = atoi(pos + 6);
+		if (iter <= 0)
+			return -1;
+	}
+
+	pos = os_strstr(cmd, " listen=");
+	if (pos) {
+		listen_freq = atoi(pos + 8);
+		if (iter <= 0)
+			return -1;
+	}
+
+	wpas_dpp_chirp_stop(wpa_s);
+	wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+	wpa_s->dpp_qr_mutual = 0;
+	wpa_s->dpp_chirp_bi = bi;
+	wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+	if (!wpa_s->dpp_presence_announcement)
+		return -1;
+	wpa_s->dpp_chirp_iter = iter;
+	wpa_s->dpp_chirp_round = 0;
+	wpa_s->dpp_chirp_scan_done = 0;
+	wpa_s->dpp_chirp_listen = listen_freq;
+
+	return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->dpp_presence_announcement) {
+		offchannel_send_action_done(wpa_s);
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+	}
+	wpa_s->dpp_chirp_bi = NULL;
+	wpabuf_free(wpa_s->dpp_presence_announcement);
+	wpa_s->dpp_presence_announcement = NULL;
+	if (wpa_s->dpp_chirp_listen)
+		wpas_dpp_listen_stop(wpa_s);
+	wpa_s->dpp_chirp_listen = 0;
+	wpa_s->dpp_chirp_freq = 0;
+	os_free(wpa_s->dpp_chirp_freqs);
+	wpa_s->dpp_chirp_freqs = NULL;
+	eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
+	if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
+		wpas_abort_ongoing_scan(wpa_s);
+		wpa_s->scan_res_handler = NULL;
+	}
+}
+
 #endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 607036a..2ce378d 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -1,7 +1,7 @@
 /*
  * wpa_supplicant - DPP
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,6 +14,8 @@
 
 int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
 void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);
@@ -33,5 +35,7 @@
 void wpas_dpp_connected(struct wpa_supplicant *wpa_s);
 void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
 				      enum dpp_status_error result);
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
 
 #endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index cf9972a..6a03d8e 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -124,13 +124,8 @@
 	return -1;
 }
 
-static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
-	struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->get_scan_results2)
-		return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
-	return NULL;
-}
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s);
 
 static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
 {
@@ -152,18 +147,38 @@
 				  enum wpa_alg alg, const u8 *addr,
 				  int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_flag key_flag)
 {
+	struct wpa_driver_set_key_params params;
+
+	os_memset(&params, 0, sizeof(params));
+	params.ifname = wpa_s->ifname;
+	params.alg = alg;
+	params.addr = addr;
+	params.key_idx = key_idx;
+	params.set_tx = set_tx;
+	params.seq = seq;
+	params.seq_len = seq_len;
+	params.key = key;
+	params.key_len = key_len;
+	params.key_flag = key_flag;
+
 	if (alg != WPA_ALG_NONE) {
-		if (key_idx >= 0 && key_idx <= 6)
+		/* keyidx = 1 can be either a broadcast or--with
+		 * Extended Key ID--a unicast key. Use bit 15 for
+		 * the pairwise keyidx 1 which is hopefully high enough
+		 * to not clash with future extensions.
+		 */
+		if (key_idx == 1 && (key_flag & KEY_FLAG_PAIRWISE))
+			wpa_s->keys_cleared &= ~BIT(15);
+		else if (key_idx >= 0 && key_idx <= 5)
 			wpa_s->keys_cleared &= ~BIT(key_idx);
 		else
 			wpa_s->keys_cleared = 0;
 	}
 	if (wpa_s->driver->set_key) {
-		return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
-					      alg, addr, key_idx, set_tx,
-					      seq, seq_len, key, key_len);
+		return wpa_s->driver->set_key(wpa_s->drv_priv, &params);
 	}
 	return -1;
 }
@@ -304,12 +319,12 @@
 
 static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
 				    const u8 *data, size_t data_len, int noack,
-				    unsigned int freq)
+				    unsigned int freq, unsigned int wait)
 {
 	if (wpa_s->driver->send_mlme)
 		return wpa_s->driver->send_mlme(wpa_s->drv_priv,
 						data, data_len, noack,
-						freq, NULL, 0);
+						freq, NULL, 0, 0, wait);
 	return -1;
 }
 
@@ -347,6 +362,17 @@
 	return -1;
 }
 
+static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s,
+					  const u8 *dest, u16 proto,
+					  const u8 *buf, size_t len,
+					  int no_encrypt)
+{
+	if (!wpa_s->driver->tx_control_port)
+		return -1;
+	return wpa_s->driver->tx_control_port(wpa_s->drv_priv, dest, proto,
+					      buf, len, no_encrypt);
+}
+
 static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
 					  const u8 *addr, const u8 *data,
 					  size_t data_len, int encrypt,
@@ -494,13 +520,8 @@
 	return -1;
 }
 
-static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
-				      struct wpa_signal_info *si)
-{
-	if (wpa_s->driver->signal_poll)
-		return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
-	return -1;
-}
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+			struct wpa_signal_info *si);
 
 static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
 				       struct wpa_channel_info *ci)
@@ -681,6 +702,13 @@
 					  qos_map_set_len);
 }
 
+static inline int wpa_drv_get_wowlan(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->get_wowlan)
+		return 0;
+	return wpa_s->driver->get_wowlan(wpa_s->drv_priv);
+}
+
 static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
 				 const struct wowlan_triggers *triggers)
 {
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 53d7585..2fa4968 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1390,7 +1390,7 @@
 			eapol_test.ctrl_iface = 1;
 			break;
 		case 'v':
-			printf("eapol_test v" VERSION_STR "\n");
+			printf("eapol_test v%s\n", VERSION_STR);
 			return 0;
 		case 'W':
 			wait_for_monitor++;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 4c459cf..cf56108 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -188,6 +188,16 @@
 			      drv_ssid_len) == 0)
 			return 0; /* current profile still in use */
 
+#ifdef CONFIG_OWE
+		if ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+		    wpa_s->current_bss &&
+		    (wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION) &&
+		    drv_ssid_len == wpa_s->current_bss->ssid_len &&
+		    os_memcmp(drv_ssid, wpa_s->current_bss->ssid,
+			      drv_ssid_len) == 0)
+			return 0; /* current profile still in use */
+#endif /* CONFIG_OWE */
+
 		wpa_msg(wpa_s, MSG_DEBUG,
 			"Driver-initiated BSS selection changed the SSID to %s",
 			wpa_ssid_txt(drv_ssid, drv_ssid_len));
@@ -479,6 +489,7 @@
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
 
+#ifdef CONFIG_WEP
 static int has_wep_key(struct wpa_ssid *ssid)
 {
 	int i;
@@ -490,6 +501,7 @@
 
 	return 0;
 }
+#endif /* CONFIG_WEP */
 
 
 static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
@@ -510,8 +522,10 @@
 		return 1;
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_WEP
 	if (has_wep_key(ssid))
 		privacy = 1;
+#endif /* CONFIG_WEP */
 
 #ifdef IEEE8021X_EAPOL
 	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
@@ -540,17 +554,21 @@
 	int proto_match = 0;
 	const u8 *rsn_ie, *wpa_ie;
 	int ret;
+#ifdef CONFIG_WEP
 	int wep_ok;
+#endif /* CONFIG_WEP */
 
 	ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
 	if (ret >= 0)
 		return ret;
 
+#ifdef CONFIG_WEP
 	/* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
 	wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
 		(((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
 		  ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
 		 (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+#endif /* CONFIG_WEP */
 
 	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 	while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
@@ -567,6 +585,7 @@
 		if (!ie.has_group)
 			ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
 
+#ifdef CONFIG_WEP
 		if (wep_ok &&
 		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
 		{
@@ -575,6 +594,7 @@
 					"   selected based on TSN in RSN IE");
 			return 1;
 		}
+#endif /* CONFIG_WEP */
 
 		if (!(ie.proto & ssid->proto) &&
 		    !(ssid->proto & WPA_PROTO_OSEN)) {
@@ -655,6 +675,7 @@
 			break;
 		}
 
+#ifdef CONFIG_WEP
 		if (wep_ok &&
 		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
 		{
@@ -663,6 +684,7 @@
 					"   selected based on TSN in WPA IE");
 			return 1;
 		}
+#endif /* CONFIG_WEP */
 
 		if (!(ie.proto & ssid->proto)) {
 			if (debug_print)
@@ -772,8 +794,8 @@
 }
 
 
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
-		      int debug_print)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+		      struct wpa_bss *bss, int debug_print)
 {
 	const struct hostapd_hw_modes *mode = NULL, *modes;
 	const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -853,7 +875,9 @@
 #ifdef CONFIG_SAE
 			if (flagged && ((rate_ie[j] & 0x7f) ==
 					BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
-				if (wpa_s->conf->sae_pwe == 0) {
+				if (wpa_s->conf->sae_pwe == 0 &&
+				    !ssid->sae_password_id &&
+				    wpa_key_mgmt_sae(ssid->key_mgmt)) {
 					if (debug_print)
 						wpa_dbg(wpa_s, MSG_DEBUG,
 							"   SAE H2E disabled");
@@ -971,6 +995,24 @@
 	*ret_ssid = pos;
 	*ret_ssid_len = ssid_len;
 
+	if (!(bss->flags & WPA_BSS_OWE_TRANSITION)) {
+		struct wpa_ssid *ssid;
+
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+			if (wpas_network_disabled(wpa_s, ssid))
+				continue;
+			if (ssid->ssid_len == ssid_len &&
+			    os_memcmp(ssid->ssid, pos, ssid_len) == 0) {
+				/* OWE BSS in transition mode for a currently
+				 * enabled OWE network. */
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"OWE: transition mode OWE SSID for active OWE profile");
+				bss->flags |= WPA_BSS_OWE_TRANSITION;
+				break;
+			}
+		}
+	}
+
 	if (bss->ssid_len > 0)
 		return;
 
@@ -1011,10 +1053,33 @@
 		wpa_ssid_txt(pos, ssid_len));
 	os_memcpy(bss->ssid, pos, ssid_len);
 	bss->ssid_len = ssid_len;
+	bss->flags |= WPA_BSS_OWE_TRANSITION;
 #endif /* CONFIG_OWE */
 }
 
 
+static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
+{
+	int i, j;
+
+	if (!wpa_s->hw.modes || !wpa_s->hw.num_modes)
+		return 0;
+
+	for (j = 0; j < wpa_s->hw.num_modes; j++) {
+		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[j];
+
+		for (i = 0; i < mode->num_channels; i++) {
+			struct hostapd_channel_data *chan = &mode->channels[i];
+
+			if (chan->freq == freq)
+				return !!(chan->flag & HOSTAPD_CHAN_DISABLED);
+		}
+	}
+
+	return 1;
+}
+
+
 struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 				     int i, struct wpa_bss *bss,
 				     struct wpa_ssid *group,
@@ -1106,6 +1171,12 @@
 		return NULL;
 	}
 
+	if (disabled_freq(wpa_s, bss->freq)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - channel disabled");
+		return NULL;
+	}
+
 	wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
 
 	for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
@@ -1206,6 +1277,7 @@
 			continue;
 		}
 
+#ifdef CONFIG_WEP
 		if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
 		    has_wep_key(ssid)) {
 			if (debug_print)
@@ -1213,6 +1285,7 @@
 					"   skip - ignore WPA/WPA2 AP for WEP network block");
 			continue;
 		}
+#endif /* CONFIG_WEP */
 
 		if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
 		    !rsn_osen) {
@@ -1262,7 +1335,7 @@
 		}
 #endif /* CONFIG_MESH */
 
-		if (!rate_match(wpa_s, bss, debug_print)) {
+		if (!rate_match(wpa_s, ssid, bss, debug_print)) {
 			if (debug_print)
 				wpa_dbg(wpa_s, MSG_DEBUG,
 					"   skip - rate sets do not match");
@@ -1270,7 +1343,8 @@
 		}
 
 #ifdef CONFIG_SAE
-		if (wpa_s->conf->sae_pwe == 1 &&
+		if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+		    wpa_s->conf->sae_pwe != 3 &&
 		    wpa_key_mgmt_sae(ssid->key_mgmt) &&
 		    (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
 		     ie[1] < 1 ||
@@ -1446,8 +1520,9 @@
 		wpa_s->owe_transition_select = 0;
 		if (!*selected_ssid)
 			continue;
-		wpa_dbg(wpa_s, MSG_DEBUG, "   selected BSS " MACSTR
+		wpa_dbg(wpa_s, MSG_DEBUG, "   selected %sBSS " MACSTR
 			" ssid='%s'",
+			bss == wpa_s->current_bss ? "current ": "",
 			MAC2STR(bss->bssid),
 			wpa_ssid_txt(bss->ssid, bss->ssid_len));
 		return bss;
@@ -1461,7 +1536,7 @@
 					     struct wpa_ssid **selected_ssid)
 {
 	struct wpa_bss *selected = NULL;
-	int prio;
+	size_t prio;
 	struct wpa_ssid *next_ssid = NULL;
 	struct wpa_ssid *ssid;
 
@@ -1616,7 +1691,7 @@
 static struct wpa_ssid *
 wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
 {
-	int prio;
+	size_t prio;
 	struct wpa_ssid *ssid;
 
 	for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
@@ -1672,6 +1747,31 @@
 }
 
 
+#ifndef CONFIG_NO_ROAMING
+
+static int wpas_get_snr_signal_info(u32 frequency, int avg_signal, int noise)
+{
+	if (noise == WPA_INVALID_NOISE)
+		noise = IS_5GHZ(frequency) ? DEFAULT_NOISE_FLOOR_5GHZ :
+			DEFAULT_NOISE_FLOOR_2GHZ;
+	return avg_signal - noise;
+}
+
+
+static unsigned int
+wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s,
+				     const struct wpa_bss *bss, int snr)
+{
+	int rate = wpa_bss_get_max_rate(bss);
+	const u8 *ies = (const void *) (bss + 1);
+	size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+
+	return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
+}
+
+#endif /* CONFIG_NO_ROAMING */
+
+
 static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
 				       struct wpa_bss *selected,
 				       struct wpa_ssid *ssid)
@@ -1680,7 +1780,10 @@
 #ifndef CONFIG_NO_ROAMING
 	int min_diff, diff;
 	int to_5ghz;
-	int cur_est, sel_est;
+	int cur_level;
+	unsigned int cur_est, sel_est;
+	struct wpa_signal_info si;
+	int cur_snr = 0;
 #endif /* CONFIG_NO_ROAMING */
 
 	if (wpa_s->reassociate)
@@ -1731,7 +1834,41 @@
 		return 1;
 	}
 
-	if (selected->est_throughput > current_bss->est_throughput + 5000) {
+	cur_level = current_bss->level;
+	cur_est = current_bss->est_throughput;
+	sel_est = selected->est_throughput;
+
+	/*
+	 * Try to poll the signal from the driver since this will allow to get
+	 * more accurate values. In some cases, there can be big differences
+	 * between the RSSI of the Probe Response frames of the AP we are
+	 * associated with and the Beacon frames we hear from the same AP after
+	 * association. This can happen, e.g., when there are two antennas that
+	 * hear the AP very differently. If the driver chooses to hear the
+	 * Probe Response frames during the scan on the "bad" antenna because
+	 * it wants to save power, but knows to choose the other antenna after
+	 * association, we will hear our AP with a low RSSI as part of the
+	 * scan even when we can hear it decently on the other antenna. To cope
+	 * with this, ask the driver to teach us how it hears the AP. Also, the
+	 * scan results may be a bit old, since we can very quickly get fresh
+	 * information about our currently associated AP.
+	 */
+	if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
+	    (si.avg_beacon_signal || si.avg_signal)) {
+		cur_level = si.avg_beacon_signal ? si.avg_beacon_signal :
+			si.avg_signal;
+		cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level,
+						   si.current_noise);
+
+		cur_est = wpas_get_est_throughput_from_bss_snr(wpa_s,
+							       current_bss,
+							       cur_snr);
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Using signal poll values for the current BSS: level=%d snr=%d est_throughput=%u",
+			cur_level, cur_snr, cur_est);
+	}
+
+	if (sel_est > cur_est + 5000) {
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"Allow reassociation - selected BSS has better estimated throughput");
 		return 1;
@@ -1739,59 +1876,59 @@
 
 	to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
 
-	if (current_bss->level < 0 &&
-	    current_bss->level > selected->level + to_5ghz * 2) {
+	if (cur_level < 0 && cur_level > selected->level + to_5ghz * 2 &&
+	    sel_est < cur_est * 1.2) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
 			"signal level");
 		return 0;
 	}
 
-	if (current_bss->est_throughput > selected->est_throughput + 5000) {
+	if (cur_est > sel_est + 5000) {
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"Skip roam - Current BSS has better estimated throughput");
 		return 0;
 	}
 
-	cur_est = current_bss->est_throughput;
-	sel_est = selected->est_throughput;
-	min_diff = 2;
-	if (current_bss->level < 0) {
-		if (current_bss->level < -85)
-			min_diff = 1;
-		else if (current_bss->level < -80)
-			min_diff = 2;
-		else if (current_bss->level < -75)
-			min_diff = 3;
-		else if (current_bss->level < -70)
-			min_diff = 4;
-		else
-			min_diff = 5;
-		if (cur_est > sel_est * 1.5)
-			min_diff += 10;
-		else if (cur_est > sel_est * 1.2)
-			min_diff += 5;
-		else if (cur_est > sel_est * 1.1)
-			min_diff += 2;
-		else if (cur_est > sel_est)
-			min_diff++;
+	if (cur_snr > GREAT_SNR) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Skip roam - Current BSS has good SNR (%u > %u)",
+			cur_snr, GREAT_SNR);
+		return 0;
 	}
-	if (to_5ghz) {
-		int reduce = 2;
 
-		/* Make it easier to move to 5 GHz band */
-		if (sel_est > cur_est * 1.5)
-			reduce = 5;
-		else if (sel_est > cur_est * 1.2)
-			reduce = 4;
-		else if (sel_est > cur_est * 1.1)
-			reduce = 3;
+	if (cur_level < -85) /* ..-86 dBm */
+		min_diff = 1;
+	else if (cur_level < -80) /* -85..-81 dBm */
+		min_diff = 2;
+	else if (cur_level < -75) /* -80..-76 dBm */
+		min_diff = 3;
+	else if (cur_level < -70) /* -75..-71 dBm */
+		min_diff = 4;
+	else if (cur_level < 0) /* -70..-1 dBm */
+		min_diff = 5;
+	else /* unspecified units (not in dBm) */
+		min_diff = 2;
 
-		if (min_diff > reduce)
-			min_diff -= reduce;
-		else
-			min_diff = 0;
-	}
-	diff = abs(current_bss->level - selected->level);
+	if (cur_est > sel_est * 1.5)
+		min_diff += 10;
+	else if (cur_est > sel_est * 1.2)
+		min_diff += 5;
+	else if (cur_est > sel_est * 1.1)
+		min_diff += 2;
+	else if (cur_est > sel_est)
+		min_diff++;
+	else if (sel_est > cur_est * 1.5)
+		min_diff -= 10;
+	else if (sel_est > cur_est * 1.2)
+		min_diff -= 5;
+	else if (sel_est > cur_est * 1.1)
+		min_diff -= 2;
+	else if (sel_est > cur_est)
+		min_diff--;
+
+	if (to_5ghz)
+		min_diff -= 2;
+	diff = selected->level - cur_level;
 	if (diff < min_diff) {
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"Skip roam - too small difference in signal level (%d < %d)",
@@ -1887,15 +2024,6 @@
 		goto scan_work_done;
 	}
 
-	if (ap) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface->scan_cb)
-			wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
-#endif /* CONFIG_AP */
-		goto scan_work_done;
-	}
-
 	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
 		wpa_s->own_scan_running,
 		data ? data->scan_info.external_scan : 0);
@@ -1912,6 +2040,15 @@
 
 	wpas_notify_scan_done(wpa_s, 1);
 
+	if (ap) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface->scan_cb)
+			wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
+#endif /* CONFIG_AP */
+		goto scan_work_done;
+	}
+
 	if (data && data->scan_info.external_scan) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
 		wpa_scan_results_free(scan_res);
@@ -2194,7 +2331,8 @@
 		return -1;
 
 	os_get_reltime(&now);
-	if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
+	if (os_reltime_expired(&now, &wpa_s->last_scan,
+			       SCAN_RES_VALID_FOR_CONNECT)) {
 		wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
 		return -1;
 	}
@@ -2327,28 +2465,41 @@
 	const u8 *map_sub_elem, *pos;
 	size_t len;
 
-	if (!wpa_s->current_ssid ||
-	    !wpa_s->current_ssid->multi_ap_backhaul_sta ||
-	    !ies ||
-	    ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
-		return;
+	wpa_s->multi_ap_ie = 0;
 
-	if (!elems.multi_ap || elems.multi_ap_len < 7) {
-		wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
-		goto fail;
-	}
+	if (!ies ||
+	    ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed ||
+	    !elems.multi_ap || elems.multi_ap_len < 7)
+		return;
 
 	pos = elems.multi_ap + 4;
 	len = elems.multi_ap_len - 4;
 
 	map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
-	if (!map_sub_elem || map_sub_elem[1] < 1) {
-		wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+	if (!map_sub_elem || map_sub_elem[1] < 1)
+		return;
+
+	wpa_s->multi_ap_backhaul = !!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS);
+	wpa_s->multi_ap_fronthaul = !!(map_sub_elem[2] &
+				       MULTI_AP_FRONTHAUL_BSS);
+	wpa_s->multi_ap_ie = 1;
+}
+
+
+static void multi_ap_set_4addr_mode(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->current_ssid ||
+	    !wpa_s->current_ssid->multi_ap_backhaul_sta)
+		return;
+
+	if (!wpa_s->multi_ap_ie) {
+		wpa_printf(MSG_INFO,
+			   "AP does not include valid Multi-AP element");
 		goto fail;
 	}
 
-	if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
-		if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+	if (!wpa_s->multi_ap_backhaul) {
+		if (wpa_s->multi_ap_fronthaul &&
 		    wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
 			wpa_printf(MSG_INFO,
 				   "WPS active, accepting fronthaul-only BSS");
@@ -2472,8 +2623,14 @@
 			wpa_s->connection_set = 1;
 			wpa_s->connection_ht = req_elems.ht_capabilities &&
 				resp_elems.ht_capabilities;
+			/* Do not include subset of VHT on 2.4 GHz vendor
+			 * extension in consideration for reporting VHT
+			 * association. */
 			wpa_s->connection_vht = req_elems.vht_capabilities &&
-				resp_elems.vht_capabilities;
+				resp_elems.vht_capabilities &&
+				(!data->assoc_info.freq ||
+				 wpas_freq_to_band(data->assoc_info.freq) !=
+				 BAND_2_4_GHZ);
 			wpa_s->connection_he = req_elems.he_capabilities &&
 				resp_elems.he_capabilities;
 
@@ -2818,6 +2975,7 @@
 #endif /* CONFIG_AP */
 
 	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+	wpa_s->own_reconnect_req = 0;
 
 	ft_completed = wpa_ft_is_completed(wpa_s->wpa);
 	if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
@@ -2867,6 +3025,8 @@
 		}
 	}
 
+	multi_ap_set_4addr_mode(wpa_s);
+
 	if (wpa_s->conf->ap_scan == 1 &&
 	    wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
 		if (wpa_supplicant_assoc_update_ie(wpa_s) < 0 && new_bss)
@@ -2971,6 +3131,13 @@
 	wpa_s->last_eapol_matches_bssid = 0;
 
 #ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->rsne_override_eapol) {
+		wpa_printf(MSG_DEBUG,
+			   "TESTING: RSNE EAPOL-Key msg 2/4 override");
+		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa,
+					wpabuf_head(wpa_s->rsne_override_eapol),
+					wpabuf_len(wpa_s->rsne_override_eapol));
+	}
 	if (wpa_s->rsnxe_override_eapol) {
 		wpa_printf(MSG_DEBUG,
 			   "TESTING: RSNXE EAPOL-Key msg 2/4 override");
@@ -2999,6 +3166,7 @@
 		wpa_s->pending_eapol_rx = NULL;
 	}
 
+#ifdef CONFIG_WEP
 	if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
 	     wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
 	    wpa_s->current_ssid &&
@@ -3006,6 +3174,7 @@
 		/* Set static WEP keys again */
 		wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
 	}
+#endif /* CONFIG_WEP */
 
 #ifdef CONFIG_IBSS_RSN
 	if (wpa_s->current_ssid &&
@@ -3051,6 +3220,10 @@
 #ifdef CONFIG_MBO
 	wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid);
 #endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP2
+	wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
 }
 
 
@@ -3178,21 +3351,25 @@
 		if (wpa_s->wpa_state == WPA_COMPLETED &&
 		    wpa_s->current_ssid &&
 		    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
-		    !locally_generated &&
-		    disconnect_reason_recoverable(reason_code)) {
+		    (wpa_s->own_reconnect_req ||
+		     (!locally_generated &&
+		      disconnect_reason_recoverable(reason_code)))) {
 			/*
 			 * It looks like the AP has dropped association with
-			 * us, but could allow us to get back in. Try to
-			 * reconnect to the same BSS without full scan to save
-			 * time for some common cases.
+			 * us, but could allow us to get back in. This is also
+			 * triggered for cases where local reconnection request
+			 * is used to force reassociation with the same BSS.
+			 * Try to reconnect to the same BSS without a full scan
+			 * to save time for some common cases.
 			 */
 			fast_reconnect = wpa_s->current_bss;
 			fast_reconnect_ssid = wpa_s->current_ssid;
-		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING) {
 			wpa_supplicant_req_scan(wpa_s, 0, 100000);
-		else
+		} else {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
 				"immediate scan");
+		}
 	} else {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
 			"try to re-connect");
@@ -4216,6 +4393,39 @@
 	}
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+	/* Try to follow AP's PFS policy. WLAN_STATUS_ASSOC_DENIED_UNSPEC is
+	 * the status code defined in the DPP R2 tech spec.
+	 * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an
+	 * interoperability workaround with older hostapd implementation. */
+	if (wpa_s->current_ssid &&
+	    wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+	    wpa_s->current_ssid->dpp_pfs == 0 &&
+	    (data->assoc_reject.status_code ==
+	     WLAN_STATUS_ASSOC_DENIED_UNSPEC ||
+	     data->assoc_reject.status_code == WLAN_STATUS_AKMP_NOT_VALID)) {
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+		struct wpa_bss *bss = wpa_s->current_bss;
+
+		wpa_s->current_ssid->dpp_pfs_fallback ^= 1;
+		if (!bss)
+			bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+		if (!bss || wpa_s->dpp_pfs_fallback) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Updated PFS policy for next try");
+			wpas_connection_failed(wpa_s, bssid);
+			wpa_supplicant_mark_disassoc(wpa_s);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "DPP: Try again with updated PFS policy");
+		wpa_s->dpp_pfs_fallback = 1;
+		wpas_connect_work_done(wpa_s);
+		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_connect(wpa_s, bss, ssid);
+		return;
+	}
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_MBO
 	if (data->assoc_reject.status_code ==
 	    WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
@@ -4282,11 +4492,44 @@
 }
 
 
+static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s,
+				     struct unprot_beacon *data)
+{
+	struct wpabuf *buf;
+	int res;
+
+	if (!data || wpa_s->wpa_state != WPA_COMPLETED ||
+	    os_memcmp(data->sa, wpa_s->bssid, ETH_ALEN) != 0)
+		return;
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_UNPROT_BEACON MACSTR,
+		MAC2STR(data->sa));
+
+	buf = wpabuf_alloc(4);
+	if (!buf)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+	wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+	wpabuf_put_u8(buf, 1); /* Dialog Token */
+	wpabuf_put_u8(buf, WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE);
+
+	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				  wpa_s->own_addr, wpa_s->bssid,
+				  wpabuf_head(buf), wpabuf_len(buf), 0);
+	if (res < 0)
+		wpa_printf(MSG_DEBUG,
+			   "Failed to send WNM-Notification Request frame");
+
+	wpabuf_free(buf);
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	int resched;
+	struct os_reltime age, clear_at;
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	int level = MSG_DEBUG;
 #endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -4589,6 +4832,20 @@
 		wpa_s->assoc_freq = data->ch_switch.freq;
 		wpa_s->current_ssid->frequency = data->ch_switch.freq;
 
+#ifdef CONFIG_SME
+		switch (data->ch_switch.ch_offset) {
+		case 1:
+			wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+			break;
+		case -1:
+			wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+			break;
+		default:
+			wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
+			break;
+		}
+#endif /* CONFIG_SME */
+
 #ifdef CONFIG_AP
 		if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
 		    wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
@@ -4811,6 +5068,8 @@
 	case EVENT_INTERFACE_ENABLED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+			eloop_cancel_timeout(wpas_clear_disabled_interface,
+					     wpa_s, NULL);
 			wpa_supplicant_update_mac_addr(wpa_s);
 			wpa_supplicant_set_default_scan_ies(wpa_s);
 			if (wpa_s->p2p_mgmt) {
@@ -4879,8 +5138,20 @@
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
 		}
 		wpa_supplicant_mark_disassoc(wpa_s);
-		if (!wpa_s->conf->bss_no_flush_when_down)
-			wpa_bss_flush(wpa_s);
+		os_reltime_age(&wpa_s->last_scan, &age);
+		if (age.sec >= SCAN_RES_VALID_FOR_CONNECT) {
+			clear_at.sec = SCAN_RES_VALID_FOR_CONNECT;
+			clear_at.usec = 0;
+		} else {
+			struct os_reltime tmp;
+
+			tmp.sec = SCAN_RES_VALID_FOR_CONNECT;
+			tmp.usec = 0;
+			os_reltime_sub(&tmp, &age, &clear_at);
+		}
+		eloop_register_timeout(clear_at.sec, clear_at.usec,
+				       wpas_clear_disabled_interface,
+				       wpa_s, NULL);
 		radio_remove_works(wpa_s, NULL, 0);
 
 		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -5057,6 +5328,9 @@
 						 data->sta_opmode.rx_nss);
 #endif /* CONFIG_AP */
 		break;
+	case EVENT_UNPROT_BEACON:
+		wpas_event_unprot_beacon(wpa_s, &data->unprot_beacon);
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
new file mode 100755
index 0000000..f49da34
--- /dev/null
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -0,0 +1,692 @@
+#!/usr/bin/python3
+#
+# Example nfcpy to wpa_supplicant wrapper for DPP NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2019-2020, The Linux Foundation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import threading
+import argparse
+
+import nfc
+import ndef
+
+import logging
+
+scriptsdir = os.path.dirname(os.path.realpath("dpp-nfc.py"))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+init_on_touch = False
+in_raw_mode = False
+prev_tcgetattr = 0
+no_input = False
+srv = None
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+
+def summary(txt):
+    print(txt)
+    if summary_file:
+        with open(summary_file, 'a') as f:
+            f.write(txt + "\n")
+
+def success_report(txt):
+    summary(txt)
+    if success_file:
+        with open(success_file, 'a') as f:
+            f.write(txt + "\n")
+
+def wpas_connect():
+    ifaces = []
+    if os.path.isdir(wpas_ctrl):
+        try:
+            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+        except OSError as error:
+            print("Could not find wpa_supplicant: ", error)
+            return None
+
+    if len(ifaces) < 1:
+        print("No wpa_supplicant control interface found")
+        return None
+
+    for ctrl in ifaces:
+        if ifname:
+            if ifname not in ctrl:
+                continue
+        try:
+            print("Trying to use control interface " + ctrl)
+            wpas = wpaspy.Ctrl(ctrl)
+            return wpas
+        except Exception as e:
+            pass
+    return None
+
+def dpp_nfc_uri_process(uri):
+    wpas = wpas_connect()
+    if wpas is None:
+        return False
+    peer_id = wpas.request("DPP_NFC_URI " + uri)
+    if "FAIL" in peer_id:
+        print("Could not parse DPP URI from NFC URI record")
+        return False
+    peer_id = int(peer_id)
+    print("peer_id=%d" % peer_id)
+    cmd = "DPP_AUTH_INIT peer=%d" % peer_id
+    res = wpas.request(cmd)
+    if "OK" not in res:
+        print("Failed to initiate DPP Authentication")
+        return False
+    print("DPP Authentication initiated")
+    return True
+
+def dpp_hs_tag_read(record):
+    wpas = wpas_connect()
+    if wpas is None:
+        return False
+    print(record)
+    if len(record.data) < 5:
+        print("Too short DPP HS")
+        return False
+    if record.data[0] != 0:
+        print("Unexpected URI Identifier Code")
+        return False
+    uribuf = record.data[1:]
+    try:
+        uri = uribuf.decode()
+    except:
+        print("Invalid URI payload")
+        return False
+    print("URI: " + uri)
+    if not uri.startswith("DPP:"):
+        print("Not a DPP URI")
+        return False
+    return dpp_nfc_uri_process(uri)
+
+def get_status(wpas, extra=None):
+    if extra:
+        extra = "-" + extra
+    else:
+        extra = ""
+    res = wpas.request("STATUS" + extra)
+    lines = res.splitlines()
+    vals = dict()
+    for l in lines:
+        try:
+            [name, value] = l.split('=', 1)
+        except ValueError:
+            logger.info("Ignore unexpected status line: " + l)
+            continue
+        vals[name] = value
+    return vals
+
+def get_status_field(wpas, field, extra=None):
+    vals = get_status(wpas, extra)
+    if field in vals:
+        return vals[field]
+    return None
+
+def own_addr(wpas):
+    return get_status_field(wpas, "address")
+
+def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
+                      curve=None, key=None):
+    cmd = "DPP_BOOTSTRAP_GEN type=" + type
+    if chan:
+        cmd += " chan=" + chan
+    if mac:
+        if mac is True:
+            mac = own_addr(wpas)
+        cmd += " mac=" + mac.replace(':', '')
+    if info:
+        cmd += " info=" + info
+    if curve:
+        cmd += " curve=" + curve
+    if key:
+        cmd += " key=" + key
+    res = wpas.request(cmd)
+    if "FAIL" in res:
+        raise Exception("Failed to generate bootstrapping info")
+    return int(res)
+
+def wpas_get_nfc_uri(start_listen=True):
+    wpas = wpas_connect()
+    if wpas is None:
+        return None
+    global own_id, chanlist
+    own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chanlist, mac=True)
+    res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+    if "FAIL" in res:
+        return None
+    if start_listen:
+        wpas.request("DPP_LISTEN 2412 netrole=configurator")
+    return res
+
+def wpas_report_handover_req(uri):
+    wpas = wpas_connect()
+    if wpas is None:
+        return None
+    global own_id
+    cmd = "DPP_NFC_HANDOVER_REQ own=%d uri=%s" % (own_id, uri)
+    return wpas.request(cmd)
+
+def wpas_report_handover_sel(uri):
+    wpas = wpas_connect()
+    if wpas is None:
+        return None
+    global own_id
+    cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
+    return wpas.request(cmd)
+
+def dpp_handover_client(llc):
+    uri = wpas_get_nfc_uri(start_listen=False)
+    uri = ndef.UriRecord(uri)
+    print("NFC URI record for DPP: " + str(uri))
+    carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+    hr = ndef.HandoverRequestRecord(version="1.4", crn=os.urandom(2))
+    hr.add_alternative_carrier('active', carrier.name)
+    message = [hr, carrier]
+    print("NFC Handover Request message for DPP: " + str(message))
+
+    client = nfc.handover.HandoverClient(llc)
+    try:
+        summary("Trying to initiate NFC connection handover")
+        client.connect()
+        summary("Connected for handover")
+    except nfc.llcp.ConnectRefused:
+        summary("Handover connection refused")
+        client.close()
+        return
+    except Exception as e:
+        summary("Other exception: " + str(e))
+        client.close()
+        return
+
+    summary("Sending handover request")
+
+    if not client.send_records(message):
+        summary("Failed to send handover request")
+        client.close()
+        return
+
+    summary("Receiving handover response")
+    message = client.recv_records(timeout=3.0)
+    if message is None:
+        summary("No response received")
+        client.close()
+        return
+    print("Received message: " + str(message))
+    if len(message) < 1 or \
+       not isinstance(message[0], ndef.HandoverSelectRecord):
+        summary("Response was not Hs - received: " + message.type)
+        client.close()
+        return
+
+    print("Received message")
+    print("alternative carriers: " + str(message[0].alternative_carriers))
+
+    dpp_found = False
+    for carrier in message:
+        if isinstance(carrier, ndef.HandoverSelectRecord):
+            continue
+        print("Remote carrier type: " + carrier.type)
+        if carrier.type == "application/vnd.wfa.dpp":
+            if len(carrier.data) == 0 or carrier.data[0] != 0:
+                print("URI Identifier Code 'None' not seen")
+                continue
+            print("DPP carrier type match - send to wpa_supplicant")
+            dpp_found = True
+            uri = carrier.data[1:].decode("utf-8")
+            print("DPP URI: " + uri)
+            res = wpas_report_handover_sel(uri)
+            if res is None or "FAIL" in res:
+                summary("DPP handover report rejected")
+                break
+
+            success_report("DPP handover reported successfully (initiator)")
+            print("peer_id=" + res)
+            peer_id = int(res)
+            # TODO: Single Configurator instance
+            wpas = wpas_connect()
+            if wpas is None:
+                break
+            res = wpas.request("DPP_CONFIGURATOR_ADD")
+            if "FAIL" in res:
+                print("Failed to initiate Configurator")
+                break
+            conf_id = int(res)
+            global own_id
+            print("Initiate DPP authentication")
+            cmd = "DPP_AUTH_INIT peer=%d own=%d conf=sta-dpp configurator=%d" % (peer_id, own_id, conf_id)
+            res = wpas.request(cmd)
+            if "FAIL" in res:
+                print("Failed to initiate DPP authentication")
+            break
+
+    if not dpp_found:
+        print("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
+        client.close()
+        print("Returning from dpp_handover_client")
+        return
+
+    print("Remove peer")
+    client.close()
+    print("Done with handover")
+    global only_one
+    if only_one:
+        print("only_one -> stop loop")
+        global continue_loop
+        continue_loop = False
+
+    global no_wait
+    if no_wait:
+        print("Trying to exit..")
+        global terminate_now
+        terminate_now = True
+
+    print("Returning from dpp_handover_client")
+
+class HandoverServer(nfc.handover.HandoverServer):
+    def __init__(self, llc):
+        super(HandoverServer, self).__init__(llc)
+        self.sent_carrier = None
+        self.ho_server_processing = False
+        self.success = False
+        self.try_own = False
+
+    def process_handover_request_message(self, records):
+        self.ho_server_processing = True
+        clear_raw_mode()
+        print("\nHandoverServer - request received: " + str(records))
+
+        carrier = None
+        hs = ndef.HandoverSelectRecord('1.4')
+        sel = [hs]
+
+        found = False
+
+        for carrier in records:
+            if isinstance(carrier, ndef.HandoverRequestRecord):
+                continue
+            print("Remote carrier type: " + carrier.type)
+            if carrier.type == "application/vnd.wfa.dpp":
+                print("DPP carrier type match - add DPP carrier record")
+                if len(carrier.data) == 0 or carrier.data[0] != 0:
+                    print("URI Identifier Code 'None' not seen")
+                    continue
+                uri = carrier.data[1:].decode("utf-8")
+                print("Received DPP URI: " + uri)
+
+                data = wpas_get_nfc_uri(start_listen=False)
+                print("Own URI (pre-processing): %s" % data)
+
+                res = wpas_report_handover_req(uri)
+                if res is None or "FAIL" in res:
+                    print("DPP handover request processing failed")
+                    continue
+
+                found = True
+                self.received_carrier = carrier
+
+                wpas = wpas_connect()
+                if wpas is None:
+                    continue
+                global own_id
+                data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+                if "FAIL" in data:
+                    continue
+                print("Own URI (post-processing): %s" % data)
+                uri = ndef.UriRecord(data)
+                print("Own bootstrapping NFC URI record: " + str(uri))
+
+                info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
+                freq = None
+                for line in info.splitlines():
+                    if line.startswith("use_freq="):
+                        freq = int(line.split('=')[1])
+                if freq is None:
+                    print("No channel negotiated over NFC - use channel 1")
+                    freq = 2412
+                res = wpas.request("DPP_LISTEN %d" % freq)
+                if "OK" not in res:
+                    print("Failed to start DPP listen")
+                    break
+
+                carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+                print("Own DPP carrier record: " + str(carrier))
+                hs.add_alternative_carrier('active', carrier.name)
+                sel = [hs, carrier]
+                break
+
+        summary("Sending handover select: " + str(sel))
+        if found:
+            self.success = True
+        else:
+            self.try_own = True
+        return sel
+
+def clear_raw_mode():
+    import sys, tty, termios
+    global prev_tcgetattr, in_raw_mode
+    if not in_raw_mode:
+        return
+    fd = sys.stdin.fileno()
+    termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+    in_raw_mode = False
+
+def getch():
+    import sys, tty, termios, select
+    global prev_tcgetattr, in_raw_mode
+    fd = sys.stdin.fileno()
+    prev_tcgetattr = termios.tcgetattr(fd)
+    ch = None
+    try:
+        tty.setraw(fd)
+        in_raw_mode = True
+        [i, o, e] = select.select([fd], [], [], 0.05)
+        if i:
+            ch = sys.stdin.read(1)
+    finally:
+        termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+        in_raw_mode = False
+    return ch
+
+def dpp_tag_read(tag):
+    success = False
+    for record in tag.ndef.records:
+        print(record)
+        print("record type " + record.type)
+        if record.type == "application/vnd.wfa.dpp":
+            summary("DPP HS tag - send to wpa_supplicant")
+            success = dpp_hs_tag_read(record)
+            break
+        if isinstance(record, ndef.UriRecord):
+            print("URI record: uri=" + record.uri)
+            print("URI record: iri=" + record.iri)
+            if record.iri.startswith("DPP:"):
+                print("DPP URI")
+                if not dpp_nfc_uri_process(record.iri):
+                    break
+                success = True
+            else:
+                print("Ignore unknown URI")
+            break
+
+    if success:
+        success_report("Tag read succeeded")
+
+    return success
+
+def rdwr_connected_write_tag(tag):
+    summary("Tag found - writing - " + str(tag))
+    if not tag.ndef.is_writeable:
+        print("Not a writable tag")
+        return
+    global dpp_tag_data
+    if tag.ndef.capacity < len(dpp_tag_data):
+        print("Not enough room for the message")
+        return
+    tag.ndef.records = dpp_tag_data
+    success_report("Tag write succeeded")
+    print("Done - remove tag")
+    global only_one
+    if only_one:
+        global continue_loop
+        continue_loop = False
+    global dpp_sel_wait_remove
+    return dpp_sel_wait_remove
+
+def write_nfc_uri(clf, wait_remove=True):
+    print("Write NFC URI record")
+    data = wpas_get_nfc_uri()
+    if data is None:
+        summary("Could not get NFC URI from wpa_supplicant")
+        return
+
+    global dpp_sel_wait_remove
+    dpp_sel_wait_remove = wait_remove
+    print("URI: %s" % data)
+    uri = ndef.UriRecord(data)
+    print(uri)
+
+    print("Touch an NFC tag")
+    global dpp_tag_data
+    dpp_tag_data = [uri]
+    clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def write_nfc_hs(clf, wait_remove=True):
+    print("Write NFC Handover Select record on a tag")
+    data = wpas_get_nfc_uri()
+    if data is None:
+        summary("Could not get NFC URI from wpa_supplicant")
+        return
+
+    global dpp_sel_wait_remove
+    dpp_sel_wait_remove = wait_remove
+    print("URI: %s" % data)
+    uri = ndef.UriRecord(data)
+    print(uri)
+    carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+    hs = ndef.HandoverSelectRecord('1.4')
+    hs.add_alternative_carrier('active', carrier.name)
+    print(hs)
+    print(carrier)
+
+    print("Touch an NFC tag")
+    global dpp_tag_data
+    dpp_tag_data = [hs, carrier]
+    print(dpp_tag_data)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def rdwr_connected(tag):
+    global only_one, no_wait
+    summary("Tag connected: " + str(tag))
+
+    if tag.ndef:
+        print("NDEF tag: " + tag.type)
+        print(tag.ndef.records)
+        success = dpp_tag_read(tag)
+        if only_one and success:
+            global continue_loop
+            continue_loop = False
+    else:
+        summary("Not an NDEF tag - remove tag")
+        return True
+
+    return not no_wait
+
+def llcp_worker(llc):
+    global init_on_touch
+    if init_on_touch:
+        print("Starting handover client")
+        dpp_handover_client(llc)
+        print("Exiting llcp_worker thread (init_in_touch)")
+        return
+
+    global no_input
+    if no_input:
+        print("Wait for handover to complete")
+    else:
+        print("Wait for handover to complete - press 'i' to initiate")
+    global srv
+    global wait_connection
+    while not wait_connection and srv.sent_carrier is None:
+        if srv.try_own:
+            srv.try_own = False
+            print("Try to initiate another handover with own parameters")
+            dpp_handover_client(llc)
+            print("Exiting llcp_worker thread (retry with own parameters)")
+            return
+        if srv.ho_server_processing:
+            time.sleep(0.025)
+        elif no_input:
+            time.sleep(0.5)
+        else:
+            res = getch()
+            if res != 'i':
+                continue
+            clear_raw_mode()
+            print("Starting handover client")
+            dpp_handover_client(llc)
+            print("Exiting llcp_worker thread (manual init)")
+            return
+
+    clear_raw_mode()
+    print("\rExiting llcp_worker thread")
+
+def llcp_startup(llc):
+    print("Start LLCP server")
+    global srv
+    srv = HandoverServer(llc)
+    return llc
+
+def llcp_connected(llc):
+    print("P2P LLCP connected")
+    global wait_connection
+    wait_connection = False
+    global init_on_touch
+    if not init_on_touch:
+        global srv
+        srv.start()
+    if init_on_touch or not no_input:
+        threading.Thread(target=llcp_worker, args=(llc,)).start()
+    return True
+
+def llcp_release(llc):
+    print("LLCP release")
+    return True
+
+def terminate_loop():
+    global terminate_now
+    return terminate_now
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for DPP NFC operations')
+    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+                        action='store_const', dest='loglevel',
+                        help='verbose debug output')
+    parser.add_argument('-q', const=logging.WARNING, action='store_const',
+                        dest='loglevel', help='be quiet')
+    parser.add_argument('--only-one', '-1', action='store_true',
+                        help='run only one operation and exit')
+    parser.add_argument('--init-on-touch', '-I', action='store_true',
+                        help='initiate handover on touch')
+    parser.add_argument('--no-wait', action='store_true',
+                        help='do not wait for tag to be removed before exiting')
+    parser.add_argument('--ifname', '-i',
+                        help='network interface name')
+    parser.add_argument('--no-input', '-a', action='store_true',
+                        help='do not use stdout input to initiate handover')
+    parser.add_argument('--tag-read-only', '-t', action='store_true',
+                        help='tag read only (do not allow connection handover)')
+    parser.add_argument('--handover-only', action='store_true',
+                        help='connection handover only (do not allow tag read)')
+    parser.add_argument('--summary',
+                        help='summary file for writing status updates')
+    parser.add_argument('--success',
+                        help='success file for writing success update')
+    parser.add_argument('--device', default='usb', help='NFC device to open')
+    parser.add_argument('--chan', default='81/1', help='channel list')
+    parser.add_argument('command', choices=['write-nfc-uri',
+                                            'write-nfc-hs'],
+                        nargs='?')
+    args = parser.parse_args()
+    print(args)
+
+    global only_one
+    only_one = args.only_one
+
+    global no_wait
+    no_wait = args.no_wait
+
+    global chanlist
+    chanlist = args.chan
+
+    logging.basicConfig(level=args.loglevel)
+
+    global init_on_touch
+    init_on_touch = args.init_on_touch
+
+    if args.ifname:
+        global ifname
+        ifname = args.ifname
+        print("Selected ifname " + ifname)
+
+    if args.summary:
+        global summary_file
+        summary_file = args.summary
+
+    if args.success:
+        global success_file
+        success_file = args.success
+
+    if args.no_input:
+        global no_input
+        no_input = True
+
+    clf = nfc.ContactlessFrontend()
+    global wait_connection
+
+    try:
+        if not clf.open(args.device):
+            print("Could not open connection with an NFC device")
+            raise SystemExit
+
+        if args.command == "write-nfc-uri":
+            write_nfc_uri(clf, wait_remove=not args.no_wait)
+            raise SystemExit
+
+        if args.command == "write-nfc-hs":
+            write_nfc_hs(clf, wait_remove=not args.no_wait)
+            raise SystemExit
+
+        global continue_loop
+        while continue_loop:
+            clear_raw_mode()
+            print("\rWaiting for a tag or peer to be touched")
+            wait_connection = True
+            try:
+                if args.tag_read_only:
+                    if not clf.connect(rdwr={'on-connect': rdwr_connected}):
+                        break
+                elif args.handover_only:
+                    if not clf.connect(llcp={'on-startup': llcp_startup,
+                                             'on-connect': llcp_connected,
+                                             'on-release': llcp_release},
+                                       terminate=terminate_loop):
+                        break
+                else:
+                    if not clf.connect(rdwr={'on-connect': rdwr_connected},
+                                       llcp={'on-startup': llcp_startup,
+                                             'on-connect': llcp_connected,
+                                             'on-release': llcp_release},
+                                       terminate=terminate_loop):
+                        break
+            except Exception as e:
+                print("clf.connect failed: " + str(e))
+                break
+
+            global srv
+            if only_one and srv and srv.success:
+                raise SystemExit
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
index 6e3d94e..2f62e9c 100644
--- a/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -108,7 +108,7 @@
 		self.path = None
 		try:
 			self.path = self.wpas.GetInterface(ifname)
-		except:
+		except dbus.DBusException as exc:
 			if not str(exc).startswith(
 				self.wpas_dbus_interface + \
 				".InterfaceUnknown:"):
diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.cpp b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
index bd893a3..ffa9b6a 100644
--- a/wpa_supplicant/hidl/1.3/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
@@ -100,7 +100,7 @@
 	struct hostapd_hw_modes *mode;
 	int count, i;
 
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, 0);
 	if (mode == NULL) {
 		/* No channels supported in this band. */
 		return;
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 36c0aff..02e6390 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -64,10 +64,16 @@
 {
 	struct ibss_rsn_peer *peer = ctx;
 	struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+	int encrypt = peer->authentication_status & IBSS_RSN_REPORTED_PTK;
 
-	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
-		   "len=%lu)",
-		   __func__, MAC2STR(dest), proto, (unsigned long) len);
+	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR
+		   " proto=0x%04x len=%lu no_encrypt=%d)",
+		   __func__, MAC2STR(dest), proto, (unsigned long) len,
+		   !encrypt);
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+		return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+					       !encrypt);
 
 	if (wpa_s->l2)
 		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
@@ -140,7 +146,7 @@
 static int supp_set_key(void *ctx, enum wpa_alg alg,
 			const u8 *addr, int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
+			const u8 *key, size_t key_len, enum key_flag key_flag)
 {
 	struct ibss_rsn_peer *peer = ctx;
 
@@ -167,7 +173,7 @@
 	if (is_broadcast_ether_addr(addr))
 		addr = peer->addr;
 	return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
-			       set_tx, seq, seq_len, key, key_len);
+			       set_tx, seq, seq_len, key, key_len, key_flag);
 }
 
 
@@ -194,7 +200,13 @@
 }
 
 
-static void supp_deauthenticate(void * ctx, u16 reason_code)
+static void supp_deauthenticate(void *ctx, u16 reason_code)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
+}
+
+
+static void supp_reconnect(void *ctx)
 {
 	wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
 }
@@ -219,6 +231,7 @@
 	ctx->mlme_setprotection = supp_mlme_setprotection;
 	ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
 	ctx->deauthenticate = supp_deauthenticate;
+	ctx->reconnect = supp_reconnect;
 	peer->supp = wpa_sm_init(ctx);
 	if (peer->supp == NULL) {
 		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
@@ -287,6 +300,10 @@
 		   "encrypt=%d)",
 		   __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
 
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+		return wpa_drv_tx_control_port(wpa_s, addr, ETH_P_EAPOL,
+					       data, data_len, !encrypt);
+
 	if (wpa_s->l2)
 		return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
 				      data_len);
@@ -296,7 +313,8 @@
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			enum key_flag key_flag)
 {
 	struct ibss_rsn *ibss_rsn = ctx;
 	u8 seq[6];
@@ -335,7 +353,7 @@
 	}
 
 	return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
-			       1, seq, 6, key, key_len);
+			       1, seq, 6, key, key_len, key_flag);
 }
 
 
@@ -487,9 +505,6 @@
 	const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
 	struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
 
-	if (wpa_s->driver->send_frame == NULL)
-		return -1;
-
 	os_memset(&auth, 0, sizeof(auth));
 
 	auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -505,8 +520,7 @@
 	wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
 		   seq, MAC2STR(da));
 
-	return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
-					 auth_length, 0);
+	return wpa_drv_send_mlme(wpa_s, (u8 *) &auth, auth_length, 0, 0, 0);
 }
 
 
@@ -852,7 +866,7 @@
 		wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
 			   MACSTR, MAC2STR(addr));
 		wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
-				NULL, 0, NULL, 0);
+				NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	if (peer &&
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 308366f..4925b5c 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -233,12 +233,10 @@
 		  2 + 24 + /* peering management */
 		  2 + 96 + 32 + 32 + /* AMPE (96 + max GTKlen + max IGTKlen) */
 		  2 + 16;  /* MIC */
-#ifdef CONFIG_IEEE80211N
 	if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
 		buf_len += 2 + 26 + /* HT capabilities */
 			   2 + 22;  /* HT operation */
 	}
-#endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_IEEE80211AC
 	if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
 		buf_len += 2 + 12 + /* VHT Capabilities */
@@ -354,7 +352,6 @@
 				   wpabuf_put(buf, PMKID_LEN));
 	}
 
-#ifdef CONFIG_IEEE80211N
 	if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
 		u8 ht_capa_oper[2 + 26 + 2 + 22];
 
@@ -362,7 +359,6 @@
 		pos = hostapd_eid_ht_operation(bss, pos);
 		wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
 	}
-#endif /* CONFIG_IEEE80211N */
 #ifdef CONFIG_IEEE80211AC
 	if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
 		u8 vht_capa_oper[2 + 12 + 2 + 5];
@@ -696,9 +692,7 @@
 	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
 	struct hostapd_data *data = wpa_s->ifmsh->bss[0];
 	struct sta_info *sta;
-#ifdef CONFIG_IEEE80211N
 	struct ieee80211_ht_operation *oper;
-#endif /* CONFIG_IEEE80211N */
 	int ret;
 
 	if (elems->mesh_config_len >= 7 &&
@@ -710,11 +704,12 @@
 	}
 
 	sta = ap_get_sta(data, addr);
-	if (!sta) {
-		sta = ap_sta_add(data, addr);
-		if (!sta)
-			return NULL;
-	}
+	if (sta)
+		return NULL;
+
+	sta = ap_sta_add(data, addr);
+	if (!sta)
+		return NULL;
 
 	/* Set WMM by default since Mesh STAs are QoS STAs */
 	sta->flags |= WLAN_STA_WMM;
@@ -728,7 +723,6 @@
 	if (!sta->my_lid)
 		mesh_mpm_init_link(wpa_s, sta);
 
-#ifdef CONFIG_IEEE80211N
 	copy_sta_ht_capab(data, sta, elems->ht_capabilities);
 
 	oper = (struct ieee80211_ht_operation *) elems->ht_operation;
@@ -742,7 +736,6 @@
 	}
 
 	update_ht_state(data, sta);
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
 	copy_sta_vht_capab(data, sta, elems->vht_capabilities);
@@ -876,7 +869,8 @@
 		wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
 		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
 				sta->addr, 0, 0, seq, sizeof(seq),
-				sta->mtk, sta->mtk_len);
+				sta->mtk, sta->mtk_len,
+				KEY_FLAG_PAIRWISE_RX_TX);
 
 		wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
 				sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
@@ -885,7 +879,8 @@
 		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
 				sta->addr, sta->mgtk_key_id, 0,
 				sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
-				sta->mgtk, sta->mgtk_len);
+				sta->mgtk, sta->mgtk_len,
+				KEY_FLAG_GROUP_RX);
 
 		if (sta->igtk_len) {
 			wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
@@ -897,7 +892,8 @@
 				wpa_cipher_to_alg(conf->mgmt_group_cipher),
 				sta->addr, sta->igtk_key_id, 0,
 				sta->igtk_rsc, sizeof(sta->igtk_rsc),
-				sta->igtk, sta->igtk_len);
+				sta->igtk, sta->igtk_len,
+				KEY_FLAG_GROUP_RX);
 		}
 	}
 
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e730b63..f19bfbf 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -100,7 +100,8 @@
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			enum key_flag key_flag)
 {
 	struct mesh_rsn *mesh_rsn = ctx;
 	u8 seq[6];
@@ -118,7 +119,7 @@
 	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
 
 	return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
-			       1, seq, 6, key, key_len);
+			       1, seq, 6, key, key_len, key_flag);
 }
 
 
@@ -196,7 +197,8 @@
 		wpa_drv_set_key(rsn->wpa_s,
 				wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
 				rsn->igtk_key_id, 1,
-				seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+				seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
+				KEY_FLAG_GROUP_TX_DEFAULT);
 	}
 
 	/* group privacy / data frames */
@@ -204,7 +206,7 @@
 			rsn->mgtk, rsn->mgtk_len);
 	wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
 			rsn->mgtk_key_id, 1, seq, sizeof(seq),
-			rsn->mgtk, rsn->mgtk_len);
+			rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
 
 	return 0;
 }
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index b74be7d..e40cf5b 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -226,10 +226,10 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (wpa_s->p2p_long_listen > 0) {
+	if (wpa_s->global->p2p_long_listen > 0) {
 		/* Continue the listen */
 		wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
-		wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+		wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
 	}
 #endif /* CONFIG_P2P */
 }
@@ -246,7 +246,7 @@
  * @buf: Frame to transmit starting from the Category field
  * @len: Length of @buf in bytes
  * @wait_time: Wait time for response in milliseconds
- * @tx_cb: Callback function for indicating TX status or %NULL for now callback
+ * @tx_cb: Callback function for indicating TX status or %NULL for no callback
  * @no_cck: Whether CCK rates are to be disallowed for TX rate selection
  * Returns: 0 on success or -1 on failure
  *
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index b15ac9e..983801f 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -14,6 +14,7 @@
 #include "utils/common.h"
 #include "common/ieee802_11_common.h"
 #include "wpa_supplicant_i.h"
+#include "bss.h"
 
 
 static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
@@ -228,7 +229,8 @@
 	int freq2 = 0;
 	int freq5 = 0;
 
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode,
+			is_6ghz_op_class(op_class->op_class));
 	if (!mode)
 		return 0;
 
@@ -355,9 +357,25 @@
 }
 
 
+static int wpas_sta_secondary_channel_offset(struct wpa_bss *bss, u8 *current,
+					     u8 *channel)
+{
+
+	u8 *ies, phy_type;
+	size_t ies_len;
+
+	if (!bss)
+		return -1;
+	ies = (u8 *) (bss + 1);
+	ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+	return wpas_get_op_chan_phy(bss->freq, ies, ies_len, current,
+				    channel, &phy_type);
+}
+
+
 size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
 			     struct wpa_ssid *ssid,
-			     int freq, u8 *pos, size_t len)
+			     struct wpa_bss *bss, u8 *pos, size_t len)
 {
 	struct wpabuf *buf;
 	u8 op, current, chan;
@@ -365,11 +383,13 @@
 	size_t res;
 
 	/*
-	 * Assume 20 MHz channel for now.
-	 * TODO: Use the secondary channel and VHT channel width that will be
-	 * used after association.
+	 * Determine the current operating class correct mode based on
+	 * advertised BSS capabilities, if available. Fall back to a less
+	 * accurate guess based on frequency if the needed IEs are not available
+	 * or used.
 	 */
-	if (ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
+	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)
 		return 0;
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index a3c4574..2c8754b 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1912,7 +1912,7 @@
 		return -1;
 
 	hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
-			  HOSTAPD_MODE_IEEE80211AD);
+			  HOSTAPD_MODE_IEEE80211AD, 0);
 	if (!hwmode) {
 		wpa_printf(MSG_ERROR,
 			   "Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
@@ -2422,7 +2422,7 @@
 		wpas_start_wps_enrollee(group_wpa_s, res);
 	}
 
-	wpa_s->p2p_long_listen = 0;
+	wpa_s->global->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
@@ -2701,7 +2701,7 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
-				 freq);
+				 freq, 0);
 }
 
 
@@ -3735,7 +3735,8 @@
 		if (o->p2p == NO_P2P_SUPP)
 			continue;
 
-		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
+		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
+				is_6ghz_op_class(o->op_class));
 		if (mode == NULL)
 			continue;
 		if (mode->mode == HOSTAPD_MODE_IEEE80211G)
@@ -3745,23 +3746,32 @@
 			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
 			if (res == ALLOWED) {
 				if (reg == NULL) {
+					if (cla == P2P_MAX_REG_CLASSES)
+						continue;
 					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
 						   o->op_class);
 					reg = &chan->reg_class[cla];
 					cla++;
 					reg->reg_class = o->op_class;
 				}
+				if (reg->channels == P2P_MAX_REG_CLASS_CHANNELS)
+					continue;
 				reg->channel[reg->channels] = ch;
 				reg->channels++;
 			} else if (res == NO_IR &&
 				   wpa_s->conf->p2p_add_cli_chan) {
 				if (cli_reg == NULL) {
+					if (cli_cla == P2P_MAX_REG_CLASSES)
+						continue;
 					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
 						   o->op_class);
 					cli_reg = &cli_chan->reg_class[cli_cla];
 					cli_cla++;
 					cli_reg->reg_class = o->op_class;
 				}
+				if (cli_reg->channels ==
+				    P2P_MAX_REG_CLASS_CHANNELS)
+					continue;
 				cli_reg->channel[cli_reg->channels] = ch;
 				cli_reg->channels++;
 			}
@@ -4758,7 +4768,7 @@
 	eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
-	wpa_s->p2p_long_listen = 0;
+	wpa_s->global->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
 	wpas_p2p_remove_pending_group_interface(wpa_s);
@@ -5643,7 +5653,7 @@
 		go_intent = wpa_s->conf->p2p_go_intent;
 
 	if (!auth)
-		wpa_s->p2p_long_listen = 0;
+		wpa_s->global->p2p_long_listen = 0;
 
 	wpa_s->p2p_wps_method = wps_method;
 	wpa_s->p2p_persistent_group = !!persistent_group;
@@ -5813,19 +5823,20 @@
 {
 	wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
 		   "(p2p_long_listen=%d ms pending_action_tx=%p)",
-		   wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+		   wpa_s->global->p2p_long_listen,
+		   offchannel_pending_action_tx(wpa_s));
 	wpas_p2p_listen_work_done(wpa_s);
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
-	if (wpa_s->p2p_long_listen > 0)
-		wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
+	if (wpa_s->global->p2p_long_listen > 0)
+		wpa_s->global->p2p_long_listen -= wpa_s->max_remain_on_chan;
 	if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
 		return; /* P2P module started a new operation */
 	if (offchannel_pending_action_tx(wpa_s))
 		return;
-	if (wpa_s->p2p_long_listen > 0) {
+	if (wpa_s->global->p2p_long_listen > 0) {
 		wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
-		wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+		wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
 	} else {
 		/*
 		 * When listen duration is over, stop listen & update p2p_state
@@ -6298,7 +6309,7 @@
 			cand = wpa_s->p2p_group_common_freqs[i];
 			mode = ieee80211_freq_to_chan(cand, &chan);
 			hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
-					  mode);
+					  mode, is_6ghz_freq(cand));
 			if (!hwmode ||
 			    wpas_p2p_verify_channel(wpa_s, hwmode, chan,
 						    BW80) != ALLOWED)
@@ -6325,7 +6336,7 @@
 			cand = wpa_s->p2p_group_common_freqs[i];
 			mode = ieee80211_freq_to_chan(cand, &chan);
 			hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
-					  mode);
+					  mode, is_6ghz_freq(cand));
 			if (!wpas_same_band(wpa_s->current_ssid->frequency,
 					    cand) ||
 			    !hwmode ||
@@ -6960,7 +6971,7 @@
 		  u8 seek_cnt, const char **seek_string, int freq)
 {
 	wpas_p2p_clear_pending_action_tx(wpa_s);
-	wpa_s->p2p_long_listen = 0;
+	wpa_s->global->p2p_long_listen = 0;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
 	    wpa_s->p2p_in_provisioning) {
@@ -7005,7 +7016,7 @@
 static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_clear_pending_action_tx(wpa_s);
-	wpa_s->p2p_long_listen = 0;
+	wpa_s->global->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 
@@ -7031,7 +7042,7 @@
 static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
-	wpa_s->p2p_long_listen = 0;
+	wpa_s->global->p2p_long_listen = 0;
 }
 
 
@@ -7060,7 +7071,7 @@
 		timeout = 3600;
 	}
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
-	wpa_s->p2p_long_listen = 0;
+	wpa_s->global->p2p_long_listen = 0;
 
 	/*
 	 * Stop previous find/listen operation to avoid trying to request a new
@@ -7072,7 +7083,7 @@
 
 	res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
 	if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
-		wpa_s->p2p_long_listen = timeout * 1000;
+		wpa_s->global->p2p_long_listen = timeout * 1000;
 		eloop_register_timeout(timeout, 0,
 				       wpas_p2p_long_listen_timeout,
 				       wpa_s, NULL);
@@ -7179,7 +7190,7 @@
 
 int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
 {
-	wpa_s->p2p_long_listen = 0;
+	wpa_s->global->p2p_long_listen = 0;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 3f2da34..4a8f4ff 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -41,6 +41,12 @@
 }
 
 
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+	wpa_supplicant_reconnect(wpa_s);
+}
+
+
 static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
 			    const void *data, u16 data_len,
 			    size_t *msg_len, void **data_pos)
@@ -127,7 +133,8 @@
 static int wpa_supplicant_set_key(void *wpa_s, enum wpa_alg alg,
 				  const u8 *addr, int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_flag key_flag)
 {
 	printf("%s - not implemented\n", __func__);
 	return -1;
@@ -146,7 +153,8 @@
 static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
 				    const u8 *bssid, const u8 *pmkid,
 				    const u8 *fils_cache_id,
-				    const u8 *pmk, size_t pmk_len)
+				    const u8 *pmk, size_t pmk_len,
+				    u32 pmk_lifetime, u8 pmk_reauth_threshold)
 {
 	printf("%s - not implemented\n", __func__);
 	return -1;
@@ -244,6 +252,7 @@
 	ctx->set_config_blob = wpa_supplicant_set_config_blob;
 	ctx->get_config_blob = wpa_supplicant_get_config_blob;
 	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
+	ctx->reconnect = _wpa_supplicant_reconnect;
 
 	wpa_s->wpa = wpa_sm_init(ctx);
 	assert(wpa_s->wpa != NULL);
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 7930e01..afc1172 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -609,7 +609,8 @@
 		pos++;
 		left--;
 
-		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+				is_6ghz_op_class(op->op_class));
 		if (!mode)
 			continue;
 
@@ -661,7 +662,8 @@
 		return NULL;
 	}
 
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+			is_6ghz_op_class(op->op_class));
 	if (!mode)
 		return NULL;
 
@@ -693,8 +695,8 @@
 }
 
 
-static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
-				u8 *op_class, u8 *chan, u8 *phy_type)
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+			 u8 *op_class, u8 *chan, u8 *phy_type)
 {
 	const u8 *ie;
 	int sec_chan = 0, vht = 0;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 4d158a9..b475730 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -668,13 +668,14 @@
 
 static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
 					enum hostapd_hw_mode band,
-					struct wpa_driver_scan_params *params)
+					struct wpa_driver_scan_params *params,
+					int is_6ghz)
 {
 	/* Include only supported channels for the specified band */
 	struct hostapd_hw_modes *mode;
 	int count, i;
 
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz);
 	if (mode == NULL) {
 		/* No channels supported in this band - use empty list */
 		params->freqs = os_zalloc(sizeof(int));
@@ -701,10 +702,10 @@
 		return; /* already using a limited channel set */
 	if (wpa_s->setband == WPA_SETBAND_5G)
 		wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
-					    params);
+					    params, 0);
 	else if (wpa_s->setband == WPA_SETBAND_2G)
 		wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
-					    params);
+					    params, 0);
 }
 
 
@@ -1108,7 +1109,9 @@
 		     tssid = tssid->next) {
 			if (wpas_network_disabled(wpa_s, tssid))
 				continue;
-			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
+			if (((params.freqs || !freqs_set) &&
+			     tssid->scan_freq) &&
+			    int_array_len(params.freqs) < 100) {
 				int_array_concat(&params.freqs,
 						 tssid->scan_freq);
 			} else {
@@ -1250,7 +1253,8 @@
 
 		params.bssid = wpa_s->next_scan_bssid;
 		bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
-		if (bss && bss->ssid_len && params.num_ssids == 1 &&
+		if (!wpa_s->next_scan_bssid_wildcard_ssid &&
+		    bss && bss->ssid_len && params.num_ssids == 1 &&
 		    params.ssids[0].ssid_len == 0) {
 			params.ssids[0].ssid = bss->ssid;
 			params.ssids[0].ssid_len = bss->ssid_len;
@@ -1327,6 +1331,7 @@
 #ifdef CONFIG_INTERWORKING
 		wpa_s->interworking_fast_assoc_tried = 0;
 #endif /* CONFIG_INTERWORKING */
+		wpa_s->next_scan_bssid_wildcard_ssid = 0;
 		if (params.bssid)
 			os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
 	}
@@ -1956,20 +1961,6 @@
 }
 
 
-/*
- * Channels with a great SNR can operate at full rate. What is a great SNR?
- * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
- * rule of thumb is that any SNR above 20 is good." This one
- * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
- * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
- * scan_est_throughput() allow even smaller SNR values for the maximum rates
- * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
- * somewhat conservative value here.
- */
-#define GREAT_SNR 25
-
-#define IS_5GHZ(n) (n > 4000)
-
 /* Compare function for sorting scan results. Return >0 if @b is considered
  * better. */
 static int wpa_scan_result_compar(const void *a, const void *b)
@@ -2178,14 +2169,6 @@
 }
 
 
-/*
- * Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurements. These values were
- * measured in an office environment with many APs.
- */
-#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
-#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
-
 void scan_snr(struct wpa_scan_res *res)
 {
 	if (res->flags & WPA_SCAN_NOISE_INVALID) {
@@ -2204,86 +2187,83 @@
 }
 
 
-static unsigned int max_ht20_rate(int snr)
+static unsigned int interpolate_rate(int snr, int snr0, int snr1,
+				     int rate0, int rate1)
 {
-	if (snr < 6)
-		return 6500; /* HT20 MCS0 */
-	if (snr < 8)
-		return 13000; /* HT20 MCS1 */
-	if (snr < 13)
-		return 19500; /* HT20 MCS2 */
-	if (snr < 17)
-		return 26000; /* HT20 MCS3 */
-	if (snr < 20)
-		return 39000; /* HT20 MCS4 */
-	if (snr < 23)
-		return 52000; /* HT20 MCS5 */
-	if (snr < 24)
-		return 58500; /* HT20 MCS6 */
-	return 65000; /* HT20 MCS7 */
+	return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0);
 }
 
 
-static unsigned int max_ht40_rate(int snr)
+#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
+	if (snr < (snr1)) \
+		return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
+
+static unsigned int max_ht20_rate(int snr, int vht)
 {
-	if (snr < 3)
-		return 13500; /* HT40 MCS0 */
-	if (snr < 6)
-		return 27000; /* HT40 MCS1 */
-	if (snr < 10)
-		return 40500; /* HT40 MCS2 */
-	if (snr < 15)
-		return 54000; /* HT40 MCS3 */
-	if (snr < 17)
-		return 81000; /* HT40 MCS4 */
-	if (snr < 22)
-		return 108000; /* HT40 MCS5 */
-	if (snr < 24)
-		return 121500; /* HT40 MCS6 */
-	return 135000; /* HT40 MCS7 */
+	if (snr < 0)
+		return 0;
+	INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */
+	INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */
+	INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */
+	INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */
+	INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */
+	INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */
+	INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */
+	INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */
+	if (!vht)
+		return 65000;
+	INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */
+	return 78000;
+}
+
+
+static unsigned int max_ht40_rate(int snr, int vht)
+{
+	if (snr < 0)
+		return 0;
+	INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */
+	INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */
+	INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */
+	INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */
+	INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */
+	INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */
+	INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */
+	INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */
+	if (!vht)
+		return 135000;
+	INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */
+	INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */
+	return 180000;
 }
 
 
 static unsigned int max_vht80_rate(int snr)
 {
-	if (snr < 1)
+	if (snr < 0)
 		return 0;
-	if (snr < 2)
-		return 29300; /* VHT80 MCS0 */
-	if (snr < 5)
-		return 58500; /* VHT80 MCS1 */
-	if (snr < 9)
-		return 87800; /* VHT80 MCS2 */
-	if (snr < 11)
-		return 117000; /* VHT80 MCS3 */
-	if (snr < 15)
-		return 175500; /* VHT80 MCS4 */
-	if (snr < 16)
-		return 234000; /* VHT80 MCS5 */
-	if (snr < 18)
-		return 263300; /* VHT80 MCS6 */
-	if (snr < 20)
-		return 292500; /* VHT80 MCS7 */
-	if (snr < 22)
-		return 351000; /* VHT80 MCS8 */
-	return 390000; /* VHT80 MCS9 */
+	INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */
+	INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */
+	INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */
+	INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */
+	INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */
+	INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */
+	INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */
+	INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */
+	INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */
+	INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */
+	return 390000;
 }
 
+#undef INTERPOLATE_RATE
 
-void scan_est_throughput(struct wpa_supplicant *wpa_s,
-			 struct wpa_scan_res *res)
+
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+			      const u8 *ies, size_t ies_len, int rate,
+			      int snr)
 {
 	enum local_hw_capab capab = wpa_s->hw_capab;
-	int rate; /* max legacy rate in 500 kb/s units */
-	const u8 *ie;
 	unsigned int est, tmp;
-	int snr = res->snr;
-
-	if (res->est_throughput)
-		return;
-
-	/* Get maximum legacy rate */
-	rate = wpa_scan_get_max_rate(res);
+	const u8 *ie;
 
 	/* Limit based on estimated SNR */
 	if (rate > 1 * 2 && snr < 1)
@@ -2296,32 +2276,50 @@
 		rate = 9 * 2;
 	else if (rate > 12 * 2 && snr < 7)
 		rate = 12 * 2;
+	else if (rate > 12 * 2 && snr < 8)
+		rate = 14 * 2;
+	else if (rate > 12 * 2 && snr < 9)
+		rate = 16 * 2;
 	else if (rate > 18 * 2 && snr < 10)
 		rate = 18 * 2;
 	else if (rate > 24 * 2 && snr < 11)
 		rate = 24 * 2;
+	else if (rate > 24 * 2 && snr < 12)
+		rate = 27 * 2;
+	else if (rate > 24 * 2 && snr < 13)
+		rate = 30 * 2;
+	else if (rate > 24 * 2 && snr < 14)
+		rate = 33 * 2;
 	else if (rate > 36 * 2 && snr < 15)
 		rate = 36 * 2;
+	else if (rate > 36 * 2 && snr < 16)
+		rate = 39 * 2;
+	else if (rate > 36 * 2 && snr < 17)
+		rate = 42 * 2;
+	else if (rate > 36 * 2 && snr < 18)
+		rate = 45 * 2;
 	else if (rate > 48 * 2 && snr < 19)
 		rate = 48 * 2;
+	else if (rate > 48 * 2 && snr < 20)
+		rate = 51 * 2;
 	else if (rate > 54 * 2 && snr < 21)
 		rate = 54 * 2;
 	est = rate * 500;
 
 	if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
-		ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP);
+		ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
 		if (ie) {
-			tmp = max_ht20_rate(snr);
+			tmp = max_ht20_rate(snr, 0);
 			if (tmp > est)
 				est = tmp;
 		}
 	}
 
 	if (capab == CAPAB_HT40 || capab == CAPAB_VHT) {
-		ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+		ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
 		if (ie && ie[1] >= 2 &&
 		    (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
-			tmp = max_ht40_rate(snr);
+			tmp = max_ht40_rate(snr, 0);
 			if (tmp > est)
 				est = tmp;
 		}
@@ -2329,22 +2327,22 @@
 
 	if (capab == CAPAB_VHT) {
 		/* Use +1 to assume VHT is always faster than HT */
-		ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP);
+		ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
 		if (ie) {
-			tmp = max_ht20_rate(snr) + 1;
+			tmp = max_ht20_rate(snr, 1) + 1;
 			if (tmp > est)
 				est = tmp;
 
-			ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+			ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
 			if (ie && ie[1] >= 2 &&
 			    (ie[3] &
 			     HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
-				tmp = max_ht40_rate(snr) + 1;
+				tmp = max_ht40_rate(snr, 1) + 1;
 				if (tmp > est)
 					est = tmp;
 			}
 
-			ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION);
+			ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
 			if (ie && ie[1] >= 1 &&
 			    (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) {
 				tmp = max_vht80_rate(snr) + 1;
@@ -2354,9 +2352,30 @@
 		}
 	}
 
-	/* TODO: channel utilization and AP load (e.g., from AP Beacon) */
+	return est;
+}
 
-	res->est_throughput = est;
+
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+			 struct wpa_scan_res *res)
+{
+	int rate; /* max legacy rate in 500 kb/s units */
+	int snr = res->snr;
+	const u8 *ies = (const void *) (res + 1);
+	size_t ie_len = res->ie_len;
+
+	if (res->est_throughput)
+		return;
+
+	/* Get maximum legacy rate */
+	rate = wpa_scan_get_max_rate(res);
+
+	if (!ie_len)
+		ie_len = res->beacon_ie_len;
+	res->est_throughput =
+		wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
+
+	/* TODO: channel utilization and AP load (e.g., from AP Beacon) */
 }
 
 
@@ -2611,8 +2630,8 @@
 
 int wpas_start_pno(struct wpa_supplicant *wpa_s)
 {
-	int ret, prio;
-	size_t i, num_ssid, num_match_ssid;
+	int ret;
+	size_t prio, i, num_ssid, num_match_ssid;
 	struct wpa_ssid *ssid;
 	struct wpa_driver_scan_params params;
 	struct sched_scan_plan scan_plan;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 58caa78..c9ce2ce 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -9,6 +9,28 @@
 #ifndef SCAN_H
 #define SCAN_H
 
+/*
+ * Noise floor values to use when we have signal strength
+ * measurements, but no noise floor measurements. These values were
+ * measured in an office environment with many APs.
+ */
+#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
+#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
+
+/*
+ * Channels with a great SNR can operate at full rate. What is a great SNR?
+ * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
+ * scan_est_throughput() allow even smaller SNR values for the maximum rates
+ * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
+ * somewhat conservative value here.
+ */
+#define GREAT_SNR 25
+
+#define IS_5GHZ(n) (n > 4000)
+
 int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
 int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
@@ -60,6 +82,9 @@
 void scan_snr(struct wpa_scan_res *res);
 void scan_est_throughput(struct wpa_supplicant *wpa_s,
 			 struct wpa_scan_res *res);
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+			      const u8 *ies, size_t ies_len, int rate,
+			      int snr);
 void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 08d7e3e..0cc81bf 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -131,7 +131,10 @@
 		return NULL;
 	}
 
-	if (wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+	if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
+		use_pt = 1;
+
+	if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
 		bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
 		if (bss) {
 			const u8 *rsnxe;
@@ -142,7 +145,9 @@
 					    BIT(WLAN_RSNX_CAPAB_SAE_H2E));
 		}
 
-		if (wpa_s->conf->sae_pwe == 1 && !use_pt) {
+		if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+		    wpa_s->conf->sae_pwe != 3 &&
+		    !use_pt) {
 			wpa_printf(MSG_DEBUG,
 				   "SAE: Cannot use H2E with the selected AP");
 			return NULL;
@@ -166,7 +171,7 @@
 		os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
 
 reuse_data:
-	len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+	len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
 	if (ssid->sae_password_id)
 		len += 4 + os_strlen(ssid->sae_password_id);
 	buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
@@ -177,8 +182,11 @@
 		wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
 				WLAN_STATUS_SUCCESS);
 	}
-	sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
-			 ssid->sae_password_id);
+	if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+			     ssid->sae_password_id) < 0) {
+		wpabuf_free(buf);
+		return NULL;
+	}
 	if (ret_use_pt)
 		*ret_use_pt = use_pt;
 
@@ -281,7 +289,7 @@
 #if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
 	const u8 *md = NULL;
 #endif /* CONFIG_IEEE80211R || CONFIG_FILS */
-	int i, bssid_changed;
+	int bssid_changed;
 	struct wpabuf *resp = NULL;
 	u8 ext_capab[18];
 	int ext_capab_len;
@@ -291,6 +299,7 @@
 #ifdef CONFIG_MBO
 	const u8 *mbo_ie;
 #endif /* CONFIG_MBO */
+	int omit_rsnxe = 0;
 
 	if (bss == NULL) {
 		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -365,18 +374,18 @@
 	}
 #endif /* CONFIG_SAE */
 
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i])
-			params.wep_key[i] = ssid->wep_key[i];
-		params.wep_key_len[i] = ssid->wep_key_len[i];
-	}
-	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#ifdef CONFIG_WEP
+	{
+		int i;
 
-	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
-	os_memset(wpa_s->bssid, 0, ETH_ALEN);
-	os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
-	if (bssid_changed)
-		wpas_notify_bssid_changed(wpa_s);
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (ssid->wep_key_len[i])
+				params.wep_key[i] = ssid->wep_key[i];
+			params.wep_key_len[i] = ssid->wep_key_len[i];
+		}
+		params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+	}
+#endif /* CONFIG_WEP */
 
 	if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
 	     wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
@@ -498,6 +507,7 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
 			md[0], md[1]);
 
+		omit_rsnxe = !wpa_bss_get_ie(bss, WLAN_EID_RSNX);
 		if (wpa_s->sme.assoc_req_ie_len + 5 <
 		    sizeof(wpa_s->sme.assoc_req_ie)) {
 			struct rsn_mdie *mdie;
@@ -570,7 +580,7 @@
 	sme_auth_handle_rrm(wpa_s, bss);
 
 	wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
-		wpa_s, ssid, bss->freq,
+		wpa_s, ssid, bss,
 		wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
 		sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
 
@@ -606,7 +616,8 @@
 #endif /* CONFIG_TESTING_OPTIONS */
 	if (wpa_s->rsnxe_len > 0 &&
 	    wpa_s->rsnxe_len <=
-	    sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+	    sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len &&
+	    !omit_rsnxe) {
 		os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
 			  wpa_s->rsnxe, wpa_s->rsnxe_len);
 		wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
@@ -718,6 +729,12 @@
 	}
 #endif /* CONFIG_SAE */
 
+	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+	os_memset(wpa_s->bssid, 0, ETH_ALEN);
+	os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+	if (bssid_changed)
+		wpas_notify_bssid_changed(wpa_s);
+
 	old_ssid = wpa_s->current_ssid;
 	wpa_s->current_ssid = ssid;
 	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
@@ -1010,7 +1027,7 @@
 				    bssid, 1, wpa_s->sme.seq_num,
 				    use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
 				    WLAN_STATUS_SUCCESS);
-	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
 	wpabuf_free(resp);
 	wpabuf_free(buf);
 
@@ -1080,7 +1097,7 @@
 	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
 				    da, 2, wpa_s->sme.seq_num,
 				    WLAN_STATUS_SUCCESS);
-	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
 	wpabuf_free(resp);
 	wpabuf_free(buf);
 }
@@ -1177,11 +1194,16 @@
 	    (external || wpa_s->current_bss) && wpa_s->current_ssid) {
 		int default_groups[] = { 19, 20, 21, 0 };
 		u16 group;
+		const u8 *token_pos;
+		size_t token_len;
+		int h2e = 0;
 
 		groups = wpa_s->conf->sae_groups;
 		if (!groups || groups[0] <= 0)
 			groups = default_groups;
 
+		wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request",
+			    data, len);
 		if (len < sizeof(le16)) {
 			wpa_dbg(wpa_s, MSG_DEBUG,
 				"SME: Too short SAE anti-clogging token request");
@@ -1199,8 +1221,30 @@
 			return -1;
 		}
 		wpabuf_free(wpa_s->sme.sae_token);
-		wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
-							 len - sizeof(le16));
+		token_pos = data + sizeof(le16);
+		token_len = len - sizeof(le16);
+		if (wpa_s->sme.sae.tmp)
+			h2e = wpa_s->sme.sae.tmp->h2e;
+		if (h2e) {
+			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) {
+				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;
+		}
+		wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
+		wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
+				wpa_s->sme.sae_token);
 		if (!external)
 			sme_send_authentication(wpa_s, wpa_s->current_bss,
 						wpa_s->current_ssid, 2);
@@ -1260,6 +1304,19 @@
 				   "SAE: Ignore commit message while waiting for confirm");
 			return 0;
 		}
+		if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e &&
+		    status_code == WLAN_STATUS_SUCCESS) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
+			return -1;
+		}
+		if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->h2e &&
+		    status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
+			return -1;
+		}
+
 		if (groups && groups[0] <= 0)
 			groups = NULL;
 		res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
@@ -1736,7 +1793,9 @@
 
 #ifdef CONFIG_DPP2
 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
-	    wpa_s->current_ssid->dpp_netaccesskey) {
+	    wpa_s->current_ssid->dpp_netaccesskey &&
+	    wpa_s->current_ssid->dpp_pfs != 2 &&
+	    !wpa_s->current_ssid->dpp_pfs_fallback) {
 		struct wpa_ssid *ssid = wpa_s->current_ssid;
 
 		dpp_pfs_free(wpa_s->dpp_pfs);
@@ -1810,6 +1869,9 @@
 	params.vhtcaps_mask = &vhtcaps_mask;
 	wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
 #endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+	wpa_supplicant_apply_he_overrides(wpa_s, wpa_s->current_ssid, &params);
+#endif /* CONFIG_HE_OVERRIDES */
 #ifdef CONFIG_IEEE80211R
 	if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
 	    get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
@@ -2308,7 +2370,7 @@
 	int start, end;
 
 	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
-			HOSTAPD_MODE_IEEE80211G);
+			HOSTAPD_MODE_IEEE80211G, 0);
 	if (mode == NULL) {
 		/* No channels supported in this band - use empty list */
 		params->freqs = os_zalloc(sizeof(int));
@@ -2601,6 +2663,10 @@
 		return;
 	if (wpa_s->sme.sa_query_count > 0)
 		return;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->disable_sa_query)
+		return;
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	os_get_reltime(&now);
 	if (wpa_s->sme.last_unprot_disconnect.sec &&
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index 03ac507..da69a87 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -12,4 +12,4 @@
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
 
 [Install]
-Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
index c8a744d..ca3054b 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -12,4 +12,4 @@
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
 
 [Install]
-Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
index 7788b38..55d2b9c 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -12,4 +12,4 @@
 ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
 
 [Install]
-Alias=multi-user.target.wants/wpa_supplicant@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 1c0399f..2e09102 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -280,6 +280,15 @@
 			wpa_wnmsleep_install_key(wpa_s->wpa,
 						 WNM_SLEEP_SUBELEM_IGTK, ptr);
 			ptr += 10 + WPA_IGTK_LEN;
+		} else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) {
+			if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) {
+				wpa_printf(MSG_DEBUG,
+					   "WNM: Too short BIGTK subelem");
+				break;
+			}
+			wpa_wnmsleep_install_key(wpa_s->wpa,
+						 WNM_SLEEP_SUBELEM_BIGTK, ptr);
+			ptr += 10 + WPA_BIGTK_LEN;
 		} else
 			break; /* skip the loop */
 	}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index a1b0615..07d5f31 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -502,6 +502,7 @@
 		"ignore_auth_resp",
 #endif /* CONFIG_TESTING_OPTIONS */
 		"relative_rssi", "relative_band_adjust",
+		"extended_key_id",
 	};
 	int i, num_fields = ARRAY_SIZE(fields);
 
@@ -593,7 +594,7 @@
 		"tdls_external_control", "osu_dir", "wowlan_triggers",
 		"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
 		"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
-		"reassoc_same_bss_optim"
+		"reassoc_same_bss_optim", "extended_key_id"
 	};
 	int i, num_fields = ARRAY_SIZE(fields);
 
@@ -1302,7 +1303,7 @@
 static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
 				     char *argv[])
 {
-	return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
+	return wpa_cli_cmd(ctrl, "LIST_NETWORKS", 0, argc, argv);
 }
 
 
@@ -1441,6 +1442,7 @@
 	"dot11MeshHoldingTimeout",
 #endif /* CONFIG_MESH */
 	"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+	"wpa_deny_ptk0_rekey",
 	"enable_edmg", "edmg_channel",
 #ifdef CONFIG_P2P
 	"go_p2p_dev_addr", "p2p_client_list", "psk_list",
@@ -1458,6 +1460,9 @@
 	"vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5",
 	"vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8",
 #endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+	"disable_he",
+#endif /* CONFIG_HE_OVERRIDES */
 	"ap_max_inactivity", "dtim_period", "beacon_int",
 #ifdef CONFIG_MACSEC
 	"macsec_policy",
@@ -1782,7 +1787,7 @@
 	}
 
 	if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
-		printf("Connected to interface '%s.\n", ctrl_ifname);
+		printf("Connected to interface '%s'.\n", ctrl_ifname);
 	} else {
 		printf("Could not connect to interface '%s' - re-trying\n",
 		       ctrl_ifname);
@@ -4004,6 +4009,10 @@
 		wpa_cli_exec(action_file, ifname, pos);
 	} else if (str_starts(pos, WPS_EVENT_ACTIVE)) {
 		wpa_cli_exec(action_file, ifname, pos);
+	} else if (str_starts(pos, WPS_EVENT_PIN_ACTIVE)) {
+		wpa_cli_exec(action_file, ifname, pos);
+	} else if (str_starts(pos, WPS_EVENT_CANCEL)) {
+		wpa_cli_exec(action_file, ifname, pos);
 	} else if (str_starts(pos, WPS_EVENT_TIMEOUT)) {
 		wpa_cli_exec(action_file, ifname, pos);
 	} else if (str_starts(pos, WPS_EVENT_FAIL)) {
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp
index 3bcf2f5..0a0b3ff 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp
@@ -476,7 +476,9 @@
 		add_station(info);
 
 		reply_len = sizeof(reply) - 1;
-		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
+		res = snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
+		if (res < 0 || (size_t) res >= sizeof(cmd))
+			break;
 		res = wpagui->ctrlRequest(cmd, reply, &reply_len);
 	} while (res >= 0);
 }
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index a0aa05e..9404ab4 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -12,6 +12,8 @@
 
 #include <cstdio>
 #include <unistd.h>
+#include <chrono>
+#include <thread>
 #include <QMessageBox>
 #include <QCloseEvent>
 #include <QImageReader>
@@ -713,9 +715,22 @@
 			   strstr(flags, "[DISABLED]") == NULL)
 			first_active = networkSelect->count() - 1;
 
-		if (last)
-			break;
 		start = end + 1;
+		if (*start && strchr(start, '\n'))
+			continue;
+
+		/* avoid race conditions */
+		std::this_thread::sleep_for(std::chrono::milliseconds(200));
+		QString cmd("LIST_NETWORKS LAST_ID=");
+		cmd.append(id);
+		if (ctrlRequest(cmd.toLocal8Bit().constData(), buf, &len) < 0)
+			break;
+
+		buf[len] = '\0';
+		start = strchr(buf, '\n');
+		if (!start)
+			break;
+		start++;
 	}
 
 	if (networkSelect->count() > 1)
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index f197352..c5d7168 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -391,6 +391,7 @@
 {
 	struct privsep_cmd_set_key *params;
 	int res;
+	struct wpa_driver_set_key_params p;
 
 	if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
 		return;
@@ -402,14 +403,19 @@
 
 	params = buf;
 
-	res = iface->driver->set_key(iface->ifname, iface->drv_priv,
-				     params->alg,
-				     params->addr, params->key_idx,
-				     params->set_tx,
-				     params->seq_len ? params->seq : NULL,
-				     params->seq_len,
-				     params->key_len ? params->key : NULL,
-				     params->key_len);
+	os_memset(&p, 0, sizeof(p));
+	p.ifname = iface->ifname;
+	p.alg = params->alg;
+	p.addr = params->addr;
+	p.key_idx = params->key_idx;
+	p.set_tx = params->set_tx;
+	p.seq = params->seq_len ? params->seq : NULL;
+	p.seq_len = params->seq_len;
+	p.key = params->key_len ? params->key : NULL;
+	p.key_len = params->key_len;
+	p.key_flag = params->key_flag;
+
+	res = iface->driver->set_key(iface->drv_priv, &p);
 	wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
 }
 
@@ -1184,14 +1190,15 @@
 
 static void usage(void)
 {
-	printf("wpa_priv v" VERSION_STR "\n"
+	printf("wpa_priv v%s\n"
 	       "Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
 	       "contributors\n"
 	       "\n"
 	       "usage:\n"
 	       "  wpa_priv [-Bdd] [-c<ctrl dir>] [-P<pid file>] "
 	       "<driver:ifname> \\\n"
-	       "           [driver:ifname ...]\n");
+	       "           [driver:ifname ...]\n",
+	       VERSION_STR);
 }
 
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 73e63ab..d429496 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -130,6 +130,7 @@
 #endif /* CONFIG_OWE */
 
 
+#ifdef CONFIG_WEP
 /* Configure default/group WEP keys for static WEP */
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
@@ -142,11 +143,15 @@
 		set = 1;
 		wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
 				i, i == ssid->wep_tx_keyidx, NULL, 0,
-				ssid->wep_key[i], ssid->wep_key_len[i]);
+				ssid->wep_key[i], ssid->wep_key_len[i],
+				i == ssid->wep_tx_keyidx ?
+				KEY_FLAG_GROUP_RX_TX_DEFAULT :
+				KEY_FLAG_GROUP_RX_TX);
 	}
 
 	return set;
 }
+#endif /* CONFIG_WEP */
 
 
 int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -200,7 +205,8 @@
 	/* TODO: should actually remember the previously used seq#, both for TX
 	 * and RX from each STA.. */
 
-	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen,
+			      KEY_FLAG_GROUP_RX_TX_DEFAULT);
 	os_memset(key, 0, sizeof(key));
 	return ret;
 }
@@ -393,7 +399,9 @@
 void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 				       struct wpa_ssid *ssid)
 {
+#ifdef CONFIG_WEP
 	int i;
+#endif /* CONFIG_WEP */
 
 	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
 		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -411,6 +419,7 @@
 	wpa_s->group_cipher = WPA_CIPHER_NONE;
 	wpa_s->mgmt_group_cipher = 0;
 
+#ifdef CONFIG_WEP
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
 		if (ssid->wep_key_len[i] > 5) {
 			wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
@@ -422,6 +431,7 @@
 			break;
 		}
 	}
+#endif /* CONFIG_WEP */
 
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
@@ -477,6 +487,31 @@
 }
 
 
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+		return;
+	wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
+	wpa_bss_flush(wpa_s);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
+{
+	struct driver_signal_override *dso;
+
+	while ((dso = dl_list_first(&wpa_s->drv_signal_override,
+				    struct driver_signal_override, list))) {
+		dl_list_del(&dso->list);
+		os_free(dso);
+	}
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
 	int i;
@@ -502,10 +537,13 @@
 	wpa_s->last_assoc_req_wpa_ie = NULL;
 	os_free(wpa_s->extra_sae_rejected_groups);
 	wpa_s->extra_sae_rejected_groups = NULL;
+	wpabuf_free(wpa_s->rsne_override_eapol);
+	wpa_s->rsne_override_eapol = NULL;
 	wpabuf_free(wpa_s->rsnxe_override_assoc);
 	wpa_s->rsnxe_override_assoc = NULL;
 	wpabuf_free(wpa_s->rsnxe_override_eapol);
 	wpa_s->rsnxe_override_eapol = NULL;
+	wpas_clear_driver_signal_override(wpa_s);
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	if (wpa_s->conf != NULL) {
@@ -552,6 +590,7 @@
 #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
 	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
 
 	wpas_wps_deinit(wpa_s);
 
@@ -708,12 +747,17 @@
 		if (wpa_s->keys_cleared & BIT(i))
 			continue;
 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-				NULL, 0);
+				NULL, 0, KEY_FLAG_GROUP);
 	}
-	if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+	/* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
+	if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
 	    !is_zero_ether_addr(addr)) {
-		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
-				0);
+		if (!(wpa_s->keys_cleared & BIT(0)))
+			wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL,
+					0, NULL, 0, KEY_FLAG_PAIRWISE);
+		if (!(wpa_s->keys_cleared & BIT(15)))
+			wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL,
+					0, NULL, 0, KEY_FLAG_PAIRWISE);
 		/* MLME-SETPROTECTION.request(None) */
 		wpa_drv_mlme_setprotection(
 			wpa_s, addr,
@@ -1242,7 +1286,7 @@
 			      u8 *wpa_ie, size_t *wpa_ie_len)
 {
 	struct wpa_ie_data ie;
-	int sel, proto;
+	int sel, proto, sae_pwe;
 	const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
 
 	if (bss) {
@@ -1421,13 +1465,18 @@
 #endif /* CONFIG_NO_WPA */
 
 	sel = ie.key_mgmt & ssid->key_mgmt;
-	wpa_dbg(wpa_s, MSG_DEBUG,
-		"WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
-		ie.key_mgmt, ssid->key_mgmt, sel);
 #ifdef CONFIG_SAE
 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
 		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
 #endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+	if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
+				  WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
+		sel &= ~WPA_KEY_MGMT_FT;
+#endif /* CONFIG_IEEE80211R */
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
+		ie.key_mgmt, ssid->key_mgmt, sel);
 	if (0) {
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_SHA384
@@ -1587,7 +1636,34 @@
 #ifdef CONFIG_OCV
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
 #endif /* CONFIG_OCV */
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe);
+	sae_pwe = wpa_s->conf->sae_pwe;
+	if (ssid->sae_password_id && sae_pwe != 3)
+		sae_pwe = 1;
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+
+	/* Extended Key ID is only supported in infrastructure BSS so far */
+	if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
+	    (ssid->proto & WPA_PROTO_RSN) &&
+	    ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+				     WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
+		int use_ext_key_id = 0;
+
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"WPA: Enable Extended Key ID support");
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID,
+				 wpa_s->conf->extended_key_id);
+		if (bss_rsn &&
+		    wpa_s->conf->extended_key_id &&
+		    wpa_s->pairwise_cipher != WPA_CIPHER_TKIP &&
+		    (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
+			use_ext_key_id = 1;
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID,
+				 use_ext_key_id);
+	} else {
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0);
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
+	}
 
 	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
@@ -1722,6 +1798,20 @@
 	} else
 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
+	if (ssid->mode != WPAS_MODE_IBSS &&
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+	    (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+	     (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+	      !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"Disable PTK0 rekey support - replaced with reconnect");
+		wpa_s->deny_ptk0_rekey = 1;
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1);
+	} else {
+		wpa_s->deny_ptk0_rekey = 0;
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
+	}
+
 	return 0;
 }
 
@@ -1963,7 +2053,8 @@
 	if (!password)
 		password = ssid->passphrase;
 
-	if (conf->sae_pwe == 0 || !password) {
+	if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password ||
+	    conf->sae_pwe == 3) {
 		/* PT derivation not needed */
 		sae_deinit_pt(ssid->pt);
 		ssid->pt = NULL;
@@ -2018,6 +2109,7 @@
 	int rand_style;
 
 	wpa_s->own_disconnect_req = 0;
+	wpa_s->own_reconnect_req = 0;
 
 	/*
 	 * If we are starting a new connection, any previously pending EAPOL
@@ -2031,6 +2123,7 @@
 	else
 		rand_style = ssid->mac_addr;
 
+	wpa_s->multi_ap_ie = 0;
 	wmm_ac_clear_saved_tspecs(wpa_s);
 	wpa_s->reassoc_same_bss = 0;
 	wpa_s->reassoc_same_ess = 0;
@@ -2314,6 +2407,10 @@
 	/* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
 	if (is_24ghz)
 		freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+#ifdef CONFIG_HE_OVERRIDES
+	if (is_24ghz && ssid->disable_he)
+		freq->he_enabled = 0;
+#endif /* CONFIG_HE_OVERRIDES */
 
 	/* Setup higher BW only for 5 GHz */
 	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
@@ -2336,8 +2433,10 @@
 
 #ifdef CONFIG_HT_OVERRIDES
 	if (ssid->disable_ht40) {
+#ifdef CONFIG_VHT_OVERRIDES
 		if (ssid->disable_vht)
 			return;
+#endif /* CONFIG_VHT_OVERRIDES */
 		goto skip_ht40;
 	}
 #endif /* CONFIG_HT_OVERRIDES */
@@ -2434,8 +2533,8 @@
 	if (!vht_freq.vht_enabled)
 		return;
 
-	/* Enable HE for VHT */
-	vht_freq.he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+	/* Enable HE with VHT for 5 GHz */
+	freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
 
 	/* setup center_freq1, bandwidth */
 	for (j = 0; j < ARRAY_SIZE(vht80); j++) {
@@ -2510,6 +2609,12 @@
 #endif /* CONFIG_HT_OVERRIDES */
 	}
 
+#ifdef CONFIG_HE_OVERRIDES
+	if (ssid->disable_he) {
+		vht_freq.he_enabled = 0;
+		freq->he_enabled = 0;
+	}
+#endif /* CONFIG_HE_OVERRIDES */
 	if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
 				    freq->channel, ssid->enable_edmg,
 				    ssid->edmg_channel, freq->ht_enabled,
@@ -2828,7 +2933,7 @@
 #endif /* CONFIG_P2P */
 
 	if (bss) {
-		wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
+		wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss,
 						    wpa_ie + wpa_ie_len,
 						    max_wpa_ie_len -
 						    wpa_ie_len);
@@ -2977,7 +3082,8 @@
 
 #ifdef CONFIG_DPP2
 	if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
-	    ssid->dpp_netaccesskey) {
+	    ssid->dpp_netaccesskey &&
+	    ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
 		dpp_pfs_free(wpa_s->dpp_pfs);
 		wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
 					      ssid->dpp_netaccesskey_len);
@@ -3216,7 +3322,7 @@
 	if (hw_mode == NUM_HOSTAPD_MODES)
 		goto fail;
 
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode);
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0);
 	if (!mode)
 		goto fail;
 
@@ -3265,10 +3371,12 @@
 	struct wpa_supplicant *wpa_s = work->wpa_s;
 	u8 *wpa_ie;
 	const u8 *edmg_ie_oper;
-	int use_crypt, ret, i, bssid_changed;
+	int use_crypt, ret, bssid_changed;
 	unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
 	struct wpa_driver_associate_params params;
+#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
 	int wep_keys_set = 0;
+#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
 	int assoc_failed = 0;
 	struct wpa_ssid *old_ssid;
 	u8 prev_bssid[ETH_ALEN];
@@ -3375,10 +3483,12 @@
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
 		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
 			use_crypt = 0;
+#ifdef CONFIG_WEP
 		if (wpa_set_wep_keys(wpa_s, ssid)) {
 			use_crypt = 1;
 			wep_keys_set = 1;
 		}
+#endif /* CONFIG_WEP */
 	}
 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
 		use_crypt = 0;
@@ -3523,12 +3633,18 @@
 	wpa_s->auth_alg = params.auth_alg;
 	params.mode = ssid->mode;
 	params.bg_scan_period = ssid->bg_scan_period;
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i])
-			params.wep_key[i] = ssid->wep_key[i];
-		params.wep_key_len[i] = ssid->wep_key_len[i];
+#ifdef CONFIG_WEP
+	{
+		int i;
+
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (ssid->wep_key_len[i])
+				params.wep_key[i] = ssid->wep_key[i];
+			params.wep_key_len[i] = ssid->wep_key_len[i];
+		}
+		params.wep_tx_keyidx = ssid->wep_tx_keyidx;
 	}
-	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#endif /* CONFIG_WEP */
 
 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
 	    (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
@@ -3605,6 +3721,9 @@
 	params.vhtcaps_mask = &vhtcaps_mask;
 	wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+	wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HE_OVERRIDES */
 
 #ifdef CONFIG_P2P
 	/*
@@ -3686,11 +3805,13 @@
 		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
 	}
 
+#ifdef CONFIG_WEP
 	if (wep_keys_set &&
 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
 		/* Set static WEP keys again */
 		wpa_set_wep_keys(wpa_s, ssid);
 	}
+#endif /* CONFIG_WEP */
 
 	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
 		/*
@@ -3804,6 +3925,15 @@
 	wpa_supplicant_clear_connection(wpa_s, addr);
 }
 
+
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->own_reconnect_req = 1;
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+
+}
+
+
 static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
 					      struct wpa_ssid *ssid)
 {
@@ -4791,6 +4921,9 @@
 
 	dl_list_init(&wpa_s->bss_tmp_disallowed);
 	dl_list_init(&wpa_s->fils_hlp_req);
+#ifdef CONFIG_TESTING_OPTIONS
+	dl_list_init(&wpa_s->drv_signal_override);
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	return wpa_s;
 }
@@ -5153,6 +5286,19 @@
 #endif /* CONFIG_VHT_OVERRIDES */
 
 
+#ifdef CONFIG_HE_OVERRIDES
+void wpa_supplicant_apply_he_overrides(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	struct wpa_driver_associate_params *params)
+{
+	if (!ssid)
+		return;
+
+	params->disable_he = ssid->disable_he;
+}
+#endif /* CONFIG_HE_OVERRIDES */
+
+
 static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
 {
 #ifdef PCSC_FUNCS
@@ -6095,7 +6241,6 @@
 		wpa_s->drv_capa_known = 1;
 		wpa_s->drv_flags = capa.flags;
 		wpa_s->drv_enc = capa.enc;
-		wpa_s->drv_smps_modes = capa.smps_modes;
 		wpa_s->drv_rrm_flags = capa.rrm_flags;
 		wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
 		wpa_s->max_scan_ssids = capa.max_scan_ssids;
@@ -6319,11 +6464,17 @@
 
 	wpa_s->disconnected = 1;
 	if (wpa_s->drv_priv) {
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
+		/* Don't deauthenticate if WoWLAN is enabled */
+		if (!wpa_drv_get_wowlan(wpa_s)) {
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
-		wpa_drv_set_countermeasures(wpa_s, 0);
-		wpa_clear_keys(wpa_s, NULL);
+			wpa_drv_set_countermeasures(wpa_s, 0);
+			wpa_clear_keys(wpa_s, NULL);
+		} else {
+			wpa_msg(wpa_s, MSG_INFO,
+				"Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
+		}
 	}
 
 	wpa_supplicant_cleanup(wpa_s);
@@ -6704,7 +6855,7 @@
 
 	if (params->wpa_debug_file_path)
 		wpa_debug_open_file(params->wpa_debug_file_path);
-	else
+	if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
 		wpa_debug_setup_stdout();
 	if (params->wpa_debug_syslog)
 		wpa_debug_open_syslog();
@@ -6772,7 +6923,7 @@
 	wpa_debug_timestamp = global->params.wpa_debug_timestamp =
 		params->wpa_debug_timestamp;
 
-	wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+	wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR);
 
 	if (eloop_init()) {
 		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
@@ -7036,7 +7187,7 @@
 	 * There is no point in blacklisting the AP if this event is
 	 * generated based on local request to disconnect.
 	 */
-	if (wpa_s->own_disconnect_req) {
+	if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
 		wpa_s->own_disconnect_req = 0;
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"Ignore connection failure due to local request to disconnect");
@@ -7301,8 +7452,10 @@
 
 int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
+#ifdef CONFIG_WEP
 	int i;
 	unsigned int drv_enc;
+#endif /* CONFIG_WEP */
 
 	if (wpa_s->p2p_mgmt)
 		return 1; /* no normal network profiles on p2p_mgmt interface */
@@ -7313,6 +7466,7 @@
 	if (ssid->disabled)
 		return 1;
 
+#ifdef CONFIG_WEP
 	if (wpa_s->drv_capa_known)
 		drv_enc = wpa_s->drv_enc;
 	else
@@ -7330,6 +7484,7 @@
 			continue;
 		return 1; /* invalid WEP key */
 	}
+#endif /* CONFIG_WEP */
 
 	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
 	    (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
@@ -7727,12 +7882,17 @@
 
 
 struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
-				   u16 num_modes, enum hostapd_hw_mode mode)
+				   u16 num_modes, enum hostapd_hw_mode mode,
+				   int is_6ghz)
 {
 	u16 i;
 
 	for (i = 0; i < num_modes; i++) {
-		if (modes[i].mode == mode)
+		if (modes[i].mode != mode ||
+		    !modes[i].num_channels || !modes[i].channels)
+			continue;
+		if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) ||
+		    (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq)))
 			return &modes[i];
 	}
 
@@ -7909,3 +8069,87 @@
 
 	return 0;
 }
+
+
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+			struct wpa_signal_info *si)
+{
+	int res;
+
+	if (!wpa_s->driver->signal_poll)
+		return -1;
+
+	res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (res == 0) {
+		struct driver_signal_override *dso;
+
+		dl_list_for_each(dso, &wpa_s->drv_signal_override,
+				 struct driver_signal_override, list) {
+			if (os_memcmp(wpa_s->bssid, dso->bssid,
+				      ETH_ALEN) != 0)
+				continue;
+			wpa_printf(MSG_DEBUG,
+				   "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
+				   si->current_signal,
+				   dso->si_current_signal,
+				   si->avg_signal,
+				   dso->si_avg_signal,
+				   si->avg_beacon_signal,
+				   dso->si_avg_beacon_signal,
+				   si->current_noise,
+				   dso->si_current_noise);
+			si->current_signal = dso->si_current_signal;
+			si->avg_signal = dso->si_avg_signal;
+			si->avg_beacon_signal = dso->si_avg_beacon_signal;
+			si->current_noise = dso->si_current_noise;
+			break;
+		}
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	return res;
+}
+
+
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_scan_results *scan_res;
+#ifdef CONFIG_TESTING_OPTIONS
+	size_t idx;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (!wpa_s->driver->get_scan_results2)
+		return NULL;
+
+	scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+
+#ifdef CONFIG_TESTING_OPTIONS
+	for (idx = 0; scan_res && idx < scan_res->num; idx++) {
+		struct driver_signal_override *dso;
+		struct wpa_scan_res *res = scan_res->res[idx];
+
+		dl_list_for_each(dso, &wpa_s->drv_signal_override,
+				 struct driver_signal_override, list) {
+			if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
+				continue;
+			wpa_printf(MSG_DEBUG,
+				   "Override driver scan signal level %d->%d for "
+				   MACSTR,
+				   res->level, dso->scan_level,
+				   MAC2STR(res->bssid));
+			res->flags |= WPA_SCAN_QUAL_INVALID;
+			if (dso->scan_level < 0)
+				res->flags |= WPA_SCAN_LEVEL_DBM;
+			else
+				res->flags &= ~WPA_SCAN_LEVEL_DBM;
+			res->level = dso->scan_level;
+			break;
+		}
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	return scan_res;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 328f91a..f242c3a 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -94,11 +94,8 @@
 # 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to
 #    the currently enabled networks are found, a new network (IBSS or AP mode
 #    operation) may be initialized (if configured) (default)
-# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
-#    parameters (e.g., WPA IE generation); this mode can also be used with
-#    non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
-#    APs (i.e., external program needs to control association). This mode must
-#    also be used when using wired Ethernet drivers (including MACsec).
+# 0: This mode must only be used when using wired Ethernet drivers
+#    (including MACsec).
 # 2: like 0, but associate with APs using security policy and SSID (but not
 #    BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
 #    enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -106,8 +103,8 @@
 #    the driver reports successful association; each network block should have
 #    explicit security policy (i.e., only one option in the lists) for
 #    key_mgmt, pairwise, group, proto variables
-# Note: ap_scan=2 should not be used with the nl80211 driver interface (the
-# current Linux interface). ap_scan=1 is optimized work working with nl80211.
+# Note: ap_scan=0/2 should not be used with the nl80211 driver interface (the
+# current Linux interface). ap_scan=1 is the only option working with nl80211.
 # For finding networks using hidden SSID, scan_ssid=1 in the network block can
 # be used with nl80211.
 # When using IBSS or AP mode, ap_scan=2 mode can force the new network to be
@@ -426,11 +423,13 @@
 #sae_groups=19 20 21
 
 # SAE mechanism for PWE derivation
-# 0 = hunting-and-pecking loop only (default)
-# 1 = hash-to-element only
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
 # 2 = both hunting-and-pecking loop and hash-to-element enabled
 # Note: The default value is likely to change from 0 to 2 once the new
 # hash-to-element mechanism has received more interoperability testing.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
 #sae_pwe=0
 
 # Default value for DTIM period (if not overridden in network block)
@@ -803,6 +802,11 @@
 # Set BIT(1) to Enable OCE in STA-CFON mode
 #oce=1
 
+# Extended Key ID support for Individually Addressed frames
+# 0 = force off: Do not use Extended Key ID (default)
+# 1 = auto: Activate Extended Key ID support if the driver supports it
+#extended_key_id=0
+
 # network block
 #
 # Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -1102,6 +1106,18 @@
 # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
 # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
 #
+# wpa_deny_ptk0_rekey: Workaround for PTK rekey issues
+# PTK0 rekeys (using only one Key ID value for pairwise keys) can degrade the
+# security and stability with some cards.
+# To avoid the issues wpa_supplicant can replace those PTK rekeys (including
+# EAP reauthentications) with fast reconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+#	this operation without issues
+# 2 = never allow problematic PTK0 rekeys
+#
 # group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
 # as the dot11RSNAConfigGroupRekeyTime parameter when operating in
 # Authenticator role in IBSS, or in AP and mesh modes.
@@ -1445,6 +1461,12 @@
 # 1-65535 = DH Group to use for FILS PFS
 #fils_dh_group=0
 
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
 # MAC address policy
 # 0 = use permanent MAC address
 # 1 = use random MAC address for each ESS connection
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 967298b..8b1d0d0 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -47,6 +47,9 @@
 struct wpas_dbus_priv;
 struct wpas_hidl_priv;
 
+/* How many seconds to consider old scan results valid for association. */
+#define SCAN_RES_VALID_FOR_CONNECT 5
+
 /**
  * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
  */
@@ -280,6 +283,7 @@
 	struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
 	int p2p_disabled;
 	int cross_connection;
+	int p2p_long_listen; /* remaining time in long Listen state in ms */
 	struct wpa_freq_range_list p2p_disallow_freq;
 	struct wpa_freq_range_list p2p_go_avoid_freq;
 	enum wpa_conc_pref {
@@ -477,6 +481,16 @@
 	struct wpabuf *pkt;
 };
 
+struct driver_signal_override {
+	struct dl_list list;
+	u8 bssid[ETH_ALEN];
+	int si_current_signal;
+	int si_avg_signal;
+	int si_avg_beacon_signal;
+	int si_current_noise;
+	int scan_level;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -540,6 +554,7 @@
 
 	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
 	int pairwise_cipher;
+	int deny_ptk0_rekey;
 	int group_cipher;
 	int key_mgmt;
 	int wpa_proto;
@@ -592,8 +607,8 @@
 	  * results.
 	  */
 	struct wpa_bss **last_scan_res;
-	unsigned int last_scan_res_used;
-	unsigned int last_scan_res_size;
+	size_t last_scan_res_used;
+	size_t last_scan_res_size;
 	struct os_reltime last_scan;
 
 	const struct wpa_driver_ops *driver;
@@ -700,6 +715,7 @@
 	int scan_id[MAX_SCAN_ID];
 	unsigned int scan_id_count;
 	u8 next_scan_bssid[ETH_ALEN];
+	unsigned int next_scan_bssid_wildcard_ssid:1;
 
 	struct wpa_ssid_value *ssids_from_scan_req;
 	unsigned int num_ssids_from_scan_req;
@@ -710,7 +726,6 @@
 
 	u64 drv_flags;
 	unsigned int drv_enc;
-	unsigned int drv_smps_modes;
 	unsigned int drv_rrm_flags;
 
 	/*
@@ -880,7 +895,6 @@
 		P2P_GROUP_INTERFACE_CLIENT
 	} p2p_group_interface;
 	struct p2p_group *p2p_group;
-	int p2p_long_listen; /* remaining time in long Listen state in ms */
 	char p2p_pin[10];
 	int p2p_wps_method;
 	u8 p2p_auth_invite[ETH_ALEN];
@@ -1064,6 +1078,7 @@
 	unsigned int wmm_ac_supported:1;
 	unsigned int ext_work_in_progress:1;
 	unsigned int own_disconnect_req:1;
+	unsigned int own_reconnect_req:1;
 	unsigned int ignore_post_flush_scan_res:1;
 
 #define MAC_ADDR_RAND_SCAN       BIT(0)
@@ -1126,6 +1141,7 @@
 	unsigned int p2p_go_csa_on_inv:1;
 	unsigned int ignore_auth_resp:1;
 	unsigned int ignore_assoc_disallow:1;
+	unsigned int disable_sa_query:1;
 	unsigned int testing_resend_assoc:1;
 	unsigned int ignore_sae_h2e_only:1;
 	struct wpabuf *sae_commit_override;
@@ -1136,8 +1152,10 @@
 	size_t last_tk_len;
 	struct wpabuf *last_assoc_req_wpa_ie;
 	int *extra_sae_rejected_groups;
+	struct wpabuf *rsne_override_eapol;
 	struct wpabuf *rsnxe_override_assoc;
 	struct wpabuf *rsnxe_override_eapol;
+	struct dl_list drv_signal_override;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1264,6 +1282,15 @@
 	size_t dpp_last_ssid_len;
 #ifdef CONFIG_DPP2
 	struct dpp_pfs *dpp_pfs;
+	int dpp_pfs_fallback;
+	struct wpabuf *dpp_presence_announcement;
+	struct dpp_bootstrap_info *dpp_chirp_bi;
+	int dpp_chirp_freq;
+	int *dpp_chirp_freqs;
+	int dpp_chirp_iter;
+	int dpp_chirp_round;
+	int dpp_chirp_scan_done;
+	int dpp_chirp_listen;
 #endif /* CONFIG_DPP2 */
 #ifdef CONFIG_TESTING_OPTIONS
 	char *dpp_config_obj_override;
@@ -1280,6 +1307,9 @@
 	unsigned int enabled_4addr_mode:1;
 	unsigned int multi_bss_support:1;
 	unsigned int drv_authorized_port:1;
+	unsigned int multi_ap_ie:1;
+	unsigned int multi_ap_backhaul:1;
+	unsigned int multi_ap_fronthaul:1;
 };
 
 
@@ -1290,6 +1320,9 @@
 void wpa_supplicant_apply_vht_overrides(
 	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
 	struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_he_overrides(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	struct wpa_driver_associate_params *params);
 
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -1321,6 +1354,7 @@
 void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 				   u16 reason_code);
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s);
 
 struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
@@ -1386,6 +1420,8 @@
 int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
 void add_freq(int *freqs, int *num_freqs, int freq);
 
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+			 u8 *op_class, u8 *chan, u8 *phy_type);
 void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
 void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
 				   const u8 *report, size_t report_len);
@@ -1408,6 +1444,7 @@
 				 struct scan_info *info);
 void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
 void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx);
 
 
 /* MBO functions */
@@ -1444,7 +1481,7 @@
 				 u8 channel, u8 bw);
 size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
 			     struct wpa_ssid *ssid,
-			     int freq, u8 *pos, size_t len);
+			     struct wpa_bss *bss, u8 *pos, size_t len);
 int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s);
 
 int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
@@ -1567,7 +1604,8 @@
 int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd);
 
 struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
-				   u16 num_modes, enum hostapd_hw_mode mode);
+				   u16 num_modes, enum hostapd_hw_mode mode,
+				   int is_6ghz);
 
 void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			  unsigned int sec, int rssi_threshold);
@@ -1588,4 +1626,6 @@
 int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
 int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
 
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
+
 #endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index d80b8f2..6bd271e 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -112,6 +112,14 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
+		int encrypt = wpa_s->wpa &&
+			wpa_sm_has_ptk_installed(wpa_s->wpa);
+
+		return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+					       !encrypt);
+	}
+
 	if (wpa_s->l2) {
 		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
 	}
@@ -219,6 +227,7 @@
 }
 
 
+#ifdef CONFIG_WEP
 /**
  * wpa_eapol_set_wep_key - set WEP key for the driver
  * @ctx: Pointer to wpa_supplicant data (wpa_s)
@@ -242,8 +251,11 @@
 	}
 	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
 			       unicast ? wpa_s->bssid : NULL,
-			       keyidx, unicast, NULL, 0, key, keylen);
+			       keyidx, unicast, NULL, 0, key, keylen,
+			       unicast ? KEY_FLAG_PAIRWISE_RX_TX :
+			       KEY_FLAG_GROUP_RX_TX_DEFAULT);
 }
+#endif /* CONFIG_WEP */
 
 
 static void wpa_supplicant_aborted_cached(void *ctx)
@@ -340,8 +352,8 @@
 	wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
 			"handshake", pmk, pmk_len);
 
-	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
-			    pmk_len)) {
+	if (wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, pmk,
+			    pmk_len, KEY_FLAG_PMK)) {
 		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
 	}
 
@@ -386,6 +398,13 @@
 			curr = bss;
 			break;
 		}
+#ifdef CONFIG_OWE
+		if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+		    (bss->flags & WPA_BSS_OWE_TRANSITION)) {
+			curr = bss;
+			break;
+		}
+#endif /* CONFIG_OWE */
 	}
 
 	if (curr) {
@@ -476,6 +495,12 @@
 }
 
 
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+	wpa_supplicant_reconnect(wpa_s);
+}
+
+
 static void * wpa_supplicant_get_network_ctx(void *wpa_s)
 {
 	return wpa_supplicant_get_ssid(wpa_s);
@@ -492,7 +517,8 @@
 static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
 				  const u8 *addr, int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_flag key_flag)
 {
 	struct wpa_supplicant *wpa_s = _wpa_s;
 	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
@@ -507,7 +533,8 @@
 	}
 #endif /* CONFIG_TESTING_GET_GTK */
 #ifdef CONFIG_TESTING_OPTIONS
-	if (addr && !is_broadcast_ether_addr(addr)) {
+	if (addr && !is_broadcast_ether_addr(addr) &&
+	    !(key_flag & KEY_FLAG_MODIFY)) {
 		wpa_s->last_tk_alg = alg;
 		os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
 		wpa_s->last_tk_key_idx = key_idx;
@@ -517,7 +544,7 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
-			       key, key_len);
+			       key, key_len, key_flag);
 }
 
 
@@ -547,7 +574,8 @@
 static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
 				    const u8 *bssid, const u8 *pmkid,
 				    const u8 *fils_cache_id,
-				    const u8 *pmk, size_t pmk_len)
+				    const u8 *pmk, size_t pmk_len,
+				    u32 pmk_lifetime, u8 pmk_reauth_threshold)
 {
 	struct wpa_supplicant *wpa_s = _wpa_s;
 	struct wpa_ssid *ssid;
@@ -569,6 +597,8 @@
 	params.pmkid = pmkid;
 	params.pmk = pmk;
 	params.pmk_len = pmk_len;
+	params.pmk_lifetime = pmk_lifetime;
+	params.pmk_reauth_threshold = pmk_reauth_threshold;
 
 	return wpa_drv_add_pmkid(wpa_s, &params);
 }
@@ -1047,6 +1077,21 @@
 }
 
 
+static int wpa_supplicant_eap_auth_start_cb(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey &&
+	    !wpa_sm_ext_key_id_active(wpa_s->wpa)) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"WPA: PTK0 rekey not allowed, reconnecting");
+		wpa_supplicant_reconnect(wpa_s);
+		return -1;
+	}
+	return 0;
+}
+
+
 static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -1102,7 +1147,9 @@
 	ctx->preauth = 0;
 	ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
 	ctx->eapol_send = wpa_supplicant_eapol_send;
+#ifdef CONFIG_WEP
 	ctx->set_wep_key = wpa_eapol_set_wep_key;
+#endif /* CONFIG_WEP */
 #ifndef CONFIG_NO_CONFIG_BLOBS
 	ctx->set_config_blob = wpa_supplicant_set_config_blob;
 	ctx->get_config_blob = wpa_supplicant_get_config_blob;
@@ -1125,6 +1172,7 @@
 	ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
 	ctx->status_cb = wpa_supplicant_status_cb;
 	ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
+	ctx->confirm_auth_cb = wpa_supplicant_eap_auth_start_cb;
 	ctx->set_anon_id = wpa_supplicant_set_anon_id;
 	ctx->cb_ctx = wpa_s;
 	wpa_s->eapol = eapol_sm_init(ctx);
@@ -1160,8 +1208,8 @@
 
 	if (wpa_s->conf->key_mgmt_offload &&
 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
-		return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
-				       NULL, 0, pmk, pmk_len);
+		return wpa_drv_set_key(wpa_s, 0, NULL, 0, 0,
+				       NULL, 0, pmk, pmk_len, KEY_FLAG_PMK);
 	else
 		return 0;
 }
@@ -1193,6 +1241,73 @@
 	return wpa_drv_channel_info(wpa_s, ci);
 }
 
+
+static void disable_wpa_wpa2(struct wpa_ssid *ssid)
+{
+	ssid->proto &= ~WPA_PROTO_WPA;
+	ssid->proto |= WPA_PROTO_RSN;
+	ssid->key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+			    WPA_KEY_MGMT_PSK_SHA256);
+	ssid->group_cipher &= ~WPA_CIPHER_TKIP;
+	if (!(ssid->group_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+				    WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)))
+		ssid->group_cipher |= WPA_CIPHER_CCMP;
+	ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+}
+
+
+static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
+{
+	struct wpa_supplicant *wpa_s = _wpa_s;
+	struct wpa_ssid *ssid;
+	int changed = 0;
+
+	wpa_msg(wpa_s, MSG_INFO, TRANSITION_DISABLE "%02x", bitmap);
+
+	ssid = wpa_s->current_ssid;
+	if (!ssid)
+		return;
+
+	if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
+	    wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+	    (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+	    (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+	     (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+		wpa_printf(MSG_DEBUG,
+			   "WPA3-Personal transition mode disabled based on AP notification");
+		disable_wpa_wpa2(ssid);
+		changed = 1;
+	}
+
+	if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) &&
+	    wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
+	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X |
+			       WPA_KEY_MGMT_FT_IEEE8021X |
+			       WPA_KEY_MGMT_IEEE8021X_SHA256)) &&
+	    (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+	     (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+		disable_wpa_wpa2(ssid);
+		changed = 1;
+	}
+
+	if ((bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) &&
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+	    (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+	    !ssid->owe_only) {
+		ssid->owe_only = 1;
+		changed = 1;
+	}
+
+	if (!changed)
+		return;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+	if (wpa_s->conf->update_config &&
+	    wpa_config_write(wpa_s->confname, wpa_s->conf))
+		wpa_printf(MSG_DEBUG, "Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
 #endif /* CONFIG_NO_WPA */
 
 
@@ -1211,6 +1326,7 @@
 	ctx->set_state = _wpa_supplicant_set_state;
 	ctx->get_state = _wpa_supplicant_get_state;
 	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+	ctx->reconnect = _wpa_supplicant_reconnect;
 	ctx->set_key = wpa_supplicant_set_key;
 	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
 	ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -1244,6 +1360,7 @@
 	ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
 	ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx;
 	ctx->channel_info = wpa_supplicant_channel_info;
+	ctx->transition_disable = wpa_supplicant_transition_disable;
 
 	wpa_s->wpa = wpa_sm_init(ctx);
 	if (wpa_s->wpa == NULL) {
@@ -1275,6 +1392,8 @@
 		conf.ssid = ssid->ssid;
 		conf.ssid_len = ssid->ssid_len;
 		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+		conf.wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
+		conf.owe_ptk_workaround = ssid->owe_ptk_workaround;
 #ifdef CONFIG_P2P
 		if (ssid->p2p_group && wpa_s->current_bss &&
 		    !wpa_s->p2p_disable_ip_addr_req) {
@@ -1297,6 +1416,7 @@
 			conf.fils_cache_id =
 				wpa_bss_get_fils_cache_id(wpa_s->current_bss);
 #endif /* CONFIG_FILS */
+		conf.beacon_prot = ssid->beacon_prot;
 	}
 	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
 }
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 8387fc3..e617158 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -532,6 +532,7 @@
 		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
 		if (wpa_s->conf->wps_cred_add_sae &&
 		    cred->key_len != 2 * PMK_LEN) {
+			ssid->auth_alg = 0;
 			ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
 			ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
 		}
@@ -1829,6 +1830,10 @@
 	wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
 		   "present in scan results; selected BSSID " MACSTR,
 		   MAC2STR(selected->bssid));
+	if (!is_zero_ether_addr(ssid->bssid))
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Network profile limited to accept only a single BSSID " MACSTR,
+			   MAC2STR(ssid->bssid));
 
 	/* Make sure that only one AP is in active PBC mode */
 	wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
@@ -1849,6 +1854,14 @@
 		    os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
 			continue;
 
+		if (!is_zero_ether_addr(ssid->bssid) &&
+		    os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
+				   " in active PBC mode due to local BSSID limitation",
+				   MAC2STR(ap->bssid));
+			continue;
+		}
+
 		wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
 			   MACSTR, MAC2STR(ap->bssid));
 		wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",