[automerger skipped] DO NOT MERGE - Merge pi-platform-release (PPRL.190205.001) into stage-aosp-master am: 7948ab66dc -s ours
am: 20859de2cb -s ours
am skip reason: subject contains skip directive

Change-Id: I4e27992c0f18b08333e7fd76a76a8421875fe698
diff --git a/.gitignore b/.gitignore
index 1d45c0a..e2ef98e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,5 @@
 *.patch
+hostapd/.cproject
+hostapd/.project
+wpa_supplicant/.cproject
+wpa_supplicant/.project
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 0224db1..9be3613 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -466,6 +466,7 @@
 L_CFLAGS += -DEAP_SERVER_PWD
 OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
 NEED_SHA256=y
+NEED_ECC=y
 endif
 
 ifdef CONFIG_EAP_EKE
@@ -649,22 +650,33 @@
 endif
 
 ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
 ifdef TLS_FUNCS
 OBJS += src/crypto/tls_gnutls.c
 LIBS += -lgnutls -lgpg-error
 endif
-OBJS += src/crypto/crypto_gnutls.c
-HOBJS += src/crypto/crypto_gnutls.c
+OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+HOBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
 ifdef NEED_FIPS186_2_PRF
 OBJS += src/crypto/fips_prf_internal.c
 OBJS += src/crypto/sha1-internal.c
 endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
 LIBS += -lgcrypt
 LIBS_h += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
 
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
@@ -820,8 +832,10 @@
 SHA1OBJS =
 ifdef NEED_SHA1
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 SHA1OBJS += src/crypto/sha1.c
 endif
+endif
 SHA1OBJS += src/crypto/sha1-prf.c
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += src/crypto/sha1-internal.c
@@ -845,8 +859,10 @@
 endif
 
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 OBJS += src/crypto/md5.c
 endif
+endif
 
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
@@ -882,8 +898,10 @@
 ifdef NEED_SHA256
 L_CFLAGS += -DCONFIG_SHA256
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 OBJS += src/crypto/sha256.c
 endif
+endif
 OBJS += src/crypto/sha256-prf.c
 ifdef CONFIG_INTERNAL_SHA256
 OBJS += src/crypto/sha256-internal.c
@@ -904,17 +922,21 @@
 ifdef NEED_SHA384
 L_CFLAGS += -DCONFIG_SHA384
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 OBJS += src/crypto/sha384.c
 endif
+endif
 OBJS += src/crypto/sha384-prf.c
 endif
 ifdef NEED_SHA512
 L_CFLAGS += -DCONFIG_SHA512
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
 OBJS += src/crypto/sha512.c
 endif
 endif
+endif
 OBJS += src/crypto/sha512-prf.c
 endif
 
@@ -1113,6 +1135,7 @@
 endif
 ifeq ($(HOSTAPD_USE_HIDL), y)
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.0
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.1
 LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhidltransport libhwbinder libutils
 LOCAL_STATIC_LIBRARIES += libhostapd_hidl
 endif
@@ -1155,12 +1178,13 @@
 LOCAL_CPPFLAGS := $(L_CPPFLAGS)
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.0
+HIDL_INTERFACE_VERSION = 1.1
 LOCAL_SRC_FILES := \
     hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
     hidl/$(HIDL_INTERFACE_VERSION)/hostapd.cpp
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.wifi.hostapd@1.0 \
+    android.hardware.wifi.hostapd@1.1 \
     libbase \
     libhidlbase \
     libhidltransport \
diff --git a/hostapd/Makefile b/hostapd/Makefile
index eb35672..2ce8b7d 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -489,6 +489,7 @@
 CFLAGS += -DEAP_SERVER_PWD
 OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
 NEED_SHA256=y
+NEED_ECC=y
 endif
 
 ifdef CONFIG_EAP_EKE
@@ -650,7 +651,29 @@
 NEED_SHA256=y
 endif
 
+ifeq ($(CONFIG_TLS), wolfssl)
+CONFIG_CRYPTO=wolfssl
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_wolfssl.o
+LIBS += -lwolfssl -lm
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+HOBJS += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+NEED_SHA256=y
+NEED_TLS_PRF_SHA256=y
+LIBS += -lwolfssl -lm
+LIBS_h += -lwolfssl -lm
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_h += -ldl
+endif
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
+CONFIG_CRYPTO=openssl
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_openssl.o
 OBJS += ../src/crypto/tls_openssl_ocsp.o
@@ -665,6 +688,7 @@
 NEED_TLS_PRF_SHA256=y
 LIBS += -lcrypto
 LIBS_h += -lcrypto
+LIBS_n += -lcrypto
 ifdef CONFIG_TLS_ADD_DL
 LIBS += -ldl
 LIBS_h += -ldl
@@ -676,22 +700,34 @@
 endif
 
 ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_gnutls.o
 LIBS += -lgnutls -lgpg-error
 endif
-OBJS += ../src/crypto/crypto_gnutls.o
-HOBJS += ../src/crypto/crypto_gnutls.o
+OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
 ifdef NEED_FIPS186_2_PRF
 OBJS += ../src/crypto/fips_prf_internal.o
 SHA1OBJS += ../src/crypto/sha1-internal.o
 endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
 LIBS += -lgcrypt
 LIBS_h += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
+LIBS_n += -lgcrypt
 CONFIG_INTERNAL_RC4=y
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
 
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
@@ -843,8 +879,10 @@
 endif
 
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-wrap.o
 endif
+endif
 ifdef NEED_AES_EAX
 AESOBJS += ../src/crypto/aes-eax.o
 NEED_AES_CTR=y
@@ -863,25 +901,31 @@
 endif
 ifdef NEED_AES_OMAC1
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-omac1.o
 endif
 endif
+endif
 ifdef NEED_AES_UNWRAP
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 NEED_AES_DEC=y
 AESOBJS += ../src/crypto/aes-unwrap.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_CBC
 NEED_AES_DEC=y
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-cbc.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_DEC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += ../src/crypto/aes-internal-dec.o
@@ -894,9 +938,13 @@
 ifdef NEED_SHA1
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1.o
 endif
 endif
+endif
+endif
 SHA1OBJS += ../src/crypto/sha1-prf.o
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += ../src/crypto/sha1-internal.o
@@ -905,8 +953,10 @@
 endif
 endif
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
 endif
+endif
 ifdef NEED_T_PRF
 SHA1OBJS += ../src/crypto/sha1-tprf.o
 endif
@@ -921,9 +971,13 @@
 
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/md5.o
 endif
 endif
+endif
+endif
 
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
@@ -939,6 +993,7 @@
 endif
 
 ifdef NEED_DES
+CFLAGS += -DCONFIG_DES
 ifdef CONFIG_INTERNAL_DES
 OBJS += ../src/crypto/des-internal.o
 endif
@@ -960,9 +1015,13 @@
 CFLAGS += -DCONFIG_SHA256
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha256.o
 endif
 endif
+endif
+endif
 OBJS += ../src/crypto/sha256-prf.o
 ifdef CONFIG_INTERNAL_SHA256
 OBJS += ../src/crypto/sha256-internal.o
@@ -984,18 +1043,26 @@
 CFLAGS += -DCONFIG_SHA384
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha384.o
 endif
 endif
+endif
+endif
 OBJS += ../src/crypto/sha384-prf.o
 endif
 ifdef NEED_SHA512
 CFLAGS += -DCONFIG_SHA512
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha512.o
 endif
 endif
+endif
+endif
 OBJS += ../src/crypto/sha512-prf.o
 endif
 
@@ -1034,10 +1101,12 @@
 HOBJS += $(SHA1OBJS)
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 HOBJS += ../src/crypto/md5.o
 endif
 endif
 endif
+endif
 
 ifdef CONFIG_RADIUS_SERVER
 CFLAGS += -DRADIUS_SERVER
@@ -1228,16 +1297,14 @@
 ifdef CONFIG_INTERNAL_MD5
 NOBJS += ../src/crypto/md5-internal.o
 endif
-NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+NOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+NOBJS += ../src/utils/os_$(CONFIG_OS).o
 NOBJS += ../src/utils/wpa_debug.o
 NOBJS += ../src/utils/wpabuf.o
 ifdef CONFIG_WPA_TRACE
 NOBJS += ../src/utils/trace.o
 LIBS_n += -lbfd
 endif
-ifdef TLS_FUNCS
-LIBS_n += -lcrypto
-endif
 
 HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
 HOBJS += ../src/crypto/aes-encblock.o
diff --git a/hostapd/android.config b/hostapd/android.config
index 5a24438..49cfe94 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -220,3 +220,9 @@
 
 # Enable support of Automatic Channel Selection
 CONFIG_ACS=y
+
+# Easy Connect (Device Provisioning Protocol - DPP)
+CONFIG_DPP=y
+
+# WPA3-Personal (SAE)
+CONFIG_SAE=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e2a470c..b26da71 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -113,7 +113,7 @@
 #endif /* CONFIG_NO_VLAN */
 
 
-static int hostapd_acl_comp(const void *a, const void *b)
+int hostapd_acl_comp(const void *a, const void *b)
 {
 	const struct mac_acl_entry *aa = a;
 	const struct mac_acl_entry *bb = b;
@@ -121,6 +121,44 @@
 }
 
 
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+			    int vlan_id, const u8 *addr)
+{
+	struct mac_acl_entry *newacl;
+
+	newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
+	if (!newacl) {
+		wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+		return -1;
+	}
+
+	*acl = newacl;
+	os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+	os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
+	(*acl)[*num].vlan_id.untagged = vlan_id;
+	(*acl)[*num].vlan_id.notempty = !!vlan_id;
+	(*num)++;
+
+	return 0;
+}
+
+
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+			    const u8 *addr)
+{
+	int i = 0;
+
+	while (i < *num) {
+		if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
+			os_remove_in_array(*acl, *num, sizeof(**acl), i);
+			(*num)--;
+		} else {
+			i++;
+		}
+	}
+}
+
+
 static int hostapd_config_read_maclist(const char *fname,
 				       struct mac_acl_entry **acl, int *num)
 {
@@ -128,7 +166,6 @@
 	char buf[128], *pos;
 	int line = 0;
 	u8 addr[ETH_ALEN];
-	struct mac_acl_entry *newacl;
 	int vlan_id;
 
 	f = fopen(fname, "r");
@@ -138,7 +175,7 @@
 	}
 
 	while (fgets(buf, sizeof(buf), f)) {
-		int i, rem = 0;
+		int rem = 0;
 
 		line++;
 
@@ -168,16 +205,7 @@
 		}
 
 		if (rem) {
-			i = 0;
-			while (i < *num) {
-				if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) ==
-				    0) {
-					os_remove_in_array(*acl, *num,
-							   sizeof(**acl), i);
-					(*num)--;
-				} else
-					i++;
-			}
+			hostapd_remove_acl_mac(acl, num, addr);
 			continue;
 		}
 		vlan_id = 0;
@@ -189,20 +217,10 @@
 		if (*pos != '\0')
 			vlan_id = atoi(pos);
 
-		newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
-		if (newacl == NULL) {
-			wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+		if (hostapd_add_acl_maclist(acl, num, vlan_id, addr) < 0) {
 			fclose(f);
 			return -1;
 		}
-
-		*acl = newacl;
-		os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
-		os_memset(&(*acl)[*num].vlan_id, 0,
-			  sizeof((*acl)[*num].vlan_id));
-		(*acl)[*num].vlan_id.untagged = vlan_id;
-		(*acl)[*num].vlan_id.notempty = !!vlan_id;
-		(*num)++;
 	}
 
 	fclose(f);
@@ -215,6 +233,62 @@
 
 
 #ifdef EAP_SERVER
+
+static int hostapd_config_eap_user_salted(struct hostapd_eap_user *user,
+					  const char *hash, size_t len,
+					  char **pos, int line,
+					  const char *fname)
+{
+	char *pos2 = *pos;
+
+	while (*pos2 != '\0' && *pos2 != ' ' && *pos2 != '\t' && *pos2 != '#')
+		pos2++;
+
+	if (pos2 - *pos < (int) (2 * (len + 1))) { /* at least 1 byte of salt */
+		wpa_printf(MSG_ERROR,
+			   "Invalid salted %s hash on line %d in '%s'",
+			   hash, line, fname);
+		return -1;
+	}
+
+	user->password = os_malloc(len);
+	if (!user->password) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to allocate memory for salted %s hash",
+			   hash);
+		return -1;
+	}
+
+	if (hexstr2bin(*pos, user->password, len) < 0) {
+		wpa_printf(MSG_ERROR,
+			   "Invalid salted password on line %d in '%s'",
+			   line, fname);
+		return -1;
+	}
+	user->password_len = len;
+	*pos += 2 * len;
+
+	user->salt_len = (pos2 - *pos) / 2;
+	user->salt = os_malloc(user->salt_len);
+	if (!user->salt) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to allocate memory for salted %s hash",
+			   hash);
+		return -1;
+	}
+
+	if (hexstr2bin(*pos, user->salt, user->salt_len) < 0) {
+		wpa_printf(MSG_ERROR,
+			   "Invalid salt for password on line %d in '%s'",
+			   line, fname);
+		return -1;
+	}
+
+	*pos = pos2;
+	return 0;
+}
+
+
 static int hostapd_config_read_eap_user(const char *fname,
 					struct hostapd_bss_config *conf)
 {
@@ -466,6 +540,24 @@
 			user->password_len = 16;
 			user->password_hash = 1;
 			pos = pos2;
+		} else if (os_strncmp(pos, "ssha1:", 6) == 0) {
+			pos += 6;
+			if (hostapd_config_eap_user_salted(user, "sha1", 20,
+							   &pos,
+							   line, fname) < 0)
+				goto failed;
+		} else if (os_strncmp(pos, "ssha256:", 8) == 0) {
+			pos += 8;
+			if (hostapd_config_eap_user_salted(user, "sha256", 32,
+							   &pos,
+							   line, fname) < 0)
+				goto failed;
+		} else if (os_strncmp(pos, "ssha512:", 8) == 0) {
+			pos += 8;
+			if (hostapd_config_eap_user_salted(user, "sha512", 64,
+							   &pos,
+							   line, fname) < 0)
+				goto failed;
 		} else {
 			pos2 = pos;
 			while (*pos2 != '\0' && *pos2 != ' ' &&
@@ -525,6 +617,7 @@
 
 	return ret;
 }
+
 #endif /* EAP_SERVER */
 
 
@@ -679,6 +772,10 @@
 			val |= WPA_KEY_MGMT_FT_PSK;
 		else if (os_strcmp(start, "FT-EAP") == 0)
 			val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+		else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
+			val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
 #endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_IEEE80211W
 		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
@@ -720,6 +817,10 @@
 		else if (os_strcmp(start, "DPP") == 0)
 			val |= WPA_KEY_MGMT_DPP;
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+		else if (os_strcmp(start, "OSEN") == 0)
+			val |= WPA_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
@@ -1136,6 +1237,8 @@
 		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
 		conf->ht40_plus_minus_allowed = 1;
 	}
+	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;
@@ -1358,6 +1461,44 @@
 }
 
 
+static int parse_venue_url(struct hostapd_bss_config *bss, char *pos,
+			    int line)
+{
+	char *sep;
+	size_t nlen;
+	struct hostapd_venue_url *url;
+	int ret = -1;
+
+	sep = os_strchr(pos, ':');
+	if (!sep)
+		goto fail;
+	*sep++ = '\0';
+
+	nlen = os_strlen(sep);
+	if (nlen > 254)
+		goto fail;
+
+	url = os_realloc_array(bss->venue_url, bss->venue_url_count + 1,
+			       sizeof(struct hostapd_venue_url));
+	if (!url)
+		goto fail;
+
+	bss->venue_url = url;
+	url = &bss->venue_url[bss->venue_url_count++];
+
+	url->venue_number = atoi(pos);
+	url->url_len = nlen;
+	os_memcpy(url->url, sep, nlen);
+
+	ret = 0;
+fail:
+	if (ret)
+		wpa_printf(MSG_ERROR, "Line %d: Invalid venue_url '%s'",
+			   line, pos);
+	return ret;
+}
+
+
 static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
 			       int line)
 {
@@ -1908,6 +2049,24 @@
 }
 
 
+static int hs20_parse_osu_nai2(struct hostapd_bss_config *bss,
+			       char *pos, int line)
+{
+	if (bss->last_osu == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
+		return -1;
+	}
+
+	os_free(bss->last_osu->osu_nai2);
+	bss->last_osu->osu_nai2 = os_strdup(pos);
+	if (bss->last_osu->osu_nai2 == NULL)
+		return -1;
+	bss->hs20_osu_providers_nai_count++;
+
+	return 0;
+}
+
+
 static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos,
 				      int line)
 {
@@ -1967,6 +2126,25 @@
 	return 0;
 }
 
+
+static int hs20_parse_operator_icon(struct hostapd_bss_config *bss, char *pos,
+				    int line)
+{
+	char **n;
+
+	n = os_realloc_array(bss->hs20_operator_icon,
+			     bss->hs20_operator_icon_count + 1, sizeof(char *));
+	if (!n)
+		return -1;
+	bss->hs20_operator_icon = n;
+	bss->hs20_operator_icon[bss->hs20_operator_icon_count] = os_strdup(pos);
+	if (!bss->hs20_operator_icon[bss->hs20_operator_icon_count])
+		return -1;
+	bss->hs20_operator_icon_count++;
+
+	return 0;
+}
+
 #endif /* CONFIG_HS20 */
 
 
@@ -2065,6 +2243,11 @@
 {
 	unsigned int flags = 0;
 
+	/* Disable TLS v1.3 by default for now to avoid interoperability issue.
+	 * This can be enabled by default once the implementation has been fully
+	 * completed and tested with other implementations. */
+	flags |= TLS_CONN_DISABLE_TLSv1_3;
+
 	if (os_strstr(val, "[ALLOW-SIGN-RSA-MD5]"))
 		flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
 	if (os_strstr(val, "[DISABLE-TIME-CHECKS]"))
@@ -2075,6 +2258,10 @@
 		flags |= TLS_CONN_DISABLE_TLSv1_1;
 	if (os_strstr(val, "[DISABLE-TLSv1.2]"))
 		flags |= TLS_CONN_DISABLE_TLSv1_2;
+	if (os_strstr(val, "[DISABLE-TLSv1.3]"))
+		flags |= TLS_CONN_DISABLE_TLSv1_3;
+	if (os_strstr(val, "[ENABLE-TLSv1.3]"))
+		flags &= ~TLS_CONN_DISABLE_TLSv1_3;
 	if (os_strstr(val, "[SUITEB]"))
 		flags |= TLS_CONN_SUITEB;
 	if (os_strstr(val, "[SUITEB-NO-ECDH]"))
@@ -2085,6 +2272,61 @@
 #endif /* EAP_SERVER */
 
 
+#ifdef CONFIG_SAE
+static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
+{
+	struct sae_password_entry *pw;
+	const char *pos = val, *pos2, *end = NULL;
+
+	pw = os_zalloc(sizeof(*pw));
+	if (!pw)
+		return -1;
+	os_memset(pw->peer_addr, 0xff, ETH_ALEN); /* default to wildcard */
+
+	pos2 = os_strstr(pos, "|mac=");
+	if (pos2) {
+		end = pos2;
+		pos2 += 5;
+		if (hwaddr_aton(pos2, pw->peer_addr) < 0)
+			goto fail;
+		pos = pos2 + ETH_ALEN * 3 - 1;
+	}
+
+	pos2 = os_strstr(pos, "|id=");
+	if (pos2) {
+		if (!end)
+			end = pos2;
+		pos2 += 4;
+		pw->identifier = os_strdup(pos2);
+		if (!pw->identifier)
+			goto fail;
+	}
+
+	if (!end) {
+		pw->password = os_strdup(val);
+		if (!pw->password)
+			goto fail;
+	} else {
+		pw->password = os_malloc(end - val + 1);
+		if (!pw->password)
+			goto fail;
+		os_memcpy(pw->password, val, end - val);
+		pw->password[end - val] = '\0';
+	}
+
+	pw->next = bss->sae_passwords;
+	bss->sae_passwords = pw;
+
+	return 0;
+fail:
+	str_clear_free(pw->password);
+	os_free(pw->identifier);
+	os_free(pw);
+	return -1;
+}
+#endif /* CONFIG_SAE */
+
+
 static int hostapd_config_fill(struct hostapd_config *conf,
 			       struct hostapd_bss_config *bss,
 			       const char *buf, char *pos, int line)
@@ -2314,8 +2556,10 @@
 	} else if (os_strcmp(buf, "pwd_group") == 0) {
 		bss->pwd_group = atoi(pos);
 #endif /* EAP_SERVER_PWD */
+#ifdef CONFIG_ERP
 	} else if (os_strcmp(buf, "eap_server_erp") == 0) {
 		bss->eap_server_erp = atoi(pos);
+#endif /* CONFIG_ERP */
 #endif /* EAP_SERVER */
 	} else if (os_strcmp(buf, "eap_message") == 0) {
 		char *term;
@@ -2643,6 +2887,20 @@
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "group_cipher") == 0) {
+		bss->group_cipher = hostapd_config_parse_cipher(line, pos);
+		if (bss->group_cipher == -1 || bss->group_cipher == 0)
+			return 1;
+		if (bss->group_cipher != WPA_CIPHER_TKIP &&
+		    bss->group_cipher != WPA_CIPHER_CCMP &&
+		    bss->group_cipher != WPA_CIPHER_GCMP &&
+		    bss->group_cipher != WPA_CIPHER_GCMP_256 &&
+		    bss->group_cipher != WPA_CIPHER_CCMP_256) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: unsupported group cipher suite '%s'",
+				   line, pos);
+			return 1;
+		}
 #ifdef CONFIG_RSN_PREAUTH
 	} else if (os_strcmp(buf, "rsn_preauth") == 0) {
 		bss->rsn_preauth = atoi(pos);
@@ -2672,7 +2930,12 @@
 			return 1;
 		}
 	} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+		/* DEPRECATED: Use ft_r0_key_lifetime instead. */
+		bss->r0_key_lifetime = atoi(pos) * 60;
+	} else if (os_strcmp(buf, "ft_r0_key_lifetime") == 0) {
 		bss->r0_key_lifetime = atoi(pos);
+	} else if (os_strcmp(buf, "r1_max_key_lifetime") == 0) {
+		bss->r1_max_key_lifetime = atoi(pos);
 	} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
 		bss->reassociation_deadline = atoi(pos);
 	} else if (os_strcmp(buf, "rkh_pos_timeout") == 0) {
@@ -2840,14 +3103,25 @@
 		}
 		bss->dtim_period = val;
 	} else if (os_strcmp(buf, "bss_load_update_period") == 0) {
-		bss->bss_load_update_period = atoi(pos);
-		if (bss->bss_load_update_period < 0 ||
-		    bss->bss_load_update_period > 100) {
+		int val = atoi(pos);
+
+		if (val < 0 || val > 100) {
 			wpa_printf(MSG_ERROR,
 				   "Line %d: invalid bss_load_update_period %d",
-				   line, bss->bss_load_update_period);
+				   line, val);
 			return 1;
 		}
+		bss->bss_load_update_period = val;
+	} else if (os_strcmp(buf, "chan_util_avg_period") == 0) {
+		int val = atoi(pos);
+
+		if (val < 0) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid chan_util_avg_period",
+				   line);
+			return 1;
+		}
+		bss->chan_util_avg_period = val;
 	} else if (os_strcmp(buf, "rts_threshold") == 0) {
 		conf->rts_threshold = atoi(pos);
 		if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
@@ -3293,6 +3567,8 @@
 #ifdef CONFIG_WNM_AP
 	} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
 		bss->wnm_sleep_mode = atoi(pos);
+	} else if (os_strcmp(buf, "wnm_sleep_mode_no_keys") == 0) {
+		bss->wnm_sleep_mode_no_keys = atoi(pos);
 	} else if (os_strcmp(buf, "bss_transition") == 0) {
 		bss->bss_transition = atoi(pos);
 #endif /* CONFIG_WNM_AP */
@@ -3333,6 +3609,9 @@
 	} else if (os_strcmp(buf, "venue_name") == 0) {
 		if (parse_venue_name(bss, pos, line) < 0)
 			return 1;
+	} else if (os_strcmp(buf, "venue_url") == 0) {
+		if (parse_venue_url(bss, pos, line) < 0)
+			return 1;
 	} else if (os_strcmp(buf, "network_auth_type") == 0) {
 		u8 auth_type;
 		u16 redirect_url_len;
@@ -3500,6 +3779,9 @@
 	} else if (os_strcmp(buf, "osu_nai") == 0) {
 		if (hs20_parse_osu_nai(bss, pos, line) < 0)
 			return 1;
+	} else if (os_strcmp(buf, "osu_nai2") == 0) {
+		if (hs20_parse_osu_nai2(bss, pos, line) < 0)
+			return 1;
 	} else if (os_strcmp(buf, "osu_method_list") == 0) {
 		if (hs20_parse_osu_method_list(bss, pos, line) < 0)
 			return 1;
@@ -3509,11 +3791,22 @@
 	} else if (os_strcmp(buf, "osu_service_desc") == 0) {
 		if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
 			return 1;
+	} else if (os_strcmp(buf, "operator_icon") == 0) {
+		if (hs20_parse_operator_icon(bss, pos, line) < 0)
+			return 1;
 	} else if (os_strcmp(buf, "subscr_remediation_url") == 0) {
 		os_free(bss->subscr_remediation_url);
 		bss->subscr_remediation_url = os_strdup(pos);
 	} else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
 		bss->subscr_remediation_method = atoi(pos);
+	} else if (os_strcmp(buf, "hs20_t_c_filename") == 0) {
+		os_free(bss->t_c_filename);
+		bss->t_c_filename = os_strdup(pos);
+	} else if (os_strcmp(buf, "hs20_t_c_timestamp") == 0) {
+		bss->t_c_timestamp = strtol(pos, NULL, 0);
+	} else if (os_strcmp(buf, "hs20_t_c_server_url") == 0) {
+		os_free(bss->t_c_server_url);
+		bss->t_c_server_url = os_strdup(pos);
 #endif /* CONFIG_HS20 */
 #ifdef CONFIG_MBO
 	} else if (os_strcmp(buf, "mbo") == 0) {
@@ -3595,10 +3888,15 @@
 	} 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, "sae_password") == 0) {
-		os_free(bss->sae_password);
-		bss->sae_password = os_strdup(pos);
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_SAE
+	} else if (os_strcmp(buf, "sae_password") == 0) {
+		if (parse_sae_password(bss, pos) < 0) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid sae_password",
+				   line);
+			return 1;
+		}
+#endif /* CONFIG_SAE */
 	} else if (os_strcmp(buf, "vendor_elements") == 0) {
 		if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
 			return 1;
@@ -3607,6 +3905,8 @@
 			return 1;
 	} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
 		bss->sae_anti_clogging_threshold = atoi(pos);
+	} else if (os_strcmp(buf, "sae_sync") == 0) {
+		bss->sae_sync = atoi(pos);
 	} else if (os_strcmp(buf, "sae_groups") == 0) {
 		if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
 			wpa_printf(MSG_ERROR,
@@ -3614,6 +3914,8 @@
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "sae_require_mfp") == 0) {
+		bss->sae_require_mfp = atoi(pos);
 	} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
 		int val = atoi(pos);
 		if (val < 0 || val > 255) {
@@ -3806,6 +4108,8 @@
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
+		bss->coloc_intf_reporting = atoi(pos);
 #endif /* CONFIG_OWE */
 	} else {
 		wpa_printf(MSG_ERROR,
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
index c98bdb6..9830f5a 100644
--- a/hostapd/config_file.h
+++ b/hostapd/config_file.h
@@ -13,5 +13,10 @@
 int hostapd_set_iface(struct hostapd_config *conf,
 		      struct hostapd_bss_config *bss, const char *field,
 		      char *value);
+int hostapd_acl_comp(const void *a, const void *b);
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+			    int vlan_id, const u8 *addr);
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+			    const u8 *addr);
 
 #endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index b3ef8d3..e539a09 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,6 +29,10 @@
 #include "common/version.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ctrl_iface_common.h"
+#ifdef CONFIG_DPP
+#include "common/dpp.h"
+#endif /* CONFIG_DPP */
+#include "common/wpa_ctrl.h"
 #include "crypto/tls.h"
 #include "drivers/driver.h"
 #include "eapol_auth/eapol_auth_sm.h"
@@ -77,9 +81,9 @@
 
 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
 				     struct sockaddr_storage *from,
-				     socklen_t fromlen)
+				     socklen_t fromlen, const char *input)
 {
-	return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen);
+	return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen, input);
 }
 
 
@@ -988,6 +992,42 @@
 	return ret;
 }
 
+
+static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
+					     const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	const char *pos;
+	unsigned int auto_report, timeout;
+
+	if (hwaddr_aton(cmd, addr)) {
+		wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
+		return -1;
+	}
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+			   " not found for Collocated Interference Request",
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+	auto_report = atoi(pos);
+	pos = os_strchr(pos, ' ');
+	if (!pos)
+		return -1;
+	pos++;
+	timeout = atoi(pos);
+
+	return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
+}
+
 #endif /* CONFIG_WNM_AP */
 
 
@@ -1027,6 +1067,14 @@
 			return pos - buf;
 		pos += ret;
 	}
+#ifdef CONFIG_SHA384
+	if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+		ret = os_snprintf(pos, end - pos, "FT-EAP-SHA384 ");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_SHA384 */
 #ifdef CONFIG_SAE
 	if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
 		ret = os_snprintf(pos, end - pos, "FT-SAE ");
@@ -1246,6 +1294,42 @@
 }
 
 
+static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
+{
+	struct sta_info *sta;
+	struct vlan_description vlan_id;
+
+	if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
+		return;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (!hostapd_maclist_found(hapd->conf->accept_mac,
+					   hapd->conf->num_accept_mac,
+					   sta->addr, &vlan_id) ||
+		    (vlan_id.notempty &&
+		     vlan_compare(&vlan_id, sta->vlan_desc)))
+			ap_sta_disconnect(hapd, sta, sta->addr,
+					  WLAN_REASON_UNSPECIFIED);
+	}
+}
+
+
+static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
+{
+	struct sta_info *sta;
+	struct vlan_description vlan_id;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (hostapd_maclist_found(hapd->conf->deny_mac,
+					  hapd->conf->num_deny_mac, sta->addr,
+					  &vlan_id) &&
+		    (!vlan_id.notempty ||
+		     !vlan_compare(&vlan_id, sta->vlan_desc)))
+			ap_sta_disconnect(hapd, sta, sta->addr,
+					  WLAN_REASON_UNSPECIFIED);
+	}
+}
+
 static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
 {
 	char *value;
@@ -1301,6 +1385,8 @@
 	} else if (os_strcasecmp(cmd,
 				 "dpp_ignore_netaccesskey_mismatch") == 0) {
 		hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
+	} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
+		dpp_test = atoi(value);
 #endif /* CONFIG_DPP */
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_MBO
@@ -1328,38 +1414,20 @@
 		hapd->dpp_configurator_params = os_strdup(value);
 #endif /* CONFIG_DPP */
 	} else {
-		struct sta_info *sta;
-		struct vlan_description vlan_id;
-
 		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
 		if (ret)
 			return ret;
 
 		if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
-			for (sta = hapd->sta_list; sta; sta = sta->next) {
-				if (hostapd_maclist_found(
-					    hapd->conf->deny_mac,
-					    hapd->conf->num_deny_mac, sta->addr,
-					    &vlan_id) &&
-				    (!vlan_id.notempty ||
-				     !vlan_compare(&vlan_id, sta->vlan_desc)))
-					ap_sta_disconnect(
-						hapd, sta, sta->addr,
-						WLAN_REASON_UNSPECIFIED);
-			}
-		} else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED &&
-			   os_strcasecmp(cmd, "accept_mac_file") == 0) {
-			for (sta = hapd->sta_list; sta; sta = sta->next) {
-				if (!hostapd_maclist_found(
-					    hapd->conf->accept_mac,
-					    hapd->conf->num_accept_mac,
-					    sta->addr, &vlan_id) ||
-				    (vlan_id.notempty &&
-				     vlan_compare(&vlan_id, sta->vlan_desc)))
-					ap_sta_disconnect(
-						hapd, sta, sta->addr,
-						WLAN_REASON_UNSPECIFIED);
-			}
+			hostapd_disassoc_deny_mac(hapd);
+		} else if (os_strcasecmp(cmd, "accept_mac_file") == 0) {
+			hostapd_disassoc_accept_mac(hapd);
+		} else if (os_strncmp(cmd, "wme_ac_", 7) == 0 ||
+			   os_strncmp(cmd, "wmm_ac_", 7) == 0) {
+			hapd->parameter_set_count++;
+			if (ieee802_11_update_beacons(hapd->iface))
+				wpa_printf(MSG_DEBUG,
+					   "Failed to update beacons with WMM parameters");
 		}
 	}
 
@@ -2204,6 +2272,11 @@
 		return ret;
 
 	for (i = 0; i < iface->num_bss; i++) {
+
+		/* Save CHAN_SWITCH VHT config */
+		hostapd_chan_switch_vht_config(
+			iface->bss[i], settings.freq_params.vht_enabled);
+
 		ret = hostapd_switch_channel(iface->bss[i], &settings);
 		if (ret) {
 			/* FIX: What do we do if CSA fails in the middle of
@@ -2679,6 +2752,80 @@
 }
 
 
+static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
+					  const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct vlan_description vlan_id;
+
+	if (!(*num))
+		return 0;
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
+		hostapd_remove_acl_mac(acl, num, addr);
+
+	return 0;
+}
+
+
+static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
+					      int *num)
+{
+	while (*num)
+		hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
+}
+
+
+static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
+					   char *buf, size_t buflen)
+{
+	int i = 0, len = 0, ret = 0;
+
+	if (!acl)
+		return 0;
+
+	while (i < num) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  MACSTR " VLAN_ID=%d\n",
+				  MAC2STR(acl[i].addr),
+				  acl[i].vlan_id.untagged);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		i++;
+		len += ret;
+	}
+	return len;
+}
+
+
+static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
+					  const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	struct vlan_description vlan_id;
+	int ret = 0, vlanid = 0;
+	const char *pos;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	pos = os_strstr(cmd, "VLAN_ID=");
+	if (pos)
+		vlanid = atoi(pos + 8);
+
+	if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
+		ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
+		if (ret != -1 && *acl)
+			qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+	}
+
+	return ret < 0 ? -1 : 0;
+}
+
+
 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
 					      char *buf, char *reply,
 					      int reply_size,
@@ -2696,6 +2843,8 @@
 	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
 		if (wpa_debug_reopen_file() < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+		wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
 	} else if (os_strcmp(buf, "STATUS") == 0) {
 		reply_len = hostapd_ctrl_iface_status(hapd, reply,
 						      reply_size);
@@ -2743,7 +2892,10 @@
 		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
 							reply_size);
 	} else if (os_strcmp(buf, "ATTACH") == 0) {
-		if (hostapd_ctrl_iface_attach(hapd, from, fromlen))
+		if (hostapd_ctrl_iface_attach(hapd, from, fromlen, NULL))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
+		if (hostapd_ctrl_iface_attach(hapd, from, fromlen, buf + 7))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "DETACH") == 0) {
 		if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
@@ -2845,6 +2997,9 @@
 	} else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
 		if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
+		if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
+			reply_len = -1;
 #endif /* CONFIG_WNM_AP */
 	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
 		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
@@ -2919,6 +3074,9 @@
 	} else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
 		if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
 			reply_len = -1;
+	} else if (os_strcmp(buf, "REKEY_GTK") == 0) {
+		if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
+			reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
 		if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -2973,6 +3131,46 @@
 						      reply_size);
 	} else if (os_strcmp(buf, "TERMINATE") == 0) {
 		eloop_terminate();
+	} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
+		if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
+			if (!hostapd_ctrl_iface_acl_add_mac(
+				    &hapd->conf->accept_mac,
+				    &hapd->conf->num_accept_mac, buf + 19))
+				hostapd_disassoc_accept_mac(hapd);
+			else
+				reply_len = -1;
+		} else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+			hostapd_ctrl_iface_acl_del_mac(
+				&hapd->conf->accept_mac,
+				&hapd->conf->num_accept_mac, buf + 19);
+		} else if (os_strcmp(buf + 11, "SHOW") == 0) {
+			reply_len = hostapd_ctrl_iface_acl_show_mac(
+				hapd->conf->accept_mac,
+				hapd->conf->num_accept_mac, reply, reply_size);
+		} else if (os_strcmp(buf + 11, "CLEAR") == 0) {
+			hostapd_ctrl_iface_acl_clear_list(
+				&hapd->conf->accept_mac,
+				&hapd->conf->num_accept_mac);
+		}
+	} else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
+		if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
+			if (!hostapd_ctrl_iface_acl_add_mac(
+				    &hapd->conf->deny_mac,
+				    &hapd->conf->num_deny_mac, buf + 17))
+				hostapd_disassoc_deny_mac(hapd);
+		} else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
+			hostapd_ctrl_iface_acl_del_mac(
+				&hapd->conf->deny_mac,
+				&hapd->conf->num_deny_mac, buf + 17);
+		} else if (os_strcmp(buf + 9, "SHOW") == 0) {
+			reply_len = hostapd_ctrl_iface_acl_show_mac(
+				hapd->conf->deny_mac,
+				hapd->conf->num_deny_mac, reply, reply_size);
+		} else if (os_strcmp(buf + 9, "CLEAR") == 0) {
+			hostapd_ctrl_iface_acl_clear_list(
+				&hapd->conf->deny_mac,
+				&hapd->conf->num_deny_mac);
+		}
 #ifdef CONFIG_DPP
 	} else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
 		res = hostapd_dpp_qr_code(hapd, buf + 12);
@@ -3012,6 +3210,12 @@
 	} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
 		if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
+		if (hostapd_dpp_listen(hapd, buf + 11) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
+		hostapd_dpp_stop(hapd);
+		hostapd_dpp_listen_stop(hapd);
 	} else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
 		res = hostapd_dpp_configurator_add(hapd, buf + 20);
 		if (res < 0) {
@@ -3024,6 +3228,13 @@
 	} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
 		if (hostapd_dpp_configurator_remove(hapd, buf + 24) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
+		if (hostapd_dpp_configurator_sign(hapd, buf + 22) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
+		reply_len = hostapd_dpp_configurator_get_key(hapd,
+							     atoi(buf + 25),
+							     reply, reply_size);
 	} else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
 		res = hostapd_dpp_pkex_add(hapd, buf + 12);
 		if (res < 0) {
@@ -3037,6 +3248,11 @@
 		if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
 			reply_len = -1;
 #endif /* CONFIG_DPP */
+#ifdef RADIUS_SERVER
+	} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
+		if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
+			reply_len = -1;
+#endif /* RADIUS_SERVER */
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -3487,9 +3703,10 @@
 
 static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
 					    struct sockaddr_storage *from,
-					    socklen_t fromlen)
+					    socklen_t fromlen, char *input)
 {
-	return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen);
+	return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen,
+				 input);
 }
 
 
@@ -3508,6 +3725,16 @@
 	wps_testing_dummy_cred = 0;
 	wps_corrupt_pkhash = 0;
 #endif /* CONFIG_WPS_TESTING */
+
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_DPP
+	dpp_test = DPP_TEST_DISABLED;
+#endif /* CONFIG_DPP */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_DPP
+	hostapd_dpp_deinit_global(interfaces);
+#endif /* CONFIG_DPP */
 }
 
 
@@ -3859,7 +4086,11 @@
 			reply_len = -1;
 	} else if (os_strcmp(buf, "ATTACH") == 0) {
 		if (hostapd_global_ctrl_iface_attach(interfaces, &from,
-						     fromlen))
+						     fromlen, NULL))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
+		if (hostapd_global_ctrl_iface_attach(interfaces, &from,
+						     fromlen, buf + 7))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "DETACH") == 0) {
 		if (hostapd_global_ctrl_iface_detach(interfaces, &from,
@@ -4175,6 +4406,18 @@
 }
 
 
+static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
+					    const char *buf)
+{
+	/* Enable Probe Request events based on explicit request.
+	 * Other events are enabled by default.
+	 */
+	if (str_starts(buf, RX_PROBE_REQUEST))
+		return !!(dst->events & WPA_EVENT_RX_PROBE_REQUEST);
+	return 1;
+}
+
+
 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
 				    enum wpa_msg_type type,
 				    const char *buf, size_t len)
@@ -4209,7 +4452,8 @@
 
 	idx = 0;
 	dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
-		if (level >= dst->debug_level) {
+		if ((level >= dst->debug_level) &&
+		     hostapd_ctrl_check_event_enabled(dst, buf)) {
 			sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
 				       &dst->addr, dst->addrlen);
 			msg.msg_name = &dst->addr;
diff --git a/hostapd/hidl/1.0/hidl.cpp b/hostapd/hidl/1.1/hidl.cpp
similarity index 93%
rename from hostapd/hidl/1.0/hidl.cpp
rename to hostapd/hidl/1.1/hidl.cpp
index a0dc50e..2051e7b 100644
--- a/hostapd/hidl/1.0/hidl.cpp
+++ b/hostapd/hidl/1.1/hidl.cpp
@@ -22,8 +22,8 @@
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::IPCThreadState;
-using android::hardware::wifi::hostapd::V1_0::IHostapd;
-using android::hardware::wifi::hostapd::V1_0::implementation::Hostapd;
+using android::hardware::wifi::hostapd::V1_1::IHostapd;
+using android::hardware::wifi::hostapd::V1_1::implementation::Hostapd;
 
 // This file is a bridge between the hostapd code written in 'C' and the HIDL
 // interface in C++. So, using "C" style static globals here!
diff --git a/hostapd/hidl/1.0/hidl.h b/hostapd/hidl/1.1/hidl.h
similarity index 100%
rename from hostapd/hidl/1.0/hidl.h
rename to hostapd/hidl/1.1/hidl.h
diff --git a/hostapd/hidl/1.0/hidl_return_util.h b/hostapd/hidl/1.1/hidl_return_util.h
similarity index 96%
rename from hostapd/hidl/1.0/hidl_return_util.h
rename to hostapd/hidl/1.1/hidl_return_util.h
index 1625dc2..d914ee2 100644
--- a/hostapd/hidl/1.0/hidl_return_util.h
+++ b/hostapd/hidl/1.1/hidl_return_util.h
@@ -16,7 +16,7 @@
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_return_util {
 
@@ -36,7 +36,7 @@
 
 }  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hidl/1.0/hostapd.cpp b/hostapd/hidl/1.1/hostapd.cpp
similarity index 67%
rename from hostapd/hidl/1.0/hostapd.cpp
rename to hostapd/hidl/1.1/hostapd.cpp
index 3cd78b3..0298537 100644
--- a/hostapd/hidl/1.0/hostapd.cpp
+++ b/hostapd/hidl/1.1/hostapd.cpp
@@ -33,7 +33,7 @@
 using android::base::RemoveFileIfExists;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
-using android::hardware::wifi::hostapd::V1_0::IHostapd;
+using android::hardware::wifi::hostapd::V1_1::IHostapd;
 
 std::string WriteHostapdConfig(
     const std::string& interface_name, const std::string& config)
@@ -126,26 +126,38 @@
 	}
 
 	std::string channel_config_as_string;
-	if (iface_params.channelParams.enableAcs) {
+	if (iface_params.V1_0.channelParams.enableAcs) {
+		std::string chanlist_as_string;
+		for (const auto &range :
+		     iface_params.channelParams.acsChannelRanges) {
+			if (range.start != range.end) {
+				chanlist_as_string +=
+					StringPrintf("%d-%d ", range.start, range.end);
+			} else {
+				chanlist_as_string += StringPrintf("%d ", range.start);
+			}
+		}
 		channel_config_as_string = StringPrintf(
 		    "channel=0\n"
-		    "acs_exclude_dfs=%d",
-		    iface_params.channelParams.acsShouldExcludeDfs);
+		    "acs_exclude_dfs=%d\n"
+		    "chanlist=%s",
+		    iface_params.V1_0.channelParams.acsShouldExcludeDfs,
+		    chanlist_as_string.c_str());
 	} else {
 		channel_config_as_string = StringPrintf(
-		    "channel=%d", iface_params.channelParams.channel);
+		    "channel=%d", iface_params.V1_0.channelParams.channel);
 	}
 
 	// Hw Mode String
 	std::string hw_mode_as_string;
 	std::string ht_cap_vht_oper_chwidth_as_string;
-	switch (iface_params.channelParams.band) {
+	switch (iface_params.V1_0.channelParams.band) {
 	case IHostapd::Band::BAND_2_4_GHZ:
 		hw_mode_as_string = "hw_mode=g";
 		break;
 	case IHostapd::Band::BAND_5_GHZ:
 		hw_mode_as_string = "hw_mode=a";
-		if (iface_params.channelParams.enableAcs) {
+		if (iface_params.V1_0.channelParams.enableAcs) {
 			ht_cap_vht_oper_chwidth_as_string =
 			    "ht_capab=[HT40+]\n"
 			    "vht_oper_chwidth=1";
@@ -153,7 +165,7 @@
 		break;
 	case IHostapd::Band::BAND_ANY:
 		hw_mode_as_string = "hw_mode=any";
-		if (iface_params.channelParams.enableAcs) {
+		if (iface_params.V1_0.channelParams.enableAcs) {
 			ht_cap_vht_oper_chwidth_as_string =
 			    "ht_capab=[HT40+]\n"
 			    "vht_oper_chwidth=1";
@@ -180,32 +192,61 @@
 	    "ignore_broadcast_ssid=%d\n"
 	    "wowlan_triggers=any\n"
 	    "%s\n",
-	    iface_params.ifaceName.c_str(), ssid_as_string.c_str(),
+	    iface_params.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
 	    channel_config_as_string.c_str(),
-	    iface_params.hwModeParams.enable80211N ? 1 : 0,
-	    iface_params.hwModeParams.enable80211AC ? 1 : 0,
+	    iface_params.V1_0.hwModeParams.enable80211N ? 1 : 0,
+	    iface_params.V1_0.hwModeParams.enable80211AC ? 1 : 0,
 	    hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
 	    nw_params.isHidden ? 1 : 0, encryption_config_as_string.c_str());
 }
+
+// hostapd core functions accept "C" style function pointers, so use global
+// functions to pass to the hostapd core function and store the corresponding
+// std::function methods to be invoked.
+//
+// NOTE: Using the pattern from the vendor HAL (wifi_legacy_hal.cpp).
+//
+// Callback to be invoked once setup is complete
+std::function<void(struct hostapd_data*)> on_setup_complete_internal_callback;
+void onAsyncSetupCompleteCb(void* ctx)
+{
+	struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+	if (on_setup_complete_internal_callback) {
+		on_setup_complete_internal_callback(iface_hapd);
+		// Invalidate this callback since we don't want this firing
+		// again.
+		on_setup_complete_internal_callback = nullptr;
+	}
+}
 }  // namespace
 
 namespace android {
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::call;
+using namespace android::hardware::wifi::hostapd::V1_0;
 
 Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces)
 {}
 
 Return<void> Hostapd::addAccessPoint(
+    const V1_0::IHostapd::IfaceParams& iface_params,
+    const NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
+{
+	return call(
+	    this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
+	    nw_params);
+}
+
+Return<void> Hostapd::addAccessPoint_1_1(
     const IfaceParams& iface_params, const NetworkParams& nw_params,
     addAccessPoint_cb _hidl_cb)
 {
 	return call(
-	    this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
+	    this, &Hostapd::addAccessPointInternal_1_1, _hidl_cb, iface_params,
 	    nw_params);
 }
 
@@ -216,19 +257,34 @@
 	    this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
 }
 
-Return<void> Hostapd::terminate() {
+Return<void> Hostapd::terminate()
+{
 	wpa_printf(MSG_INFO, "Terminating...");
 	eloop_terminate();
 	return Void();
 }
 
+Return<void> Hostapd::registerCallback(
+    const sp<IHostapdCallback>& callback, registerCallback_cb _hidl_cb)
+{
+	return call(
+	    this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
+}
+
 HostapdStatus Hostapd::addAccessPointInternal(
+    const V1_0::IHostapd::IfaceParams& iface_params,
+    const NetworkParams& nw_params)
+{
+	return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+HostapdStatus Hostapd::addAccessPointInternal_1_1(
     const IfaceParams& iface_params, const NetworkParams& nw_params)
 {
-	if (hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str())) {
+	if (hostapd_get_iface(interfaces_, iface_params.V1_0.ifaceName.c_str())) {
 		wpa_printf(
 		    MSG_ERROR, "Interface %s already present",
-		    iface_params.ifaceName.c_str());
+		    iface_params.V1_0.ifaceName.c_str());
 		return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
 	}
 	const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
@@ -237,13 +293,13 @@
 		return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
 	}
 	const auto conf_file_path =
-	    WriteHostapdConfig(iface_params.ifaceName, conf_params);
+	    WriteHostapdConfig(iface_params.V1_0.ifaceName, conf_params);
 	if (conf_file_path.empty()) {
 		wpa_printf(MSG_ERROR, "Failed to write config file");
 		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	std::string add_iface_param_str = StringPrintf(
-	    "%s config=%s", iface_params.ifaceName.c_str(),
+	    "%s config=%s", iface_params.V1_0.ifaceName.c_str(),
 	    conf_file_path.c_str());
 	std::vector<char> add_iface_param_vec(
 	    add_iface_param_str.begin(), add_iface_param_str.end() + 1);
@@ -254,12 +310,29 @@
 		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	struct hostapd_data* iface_hapd =
-	    hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str());
+	    hostapd_get_iface(interfaces_, iface_params.V1_0.ifaceName.c_str());
 	WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
+	// Register the setup complete callbacks
+	on_setup_complete_internal_callback =
+	    [this](struct hostapd_data* iface_hapd) {
+		    wpa_printf(
+			MSG_DEBUG, "AP interface setup completed - state %s",
+			hostapd_state_text(iface_hapd->iface->state));
+		    if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
+			    // Invoke the failure callback on all registered
+			    // clients.
+			    for (const auto& callback : callbacks_) {
+				    callback->onFailure(
+					iface_hapd->conf->iface);
+			    }
+		    }
+	    };
+	iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
+	iface_hapd->setup_complete_cb_ctx = iface_hapd;
 	if (hostapd_enable_iface(iface_hapd->iface) < 0) {
 		wpa_printf(
 		    MSG_ERROR, "Enabling interface %s failed",
-		    iface_params.ifaceName.c_str());
+		    iface_params.V1_0.ifaceName.c_str());
 		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	return {HostapdStatusCode::SUCCESS, ""};
@@ -278,8 +351,16 @@
 	}
 	return {HostapdStatusCode::SUCCESS, ""};
 }
+
+HostapdStatus Hostapd::registerCallbackInternal(
+    const sp<IHostapdCallback>& callback)
+{
+	callbacks_.push_back(callback);
+	return {HostapdStatusCode::SUCCESS, ""};
+}
+
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hidl/1.0/hostapd.h b/hostapd/hidl/1.1/hostapd.h
similarity index 64%
rename from hostapd/hidl/1.0/hostapd.h
rename to hostapd/hidl/1.1/hostapd.h
index 7985fd9..e2b4ba8 100644
--- a/hostapd/hidl/1.0/hostapd.h
+++ b/hostapd/hidl/1.1/hostapd.h
@@ -14,7 +14,8 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.1/IHostapdCallback.h>
 
 extern "C"
 {
@@ -28,15 +29,16 @@
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::hostapd::V1_0;
 
 /**
  * Implementation of the hostapd hidl object. This hidl
  * object is used core for global control operations on
  * hostapd.
  */
-class Hostapd : public V1_0::IHostapd
+class Hostapd : public V1_1::IHostapd
 {
 public:
 	Hostapd(hapd_interfaces* interfaces);
@@ -44,26 +46,39 @@
 
 	// Hidl methods exposed.
 	Return<void> addAccessPoint(
+	    const V1_0::IHostapd::IfaceParams& iface_params,
+	    const NetworkParams& nw_params, addAccessPoint_cb _hidl_cb) override;
+	Return<void> addAccessPoint_1_1(
 	    const IfaceParams& iface_params, const NetworkParams& nw_params,
 	    addAccessPoint_cb _hidl_cb) override;
 	Return<void> removeAccessPoint(
 	    const hidl_string& iface_name,
 	    removeAccessPoint_cb _hidl_cb) override;
 	Return<void> terminate() override;
+	Return<void> registerCallback(
+	    const sp<IHostapdCallback>& callback,
+	    registerCallback_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
 	HostapdStatus addAccessPointInternal(
-	    const IfaceParams& iface_params, const NetworkParams& nw_params);
+	    const V1_0::IHostapd::IfaceParams& iface_params,
+	    const NetworkParams& nw_params);
+	HostapdStatus addAccessPointInternal_1_1(
+	    const IfaceParams& IfaceParams, const NetworkParams& nw_params);
 	HostapdStatus removeAccessPointInternal(const std::string& iface_name);
+	HostapdStatus registerCallbackInternal(
+	    const sp<IHostapdCallback>& callback);
 
 	// Raw pointer to the global structure maintained by the core.
 	struct hapd_interfaces* interfaces_;
+	// Callbacks registered.
+	std::vector<sp<IHostapdCallback>> callbacks_;
 
 	DISALLOW_COPY_AND_ASSIGN(Hostapd);
 };
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
index 37a95c2..c8792d6 100644
--- a/hostapd/hostapd.android.rc
+++ b/hostapd/hostapd.android.rc
@@ -13,6 +13,7 @@
 
 service hostapd /vendor/bin/hw/hostapd
     interface android.hardware.wifi.hostapd@1.0::IHostapd default
+    interface android.hardware.wifi.hostapd@1.1::IHostapd default
     class main
     capabilities NET_ADMIN NET_RAW
     user wifi
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index f558855..a005217 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -511,6 +511,12 @@
 # Beacon and Probe Response frames.
 #bss_load_update_period=50
 
+# Channel utilization averaging period (in BUs)
+# This field is used to enable and configure channel utilization average
+# calculation with bss_load_update_period. This should be in multiples of
+# bss_load_update_period for more accurate calculation.
+#chan_util_avg_period=600
+
 # Fixed BSS Load value for testing purposes
 # This field can be used to configure hostapd to add a fixed BSS Load element
 # into Beacon and Probe Response frames for testing purposes. The format is
@@ -1185,6 +1191,8 @@
 #radius_das_port=3799
 #
 # DAS client (the host that can send Disconnect/CoA requests) and shared secret
+# Format: <IP address> <shared secret>
+# IP address 0.0.0.0 can be used to allow requests from any address.
 #radius_das_client=192.168.1.123 shared secret here
 #
 # DAS Event-Timestamp time window in seconds
@@ -1231,7 +1239,10 @@
 # and/or WPA2 (full IEEE 802.11i/RSN):
 # bit0 = WPA
 # bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
-#wpa=1
+# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2.
+# In other words, for WPA3, wpa=2 is used the configuration (and
+# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
+#wpa=2
 
 # 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
@@ -1260,27 +1271,53 @@
 # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
 # entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
 # added to enable SHA256-based stronger algorithms.
+# WPA-PSK = WPA-Personal / WPA2-Personal
+# WPA-PSK-SHA256 = WPA2-Personal using SHA256
+# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
+# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
+# SAE = SAE (WPA3-Personal)
+# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
+# FT-PSK = FT with passphrase/PSK
+# FT-EAP = FT with EAP
+# FT-EAP-SHA384 = FT with EAP using SHA384
+# FT-SAE = FT with SAE
 # FILS-SHA256 = Fast Initial Link Setup with SHA256
 # FILS-SHA384 = Fast Initial Link Setup with SHA384
 # FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
 # FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+# DPP = Device Provisioning Protocol
+# OSEN = Hotspot 2.0 online signup with encryption
 # (dot11RSNAConfigAuthenticationSuitesTable)
 #wpa_key_mgmt=WPA-PSK WPA-EAP
 
 # Set of accepted cipher suites (encryption algorithms) for pairwise keys
 # (unicast packets). This is a space separated list of algorithms:
-# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
-# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# CCMP = AES in Counter mode with CBC-MAC (CCMP-128)
+# TKIP = Temporal Key Integrity Protocol
+# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key
+# GCMP = Galois/counter mode protocol (GCMP-128)
+# GCMP-256 = Galois/counter mode protocol with 256-bit key
 # Group cipher suite (encryption algorithm for broadcast and multicast frames)
 # is automatically selected based on this configuration. If only CCMP is
 # allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
-# TKIP will be used as the group cipher.
+# TKIP will be used as the group cipher. The optional group_cipher parameter can
+# be used to override this automatic selection.
+#
 # (dot11RSNAConfigPairwiseCiphersTable)
 # Pairwise cipher for WPA (v1) (default: TKIP)
 #wpa_pairwise=TKIP CCMP
 # Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
 #rsn_pairwise=CCMP
 
+# Optional override for automatic group cipher selection
+# This can be used to select a specific group cipher regardless of which
+# pairwise ciphers were enabled for WPA and RSN. It should be noted that
+# overriding the group cipher with an unexpected value can result in
+# interoperability issues and in general, this parameter is mainly used for
+# testing purposes.
+#group_cipher=CCMP
+
 # Time interval for rekeying GTK (broadcast/multicast encryption keys) in
 # seconds. (dot11RSNAConfigGroupRekeyTime)
 # This defaults to 86400 seconds (once per day) when using CCMP/GCMP as the
@@ -1397,19 +1434,43 @@
 #okc=1
 
 # SAE password
-# This parameter can be used to set a password for SAE. By default, the
+# This parameter can be used to set passwords for SAE. By default, the
 # wpa_passphrase value is used if this separate parameter is not used, but
 # wpa_passphrase follows the WPA-PSK constraints (8..63 characters) even though
 # SAE passwords do not have such constraints. If the BSS enabled both SAE and
-# WPA-PSK and both values are set, SAE uses the sae_password value and WPA-PSK
+# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK
 # uses the wpa_passphrase value.
+#
+# Each sae_password entry is added to a list of available passwords. This
+# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
+# starts with the password (dot11RSNAConfigPasswordCredential). That value can
+# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
+# by optional password identifier (dot11RSNAConfigPasswordIdentifier). If the
+# peer MAC address is not included or is set to the wildcard address
+# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
+# specific peer MAC address is included, only a station with that MAC address
+# is allowed to use the entry. If the password identifier (with non-zero length)
+# is included, the entry is limited to be used only with that specified
+# identifier. The last matching (based on peer MAC address and identifier) entry
+# is used to select which password to use. Setting sae_password to an empty
+# string has a special meaning of removing all previously added entries.
+# sae_password uses the following encoding:
+#<password/credential>[|mac=<peer mac>][|id=<identifier>]
+# Examples:
 #sae_password=secret
+#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
+#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
 
 # SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
 # This parameter defines how many open SAE instances can be in progress at the
 # same time before the anti-clogging mechanism is taken into use.
 #sae_anti_clogging_threshold=5
 
+# Maximum number of SAE synchronization errors (dot11RSNASAESync)
+# The offending SAe peer will be disconnected if more than this many
+# synchronization errors happen.
+#sae_sync=5
+
 # Enabled SAE finite cyclic groups
 # SAE implementation are required to support group 19 (ECC group defined over a
 # 256-bit prime order field). All groups that are supported by the
@@ -1419,6 +1480,14 @@
 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
 #sae_groups=19 20 21 25 26
 
+# Require MFP for all associations using SAE
+# This parameter can be used to enforce negotiation of MFP for all associations
+# that negotiate use of SAE. This is used in cases where SAE-capable devices are
+# known to be MFP-capable and the BSS is configured with optional MFP
+# (ieee80211w=1) for legacy support. The non-SAE stations can connect without
+# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
+#sae_require_mfp=0
+
 # FILS Cache Identifier (16-bit value in hexdump format)
 #fils_cache_id=0011
 
@@ -1492,9 +1561,16 @@
 # 1 to 48 octet identifier.
 # This is configured with nas_identifier (see RADIUS client section above).
 
-# Default lifetime of the PMK-RO in minutes; range 1..65535
+# Default lifetime of the PMK-R0 in seconds; range 60..4294967295
+# (default: 14 days / 1209600 seconds; 0 = disable timeout)
 # (dot11FTR0KeyLifetime)
-#r0_key_lifetime=10000
+#ft_r0_key_lifetime=1209600
+
+# Maximum lifetime for PMK-R1; applied only if not zero
+# PMK-R1 is removed at latest after this limit.
+# Removing any PMK-R1 for expiry can be disabled by setting this to -1.
+# (default: 0)
+#r1_max_key_lifetime=0
 
 # PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
 # 6-octet identifier as a hex string.
@@ -1841,6 +1917,18 @@
 # 1 = enabled (allow stations to use WNM-Sleep Mode)
 #wnm_sleep_mode=1
 
+# WNM-Sleep Mode GTK/IGTK workaround
+# Normally, WNM-Sleep Mode exit with management frame protection negotiated
+# would result in the current GTK/IGTK getting added into the WNM-Sleep Mode
+# Response frame. Some station implementations may have a vulnerability that
+# results in GTK/IGTK reinstallation based on this frame being replayed. This
+# configuration parameter can be used to disable that behavior and use EAPOL-Key
+# frames for GTK/IGTK update instead. This would likely be only used with
+# wpa_disable_eapol_key_retries=1 that enables a workaround for similar issues
+# with EAPOL-Key. This is related to station side vulnerabilities CVE-2017-13087
+# and CVE-2017-13088. To enable this AP-side workaround, set the parameter to 1.
+#wnm_sleep_mode_no_keys=0
+
 # BSS Transition Management
 # 0 = disabled (default)
 # 1 = enabled
@@ -1928,6 +2016,15 @@
 # (double quoted string, printf-escaped string)
 #venue_name=P"eng:Example\nvenue"
 
+# Venue URL information
+# This parameter can be used to configure one or more Venue URL Duples to
+# provide additional information corresponding to Venue Name information.
+# Each entry has a Venue Number value separated by colon from the Venue URL
+# string. Venue Number indicates the corresponding venue_name entry (1 = 1st
+# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name)
+#venue_url=1:http://www.example.com/info-eng
+#venue_url=2:http://www.example.com/info-fin
+
 # Network Authentication Type
 # This parameter indicates what type of network authentication is used in the
 # network.
@@ -2098,7 +2195,27 @@
 # channels 36-48):
 #hs20_operating_class=5173
 
-# OSU icons
+# Terms and Conditions information
+#
+# hs20_t_c_filename contains the Terms and Conditions filename that the AP
+# indicates in RADIUS Access-Request messages.
+#hs20_t_c_filename=terms-and-conditions
+#
+# hs20_t_c_timestamp contains the Terms and Conditions timestamp that the AP
+# indicates in RADIUS Access-Request messages. Usually, this contains the number
+# of seconds since January 1, 1970 00:00 UTC showing the time when the file was
+# last modified.
+#hs20_t_c_timestamp=1234567
+#
+# hs20_t_c_server_url contains a template for the Terms and Conditions server
+# URL. This template is used to generate the URL for a STA that needs to
+# acknowledge Terms and Conditions. Unlike the other hs20_t_c_* parameters, this
+# parameter is used on the authentication server, not the AP.
+# Macros:
+# @1@ = MAC address of the STA (colon separated hex octets)
+#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123
+
+# OSU and Operator icons
 # <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path>
 #hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
 #hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
@@ -2110,12 +2227,15 @@
 # OSU Providers
 # One or more sets of following parameter. Each OSU provider is started by the
 # mandatory osu_server_uri item. The other parameters add information for the
-# last added OSU provider.
+# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN
+# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI
+# value for OSEN authentication when using a shared BSS (Single SSID) for OSU.
 #
 #osu_server_uri=https://example.com/osu/
 #osu_friendly_name=eng:Example operator
 #osu_friendly_name=fin:Esimerkkipalveluntarjoaja
 #osu_nai=anonymous@example.com
+#osu_nai2=anonymous@example.com
 #osu_method_list=1 0
 #osu_icon=icon32
 #osu_icon=icon64
@@ -2124,6 +2244,13 @@
 #
 #osu_server_uri=...
 
+# Operator Icons
+# Operator icons are specified using references to the hs20_icon entries
+# (Name subfield). This information, if present, is advertsised in the
+# Operator Icon Metadata ANQO-element.
+#operator_icon=icon32
+#operator_icon=icon64
+
 ##### Multiband Operation (MBO) ###############################################
 #
 # MBO enabled
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
index 826db34..411b9ea 100644
--- a/hostapd/hostapd.eap_user_sqlite
+++ b/hostapd/hostapd.eap_user_sqlite
@@ -3,7 +3,8 @@
 	methods TEXT,
 	password TEXT,
 	remediation TEXT,
-	phase2 INTEGER
+	phase2 INTEGER,
+	t_c_timestamp INTEGER
 );
 
 CREATE TABLE wildcards(
@@ -24,3 +25,18 @@
 	username TEXT,
 	note TEXT
 );
+
+CREATE TABLE pending_tc(
+	mac_addr TEXT PRIMARY KEY,
+	identity TEXT
+);
+
+CREATE TABLE current_sessions(
+	mac_addr TEXT PRIMARY KEY,
+	identity TEXT,
+	start_time TEXT,
+	nas TEXT,
+	hs20_t_c_filtering BOOLEAN,
+	waiting_coa_ack BOOLEAN,
+	coa_ack_received BOOLEAN
+);
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 5b0882a..fbec5d2 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1408,6 +1408,20 @@
 }
 
 
+static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
+}
+
+
 static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
 						char *argv[])
 {
@@ -1422,6 +1436,13 @@
 }
 
 
+static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
+						    int argc, char *argv[])
+{
+	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
+}
+
+
 static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
 					char *argv[])
 {
@@ -1438,6 +1459,27 @@
 #endif /* CONFIG_DPP */
 
 
+static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv);
+}
+
+
 struct hostapd_cli_cmd {
 	const char *cmd;
 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1586,16 +1628,29 @@
 	  "<id> = show DPP bootstrap information" },
 	{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
 	  "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
+	{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
+	  "<freq in MHz> = start DPP listen" },
+	{ "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL,
+	  "= stop DPP listen" },
 	{ "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
 	  "[curve=..] [key=..] = add DPP configurator" },
 	{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
 	  NULL,
 	  "*|<id> = remove DPP configurator" },
+	{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_get_key,
+	  NULL,
+	  "<id> = Get DPP configurator's private key" },
 	{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
 	  "add PKEX code" },
 	{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
 	  "*|<id> = remove DPP pkex information" },
 #endif /* CONFIG_DPP */
+	{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
+	  "=Add/Delete/Show/Clear accept MAC ACL" },
+	{ "deny_acl", hostapd_cli_cmd_deny_macacl, NULL,
+	  "=Add/Delete/Show/Clear deny MAC ACL" },
+	{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
+	  "<addr> = poll a STA to check connectivity with a QoS null frame" },
 	{ NULL, NULL, NULL, NULL }
 };
 
diff --git a/hostapd/main.c b/hostapd/main.c
index 6c0490f..dbe065e 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -24,6 +24,7 @@
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #include "ap/ap_drv_ops.h"
+#include "ap/dpp_hostapd.h"
 #include "fst/fst.h"
 #include "config_file.h"
 #include "eap_register.h"
@@ -671,6 +672,9 @@
 #ifdef CONFIG_ETH_P_OUI
 	dl_list_init(&interfaces.eth_p_oui);
 #endif /* CONFIG_ETH_P_OUI */
+#ifdef CONFIG_DPP
+	hostapd_dpp_init_global(&interfaces);
+#endif /* CONFIG_DPP */
 
 	for (;;) {
 		c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
@@ -928,6 +932,10 @@
 	}
 	os_free(interfaces.iface);
 
+#ifdef CONFIG_DPP
+	hostapd_dpp_deinit_global(&interfaces);
+#endif /* CONFIG_DPP */
+
 	if (interfaces.eloop_initialized)
 		eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
 	hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
diff --git a/hs20/client/est.c b/hs20/client/est.c
index 9f1519b..b1aacb8 100644
--- a/hs20/client/est.c
+++ b/hs20/client/est.c
@@ -666,7 +666,6 @@
 	char *buf, *resp, *req, *req2;
 	size_t buflen, resp_len, len, pkcs7_len;
 	unsigned char *pkcs7;
-	FILE *f;
 	char client_cert_buf[200];
 	char client_key_buf[200];
 	const char *client_cert = NULL, *client_key = NULL;
@@ -721,11 +720,6 @@
 		return -1;
 	}
 	wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
-	f = fopen("Cert/est-resp.raw", "w");
-	if (f) {
-		fwrite(resp, resp_len, 1, f);
-		fclose(f);
-	}
 
 	pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
 	if (pkcs7 == NULL) {
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index d73feb1..9e1b0c7 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -105,6 +105,35 @@
 }
 
 
+static int android_update_permission(const char *path, mode_t mode)
+{
+#ifdef ANDROID
+	/* we need to change file/folder permission for Android */
+
+	if (!path) {
+		wpa_printf(MSG_ERROR, "file path null");
+		return -1;
+	}
+
+	/* Allow processes running with Group ID as AID_WIFI,
+	 * to read files from SP, SP/<fqdn>, Cert and osu-info directories */
+	if (chown(path, -1, AID_WIFI)) {
+		wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
+			   strerror(errno));
+		return -1;
+	}
+
+	if (chmod(path, mode) < 0) {
+		wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
+			   strerror(errno));
+		return -1;
+	}
+#endif  /* ANDROID */
+
+	return 0;
+}
+
+
 int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
 {
 	xml_node_t *node;
@@ -169,6 +198,8 @@
 	}
 
 	mkdir("Cert", S_IRWXU);
+	android_update_permission("Cert", S_IRWXU | S_IRWXG);
+
 	if (est_load_cacerts(ctx, url) < 0 ||
 	    est_build_csr(ctx, url) < 0 ||
 	    est_simple_enroll(ctx, url, user, pw) < 0)
@@ -262,7 +293,6 @@
 
 	unlink("Cert/est-req.b64");
 	unlink("Cert/est-req.pem");
-	unlink("Cert/est-resp.raw");
 	rmdir("Cert");
 
 	return 0;
@@ -406,7 +436,7 @@
 	if (node == NULL) {
 		wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
 		xml_node_free(ctx->xml, pps);
-		return -1;
+		return -2;
 	}
 
 	ret = download_cert(ctx, node, ca_fname);
@@ -433,7 +463,7 @@
 	if (node == NULL) {
 		wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS");
 		xml_node_free(ctx->xml, pps);
-		return -1;
+		return -2;
 	}
 
 	aaa = xml_node_first_child(ctx->xml, node);
@@ -455,7 +485,7 @@
 {
 	char *dir, *pos;
 	char fname[300];
-	int ret;
+	int ret, ret1;
 
 	dir = os_strdup(pps_fname);
 	if (dir == NULL)
@@ -470,9 +500,13 @@
 	snprintf(fname, sizeof(fname), "%s/ca.pem", dir);
 	ret = cmd_dl_osu_ca(ctx, pps_fname, fname);
 	snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir);
-	cmd_dl_polupd_ca(ctx, pps_fname, fname);
+	ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname);
+	if (ret == 0 && ret1 == -1)
+		ret = -1;
 	snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
-	cmd_dl_aaa_ca(ctx, pps_fname, fname);
+	ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname);
+	if (ret == 0 && ret1 == -1)
+		ret = -1;
 
 	os_free(dir);
 
@@ -578,20 +612,8 @@
 		}
 	}
 
-#ifdef ANDROID
-	/* Allow processes running with Group ID as AID_WIFI,
-	 * to read files from SP/<fqdn> directory */
-	if (chown(fname, -1, AID_WIFI)) {
-		wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
-			   strerror(errno));
-		/* Try to continue anyway */
-	}
-	if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) {
-		wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
-			   strerror(errno));
-		/* Try to continue anyway */
-	}
-#endif /* ANDROID */
+	android_update_permission("SP", S_IRWXU | S_IRGRP | S_IXGRP);
+	android_update_permission(fname, S_IRWXU | S_IRGRP | S_IXGRP);
 
 	snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
 
@@ -1213,8 +1235,7 @@
 			     homeoi) < 0)
 			wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium");
 	} else {
-		if (set_cred_quoted(ctx->ifname, id, "roaming_consortium",
-				    homeoi) < 0)
+		if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0)
 			wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
 	}
 
@@ -1289,7 +1310,9 @@
 	if (str == NULL)
 		return;
 	wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str);
-	/* TODO: Set to wpa_supplicant */
+	if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums",
+			    str) < 0)
+		wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums");
 	xml_node_get_text_free(ctx->xml, str);
 }
 
@@ -1442,10 +1465,92 @@
 }
 
 
+static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx,
+					     int id, xml_node_t *node)
+{
+	char *str = xml_node_get_text(ctx->xml, node);
+	int type;
+	const char *eap_method = NULL;
+
+	if (!str)
+		return;
+	wpa_printf(MSG_INFO,
+		   "- Credential/UsernamePassword/EAPMethod/EAPType = %s", str);
+	type = atoi(str);
+	switch (type) {
+	case EAP_TYPE_TLS:
+		eap_method = "TLS";
+		break;
+	case EAP_TYPE_TTLS:
+		eap_method = "TTLS";
+		break;
+	case EAP_TYPE_PEAP:
+		eap_method = "PEAP";
+		break;
+	case EAP_TYPE_PWD:
+		eap_method = "PWD";
+		break;
+	}
+	xml_node_get_text_free(ctx->xml, str);
+	if (!eap_method) {
+		wpa_printf(MSG_INFO, "Unknown EAPType value");
+		return;
+	}
+
+	if (set_cred(ctx->ifname, id, "eap", eap_method) < 0)
+		wpa_printf(MSG_INFO, "Failed to set cred eap");
+}
+
+
+static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx,
+						 int id, xml_node_t *node)
+{
+	char *str = xml_node_get_text(ctx->xml, node);
+	const char *phase2 = NULL;
+
+	if (!str)
+		return;
+	wpa_printf(MSG_INFO,
+		   "- Credential/UsernamePassword/EAPMethod/InnerMethod = %s",
+		   str);
+	if (os_strcmp(str, "PAP") == 0)
+		phase2 = "auth=PAP";
+	else if (os_strcmp(str, "CHAP") == 0)
+		phase2 = "auth=CHAP";
+	else if (os_strcmp(str, "MS-CHAP") == 0)
+		phase2 = "auth=MSCHAP";
+	else if (os_strcmp(str, "MS-CHAP-V2") == 0)
+		phase2 = "auth=MSCHAPV2";
+	xml_node_get_text_free(ctx->xml, str);
+	if (!phase2) {
+		wpa_printf(MSG_INFO, "Unknown InnerMethod value");
+		return;
+	}
+
+	if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0)
+		wpa_printf(MSG_INFO, "Failed to set cred phase2");
+}
+
+
 static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id,
 				    xml_node_t *node)
 {
-	wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod - TODO");
+	xml_node_t *child;
+	const char *name;
+
+	wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod");
+
+	xml_node_for_each_child(ctx->xml, child, node) {
+		xml_node_for_each_check(ctx->xml, child);
+		name = xml_node_get_localname(ctx->xml, child);
+		if (os_strcasecmp(name, "EAPType") == 0)
+			set_pps_cred_eap_method_eap_type(ctx, id, child);
+		else if (os_strcasecmp(name, "InnerMethod") == 0)
+			set_pps_cred_eap_method_inner_method(ctx, id, child);
+		else
+			wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'",
+				   name);
+	}
 }
 
 
@@ -1884,7 +1989,9 @@
 	char url[256];
 	unsigned int methods;
 	char osu_ssid[33];
+	char osu_ssid2[33];
 	char osu_nai[256];
+	char osu_nai2[256];
 	struct osu_lang_text friendly_name[MAX_OSU_VALS];
 	size_t friendly_name_count;
 	struct osu_lang_text serv_desc[MAX_OSU_VALS];
@@ -1943,12 +2050,24 @@
 			continue;
 		}
 
+		if (strncmp(buf, "osu_ssid2=", 10) == 0) {
+			snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
+				 "%s", buf + 10);
+			continue;
+		}
+
 		if (os_strncmp(buf, "osu_nai=", 8) == 0) {
 			os_snprintf(last->osu_nai, sizeof(last->osu_nai),
 				    "%s", buf + 8);
 			continue;
 		}
 
+		if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
+			os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
+				    "%s", buf + 9);
+			continue;
+		}
+
 		if (strncmp(buf, "friendly_name=", 14) == 0) {
 			struct osu_lang_text *txt;
 			if (last->friendly_name_count == MAX_OSU_VALS)
@@ -2024,9 +2143,9 @@
 
 
 static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
-		       const char *ssid, const char *url,
+		       const char *ssid, const char *ssid2, const char *url,
 		       unsigned int methods, int no_prod_assoc,
-		       const char *osu_nai)
+		       const char *osu_nai, const char *osu_nai2)
 {
 	int id;
 	const char *ifname = ctx->ifname;
@@ -2034,26 +2153,54 @@
 	struct wpa_ctrl *mon;
 	int res;
 
+	if (ssid2 && ssid2[0] == '\0')
+		ssid2 = NULL;
+
+	if (ctx->osu_ssid) {
+		if (os_strcmp(ssid, ctx->osu_ssid) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "Enforced OSU SSID matches ANQP info");
+			ssid2 = NULL;
+		} else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "Enforced OSU SSID matches RSN[OSEN] info");
+			ssid = ssid2;
+		} else {
+			wpa_printf(MSG_INFO, "Enforced OSU SSID did not match");
+			write_summary(ctx, "Enforced OSU SSID did not match");
+			return -1;
+		}
+	}
+
 	id = add_network(ifname);
 	if (id < 0)
 		return -1;
 	if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
 		return -1;
+	if (ssid2)
+		osu_nai = osu_nai2;
 	if (osu_nai && os_strlen(osu_nai) > 0) {
 		char dir[255], fname[300];
 		if (getcwd(dir, sizeof(dir)) == NULL)
 			return -1;
 		os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir);
 
+		if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0)
+			return -1;
+
 		if (set_network(ifname, id, "proto", "OSEN") < 0 ||
 		    set_network(ifname, id, "key_mgmt", "OSEN") < 0 ||
 		    set_network(ifname, id, "pairwise", "CCMP") < 0 ||
-		    set_network(ifname, id, "group", "GTK_NOT_USED") < 0 ||
+		    set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 ||
 		    set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 ||
 		    set_network(ifname, id, "ocsp", "2") < 0 ||
 		    set_network_quoted(ifname, id, "identity", osu_nai) < 0 ||
 		    set_network_quoted(ifname, id, "ca_cert", fname) < 0)
 			return -1;
+	} else if (ssid2) {
+		wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]");
+		write_summary(ctx, "No OSU_NAI set for RSN[OSEN]");
+		return -1;
 	} else {
 		if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
 			return -1;
@@ -2229,8 +2376,12 @@
 		fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
 			"SSID: %s<br>\n",
 			last->bssid, last->osu_ssid);
+		if (last->osu_ssid2[0])
+			fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2);
 		if (last->osu_nai[0])
 			fprintf(f, "NAI: %s<br>\n", last->osu_nai);
+		if (last->osu_nai2[0])
+			fprintf(f, "NAI2: %s<br>\n", last->osu_nai2);
 		fprintf(f, "URL: %s<br>\n"
 			"methods:%s%s<br>\n"
 			"</small></p>\n",
@@ -2257,6 +2408,8 @@
 		ret = 0;
 		wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
 		wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
+		if (last->osu_ssid2[0])
+			wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2);
 		wpa_printf(MSG_INFO, "URL: %s", last->url);
 		write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s",
 			      ret, last->bssid, last->osu_ssid, last->url);
@@ -2311,10 +2464,13 @@
 					   "No supported OSU provisioning method");
 				ret = -1;
 			}
-		} else if (connect)
+		} else if (connect) {
 			ret = osu_connect(ctx, last->bssid, last->osu_ssid,
+					  last->osu_ssid2,
 					  last->url, last->methods,
-					  no_prod_assoc, last->osu_nai);
+					  no_prod_assoc, last->osu_nai,
+					  last->osu_nai2);
+		}
 	} else
 		ret = -1;
 
@@ -2346,15 +2502,7 @@
 		return -1;
 	}
 
-#ifdef ANDROID
-	/* Allow processes running with Group ID as AID_WIFI
-	 * to read/write files from osu-info directory
-	 */
-	if (chown(fname, -1, AID_WIFI)) {
-		wpa_printf(MSG_INFO, "Could not chown osu-info directory: %s",
-			   strerror(errno));
-	}
-#endif /* ANDROID */
+	android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
 
 	snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
 	if (wpa_command(ifname, buf) < 0) {
@@ -3040,7 +3188,7 @@
 		return -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
+		c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -3057,6 +3205,9 @@
 		case 'N':
 			no_prod_assoc = 1;
 			break;
+		case 'o':
+			ctx.osu_ssid = optarg;
+			break;
 		case 'O':
 			friendly_name = optarg;
 			break;
diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h
index 9a7059e..5c8e6d0 100644
--- a/hs20/client/osu_client.h
+++ b/hs20/client/osu_client.h
@@ -47,6 +47,7 @@
 	int client_cert_present;
 	char **server_dnsname;
 	size_t server_dnsname_count;
+	const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
 #define WORKAROUND_OCSP_OPTIONAL 0x00000001
 	unsigned long int workarounds;
 };
diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt
index 20774a6..70f1313 100644
--- a/hs20/server/hs20-osu-server.txt
+++ b/hs20/server/hs20-osu-server.txt
@@ -2,7 +2,7 @@
 ======================
 
 The information in this document is based on the assumption that Ubuntu
-12.04 server (64-bit) distribution is used and the web server is
+16.04 server (64-bit) distribution is used and the web server is
 Apache2. Neither of these are requirements for the installation, but if
 other combinations are used, the package names and configuration
 parameters may need to be adjusted.
@@ -12,16 +12,11 @@
 secure to be installed in a publicly available Internet server without
 considerable amount of modification and review for security issues.
 
-NOTE: While this describes use on Ubuntu 12.04, the version of Apache2
-included in that distribution is not new enough to support all OSU
-server validation steps. In other words, it may be most adapt the steps
-described here to Ubuntu 13.10.
-
 
 Build dependencies
 ------------------
 
-Ubuntu 12.04 server
+Ubuntu 16.04 server
 - default installation
 - upgraded to latest package versions
   sudo apt-get update
@@ -30,7 +25,7 @@
 Packages needed for running the service:
   sudo apt-get install sqlite3
   sudo apt-get install apache2
-  sudo apt-get install php5-sqlite libapache2-mod-php5
+  sudo apt-get install php-sqlite3 php-xml libapache2-mod-php
 
 Additional packages needed for building the components:
   sudo apt-get install build-essential
@@ -100,6 +95,12 @@
 # the examples as-is for initial testing).
 cp -r www /home/user/hs20-server
 
+# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be
+# inserted within the BODY section of the page).
+cat > /home/user/hs20-server/terms-and-conditions <<EOF
+<P>Terms and conditions..</P>
+EOF
+
 # Build local keys and certs
 cd ca
 # Display help options.
@@ -226,8 +227,7 @@
         <Directory "/home/user/hs20-server/www/">
                 Options Indexes MultiViews FollowSymLinks
                 AllowOverride None
-                Order allow,deny
-                Allow from all
+		Require all granted
         </Directory>
 
 Update SSL configuration to use the OSU server certificate/key.
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
index 591f66b..abd6867 100644
--- a/hs20/server/hs20_spp_server.c
+++ b/hs20/server/hs20_spp_server.c
@@ -70,6 +70,10 @@
 	ctx->addr = getenv("HS20ADDR");
 	if (ctx->addr)
 		debug_print(ctx, 1, "Connection from %s", ctx->addr);
+	ctx->test = getenv("HS20TEST");
+	if (ctx->test)
+		debug_print(ctx, 1, "Requested test functionality: %s",
+			    ctx->test);
 
 	user = getenv("HS20USER");
 	if (user && strlen(user) == 0)
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index 51c1d96..e5af4c2 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -57,19 +57,26 @@
 			  const char *user, const char *realm,
 			  const char *sessionid, const char *pw,
 			  const char *redirect_uri,
-			  enum hs20_session_operation operation)
+			  enum hs20_session_operation operation,
+			  const u8 *mac_addr)
 {
 	char *sql;
 	int ret = 0;
+	char addr[20];
 
+	if (mac_addr)
+		snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr));
+	else
+		addr[0] = '\0';
 	sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
-			      "operation,password,redirect_uri) "
+			      "operation,password,redirect_uri,mac_addr,test) "
 			      "VALUES "
 			      "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
-			      "%Q,%Q,%Q,%d,%Q,%Q)",
+			      "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
 			      sessionid, user ? user : "", realm ? realm : "",
 			      operation, pw ? pw : "",
-			      redirect_uri ? redirect_uri : "");
+			      redirect_uri ? redirect_uri : "",
+			      addr, ctx->test);
 	if (sql == NULL)
 		return -1;
 	debug_print(ctx, 1, "DB: %s", sql);
@@ -329,6 +336,29 @@
 }
 
 
+static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm,
+				       xml_node_t *parent, const char *name,
+				       const char *field)
+{
+	char *val;
+
+	val = db_get_osu_config_val(ctx, realm, field);
+	if (val) {
+		size_t len;
+
+		len = os_strlen(val);
+		if (len > 0) {
+			if (val[len - 1] == '0')
+				val[len - 1] = '1';
+			else
+				val[len - 1] = '0';
+		}
+	}
+	xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
+	os_free(val);
+}
+
+
 static int new_password(char *buf, int buflen)
 {
 	int i;
@@ -533,7 +563,8 @@
 
 
 static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
-				 const char *user, const char *pw)
+				 const char *user, const char *pw,
+				 int machine_managed)
 {
 	xml_node_t *node;
 
@@ -541,7 +572,8 @@
 	if (node == NULL)
 		return -1;
 
-	add_text_node(ctx, node, "MachineManaged", "TRUE");
+	add_text_node(ctx, node, "MachineManaged",
+		      machine_managed ? "TRUE" : "FALSE");
 	add_text_node(ctx, node, "SoftTokenApp", "");
 	add_eap_ttls(ctx, node);
 
@@ -566,7 +598,7 @@
 
 static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
 					const char *user, const char *realm,
-					const char *pw)
+					const char *pw, int machine_managed)
 {
 	xml_node_t *cred;
 
@@ -576,7 +608,7 @@
 		return NULL;
 	}
 	add_creation_date(ctx, cred);
-	if (add_username_password(ctx, cred, user, pw) < 0) {
+	if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) {
 		xml_node_free(ctx->xml, cred);
 		return NULL;
 	}
@@ -593,7 +625,7 @@
 	if (new_password(new_pw, new_pw_len) < 0)
 		return NULL;
 	debug_print(ctx, 1, "Update password to '%s'", new_pw);
-	return build_credential_pw(ctx, user, realm, new_pw);
+	return build_credential_pw(ctx, user, realm, new_pw, 1);
 }
 
 
@@ -703,8 +735,23 @@
 		cred = build_credential_cert(ctx, real_user ? real_user : user,
 					     realm, cert);
 	} else {
-		cred = build_credential(ctx, real_user ? real_user : user,
-					realm, new_pw, sizeof(new_pw));
+		char *pw;
+
+		pw = db_get_session_val(ctx, user, realm, session_id,
+					"password");
+		if (pw && pw[0]) {
+			debug_print(ctx, 1, "New password from the user: '%s'",
+				    pw);
+			snprintf(new_pw, sizeof(new_pw), "%s", pw);
+			free(pw);
+			cred = build_credential_pw(ctx,
+						   real_user ? real_user : user,
+						   realm, new_pw, 0);
+		} else {
+			cred = build_credential(ctx,
+						real_user ? real_user : user,
+						realm, new_pw, sizeof(new_pw));
+		}
 	}
 	free(real_user);
 	if (!cred) {
@@ -721,7 +768,7 @@
 	}
 
 	snprintf(buf, sizeof(buf),
-		 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
+		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
 		 realm);
 
 	if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
@@ -742,7 +789,7 @@
 		debug_print(ctx, 1, "Request DB password update on success "
 			    "notification");
 		db_add_session(ctx, user, realm, session_id, new_pw, NULL,
-			       UPDATE_PASSWORD);
+			       UPDATE_PASSWORD, NULL);
 	}
 
 	return spp_node;
@@ -771,7 +818,7 @@
 		      "requires policy remediation", NULL);
 
 	db_add_session(ctx, user, realm, session_id, NULL, NULL,
-		       POLICY_REMEDIATION);
+		       POLICY_REMEDIATION, NULL);
 
 	policy = build_policy(ctx, user, realm, dmacc);
 	if (!policy) {
@@ -787,7 +834,7 @@
 		return NULL;
 
 	snprintf(buf, sizeof(buf),
-		 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
+		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
 		 realm);
 
 	if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
@@ -844,7 +891,7 @@
 		return NULL;
 
 	db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
-		       USER_REMEDIATION);
+		       USER_REMEDIATION, NULL);
 
 	snprintf(uri, sizeof(uri), "%s%s", val, session_id);
 	os_free(val);
@@ -866,7 +913,7 @@
 		return NULL;
 
 	db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
-		       FREE_REMEDIATION);
+		       FREE_REMEDIATION, NULL);
 
 	snprintf(uri, sizeof(uri), "%s%s", val, session_id);
 	os_free(val);
@@ -940,8 +987,10 @@
 				       redirect_uri);
 	else if (type && strcmp(type, "policy") == 0)
 		ret = policy_remediation(ctx, user, realm, session_id, dmacc);
-	else
+	else if (type && strcmp(type, "machine") == 0)
 		ret = machine_remediation(ctx, user, realm, session_id, dmacc);
+	else
+		ret = no_sub_rem(ctx, user, realm, session_id);
 	free(type);
 
 	return ret;
@@ -1033,7 +1082,8 @@
 			"No update available at this time", NULL);
 	}
 
-	db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE);
+	db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE,
+		       NULL);
 
 	status = "Update complete, request sppUpdateResponse";
 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
@@ -1042,7 +1092,7 @@
 		return NULL;
 
 	snprintf(buf, sizeof(buf),
-		 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
+		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
 		 realm);
 
 	if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
@@ -1146,14 +1196,15 @@
 static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
 						   const char *realm,
 						   const char *session_id,
-						   const char *redirect_uri)
+						   const char *redirect_uri,
+						   const u8 *mac_addr)
 {
 	xml_namespace_t *ns;
 	xml_node_t *spp_node, *exec_node;
 	char uri[300], *val;
 
 	if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
-			   SUBSCRIPTION_REGISTRATION) < 0)
+			   SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
 		return NULL;
 	val = db_get_osu_config_val(ctx, realm, "signup_url");
 	if (val == NULL)
@@ -1213,9 +1264,9 @@
 static xml_node_t * build_pps(struct hs20_svc *ctx,
 			      const char *user, const char *realm,
 			      const char *pw, const char *cert,
-			      int machine_managed)
+			      int machine_managed, const char *test)
 {
-	xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp;
+	xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
 	xml_node_t *cred, *eap, *userpw;
 
 	pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
@@ -1225,7 +1276,7 @@
 
 	add_text_node(ctx, pps, "UpdateIdentifier", "1");
 
-	c = xml_node_create(ctx->xml, pps, NULL, "Credential1");
+	c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
 
 	add_text_node(ctx, c, "CredentialPriority", "1");
 
@@ -1233,18 +1284,51 @@
 	aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
 	add_text_node_conf(ctx, realm, aaa1, "CertURL",
 			   "aaa_trust_root_cert_url");
-	add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
-			   "aaa_trust_root_cert_fingerprint");
+	if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
+		debug_print(ctx, 1,
+			    "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
+		add_text_node_conf_corrupt(ctx, realm, aaa1,
+					   "CertSHA256Fingerprint",
+					   "aaa_trust_root_cert_fingerprint");
+	} else {
+		add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
+				   "aaa_trust_root_cert_fingerprint");
+	}
+
+	if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
+		debug_print(ctx, 1,
+			    "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
+		p = xml_node_create(ctx->xml, c, NULL, "Policy");
+		upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
+		add_text_node(ctx, upd, "UpdateInterval", "30");
+		add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
+		add_text_node(ctx, upd, "Restriction", "Unrestricted");
+		add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
+		trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
+		add_text_node_conf(ctx, realm, trust, "CertURL",
+				   "policy_trust_root_cert_url");
+		add_text_node_conf_corrupt(ctx, realm, trust,
+					   "CertSHA256Fingerprint",
+					   "policy_trust_root_cert_fingerprint");
+	}
 
 	upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
 	add_text_node(ctx, upd, "UpdateInterval", "4294967295");
-	add_text_node(ctx, upd, "UpdateMethod", "ClientInitiated");
+	add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
 	add_text_node(ctx, upd, "Restriction", "HomeSP");
 	add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
 	trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
 	add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
-	add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
-			   "trust_root_cert_fingerprint");
+	if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
+		debug_print(ctx, 1,
+			    "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
+		add_text_node_conf_corrupt(ctx, realm, trust,
+					   "CertSHA256Fingerprint",
+					   "trust_root_cert_fingerprint");
+	} else {
+		add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
+				   "trust_root_cert_fingerprint");
+	}
 
 	homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
 	add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
@@ -1328,7 +1412,7 @@
 	xml_node_t *pps, *tnds;
 	char buf[400];
 	char *str;
-	char *user, *realm, *pw, *type, *mm;
+	char *user, *realm, *pw, *type, *mm, *test;
 	const char *status;
 	int cert = 0;
 	int machine_managed = 0;
@@ -1387,9 +1471,15 @@
 		return NULL;
 
 	fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+	test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
+	if (test)
+		debug_print(ctx, 1, "TEST: Requested special behavior: %s",
+			    test);
 	pps = build_pps(ctx, user, realm, pw,
-			fingerprint ? fingerprint : NULL, machine_managed);
+			fingerprint ? fingerprint : NULL, machine_managed,
+			test);
 	free(fingerprint);
+	free(test);
 	if (!pps) {
 		xml_node_free(ctx->xml, spp_node);
 		free(user);
@@ -1460,7 +1550,7 @@
 		return NULL;
 	}
 
-	cred = build_credential_pw(ctx, free_account, realm, pw);
+	cred = build_credential_pw(ctx, free_account, realm, pw, 1);
 	free(free_account);
 	free(pw);
 	if (!cred) {
@@ -1475,7 +1565,7 @@
 		return NULL;
 
 	snprintf(buf, sizeof(buf),
-		 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
+		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
 		 realm);
 
 	if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
@@ -1606,11 +1696,12 @@
 	char *req_reason_buf = NULL;
 	char str[200];
 	xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
-	xml_node_t *mo;
+	xml_node_t *mo, *macaddr;
 	char *version;
 	int valid;
 	char *supp, *pos;
 	char *err;
+	u8 wifi_mac_addr[ETH_ALEN];
 
 	version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
 					     "sppVersion");
@@ -1716,6 +1807,29 @@
 		goto out;
 	}
 	os_free(err);
+
+	os_memset(wifi_mac_addr, 0, ETH_ALEN);
+	macaddr = get_node(ctx->xml, devdetail,
+			   "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
+	if (macaddr) {
+		char *addr, buf[50];
+
+		addr = xml_node_get_text(ctx->xml, macaddr);
+		if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
+			snprintf(buf, sizeof(buf), "DevDetail MAC address: "
+				 MACSTR, MAC2STR(wifi_mac_addr));
+			hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
+			xml_node_get_text_free(ctx->xml, addr);
+		} else {
+			hs20_eventlog(ctx, user, realm, session_id,
+				      "Could not extract MAC address from DevDetail",
+				      NULL);
+		}
+	} else {
+		hs20_eventlog(ctx, user, realm, session_id,
+			      "No MAC address in DevDetail", NULL);
+	}
+
 	if (user)
 		db_update_mo(ctx, user, realm, "devdetail", devdetail);
 
@@ -1762,7 +1876,7 @@
 			else
 				oper = NO_OPERATION;
 			if (db_add_session(ctx, user, realm, session_id, NULL,
-					   NULL, oper) < 0)
+					   NULL, oper, NULL) < 0)
 				goto out;
 
 			ret = spp_exec_upload_mo(ctx, session_id,
@@ -1799,7 +1913,8 @@
 
 	if (strcasecmp(req_reason, "Subscription registration") == 0) {
 		ret = hs20_subscription_registration(ctx, realm, session_id,
-						     redirect_uri);
+						     redirect_uri,
+						     wifi_mac_addr);
 		hs20_eventlog_node(ctx, user, realm, session_id,
 				   "subscription registration response",
 				   ret);
@@ -1948,13 +2063,15 @@
 		goto out;
 	}
 
-	sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
-			      "methods,cert,cert_pem,machine_managed) VALUES "
-			      "(%Q,%Q,1,%Q,%Q,%Q,%d)",
+	str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
+
+	sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr) VALUES (%Q,%Q,1,%Q,%Q,%Q,%d,%Q)",
 			      user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
 			      fingerprint ? fingerprint : "",
 			      cert_pem ? cert_pem : "",
-			      pw_mm && atoi(pw_mm) ? 1 : 0);
+			      pw_mm && atoi(pw_mm) ? 1 : 0,
+			      str ? str : "");
+	free(str);
 	if (sql == NULL)
 		goto out;
 	debug_print(ctx, 1, "DB: %s", sql);
@@ -1996,6 +2113,32 @@
 		free(str);
 	}
 
+	if (cert && user) {
+		const char *serialnum;
+
+		str = db_get_session_val(ctx, NULL, NULL, session_id,
+					 "mac_addr");
+
+		if (os_strncmp(user, "cert-", 5) == 0)
+			serialnum = user + 5;
+		else
+			serialnum = "";
+		sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
+				      str ? str : "", user, realm ? realm : "",
+				      serialnum);
+		free(str);
+		if (sql) {
+			debug_print(ctx, 1, "DB: %s", sql);
+			if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
+			    SQLITE_OK) {
+				debug_print(ctx, 1,
+					    "Failed to add cert_enroll entry into sqlite database: %s",
+					    sqlite3_errmsg(ctx->db));
+			}
+			sqlite3_free(sql);
+		}
+	}
+
 	if (ret == 0) {
 		hs20_eventlog(ctx, user, realm, session_id,
 			      "completed subscription registration", NULL);
@@ -2119,6 +2262,9 @@
 					      "", dmacc);
 			free(val);
 		}
+		if (oper == POLICY_UPDATE)
+			db_update_val(ctx, user, realm, "polupd_done", "1",
+				      dmacc);
 		ret = build_spp_exchange_complete(
 			ctx, session_id,
 			"Exchange complete, release TLS connection", NULL);
diff --git a/hs20/server/spp_server.h b/hs20/server/spp_server.h
index 7b27be3..3556f5c 100644
--- a/hs20/server/spp_server.h
+++ b/hs20/server/spp_server.h
@@ -16,6 +16,7 @@
 	FILE *debug_log;
 	sqlite3 *db;
 	const char *addr;
+	const char *test;
 };
 
 
diff --git a/hs20/server/sql.txt b/hs20/server/sql.txt
index 6609538..666ef13 100644
--- a/hs20/server/sql.txt
+++ b/hs20/server/sql.txt
@@ -22,7 +22,9 @@
 	devinfo TEXT,
 	devdetail TEXT,
 	cert TEXT,
-	cert_pem TEXT
+	cert_pem TEXT,
+	mac_addr TEXT,
+	test TEXT
 );
 
 CREATE index sessions_id_index ON sessions(id);
@@ -50,10 +52,44 @@
 	osu_password TEXT,
 	shared INTEGER,
 	cert TEXT,
-	cert_pem TEXT
+	cert_pem TEXT,
+	t_c_timestamp INTEGER,
+	mac_addr TEXT,
+	last_msk TEXT,
+	polupd_done TEXT,
 );
 
 CREATE TABLE wildcards(
 	identity TEXT PRIMARY KEY,
 	methods TEXT
 );
+
+CREATE TABLE authlog(
+	timestamp TEXT,
+	session TEXT,
+	nas_ip TEXT,
+	username TEXT,
+	note TEXT
+);
+
+CREATE TABLE pending_tc(
+	mac_addr TEXT PRIMARY KEY,
+	identity TEXT
+);
+
+CREATE TABLE current_sessions(
+	mac_addr TEXT PRIMARY KEY,
+	identity TEXT,
+	start_time TEXT,
+	nas TEXT,
+	hs20_t_c_filtering BOOLEAN,
+	waiting_coa_ack BOOLEAN,
+	coa_ack_received BOOLEAN
+);
+
+CREATE TABLE cert_enroll(
+	mac_addr TEXT PRIMARY KEY,
+	user TEXT,
+	realm TEXT,
+	serialnum TEXT
+);
diff --git a/hs20/server/www/config.php b/hs20/server/www/config.php
index e3af435..4272b10 100644
--- a/hs20/server/www/config.php
+++ b/hs20/server/www/config.php
@@ -1,4 +1,7 @@
 <?php
 $osu_root = "/home/user/hs20-server";
 $osu_db = "sqlite:$osu_root/AS/DB/eap_user.db";
+$t_c_file = "$osu_root/terms-and-conditions";
+$t_c_timestamp = 123456789;
+$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as"
 ?>
diff --git a/hs20/server/www/est.php b/hs20/server/www/est.php
index a45648b..6983ec9 100644
--- a/hs20/server/www/est.php
+++ b/hs20/server/www/est.php
@@ -2,7 +2,7 @@
 
 require('config.php');
 
-$params = split("/", $_SERVER["PATH_INFO"], 3);
+$params = explode("/", $_SERVER["PATH_INFO"], 3);
 $realm = $params[1];
 $cmd = $params[2];
 $method = $_SERVER["REQUEST_METHOD"];
diff --git a/hs20/server/www/remediation-pw.php b/hs20/server/www/remediation-pw.php
new file mode 100644
index 0000000..76fdccb
--- /dev/null
+++ b/hs20/server/www/remediation-pw.php
@@ -0,0 +1,41 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+   die($sqliteerror);
+}
+
+if (isset($_POST["id"]))
+  $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
+else
+  die("Missing session id");
+
+$pw = $_POST["password"];
+if (strlen($id) < 32 || !isset($pw)) {
+  die("Invalid POST data");
+}
+
+$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+   die("Session not found");
+}
+$user = $row['user'];
+$realm = $row['realm'];
+
+$uri = $row['redirect_uri'];
+$rowid = $row['rowid'];
+
+if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) {
+  die("Failed to update session database");
+}
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+	"VALUES ('$user', '$realm', '$id', " .
+	"strftime('%Y-%m-%d %H:%M:%f','now'), " .
+	"'completed user input response for subscription remediation')");
+
+header("Location: $uri", true, 302);
+
+?>
diff --git a/hs20/server/www/remediation.php b/hs20/server/www/remediation.php
index 392a7bd..3628065 100644
--- a/hs20/server/www/remediation.php
+++ b/hs20/server/www/remediation.php
@@ -6,13 +6,50 @@
 
 <?php
 
-echo "SessionID: " . $_GET["session_id"] . "<br>\n";
+require('config.php');
 
-echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+$db = new PDO($osu_db);
+if (!$db) {
+   die($sqliteerror);
+}
+
+if (isset($_GET["session_id"]))
+	$id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]);
+else
+	$id = 0;
+echo "SessionID: " . $id . "<br>\n";
+
+$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+   die("Session not found");
+}
+
+$username = $row['user'];
+echo "User: " . $username . "@" . $row['realm'] . "<br>\n";
+
+$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch();
+if ($user == false) {
+   die("User not found");
+}
+
+echo "<hr><br>\n";
+
+$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0;
+
+if ($cert) {
+   echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+} else if ($user['machine_managed'] == "1") {
+   echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+   echo "This will provide a new machine-generated password.<br>\n";
+} else {
+   echo "<form action=\"remediation-pw.php\" method=\"POST\">\n";
+   echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
+   echo "New password: <input type=\"password\" name=\"password\"><br>\n";
+   echo "<input type=\"submit\" value=\"Change password\">\n";
+   echo "</form>\n";
+}
 
 ?>
 
-This will provide a new machine-generated password.
-
 </body>
 </html>
diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php
index aeb2f68..80a9d40 100644
--- a/hs20/server/www/signup.php
+++ b/hs20/server/www/signup.php
@@ -15,19 +15,30 @@
    die($sqliteerror);
 }
 
-$row = $db->query("SELECT realm FROM sessions WHERE id='$id'")->fetch();
+$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch();
 if ($row == false) {
    die("Session not found for id: $id");
 }
 $realm = $row['realm'];
+$test = $row['test'];
+
+if (strlen($test) > 0) {
+  echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n";
+}
 
 echo "<h3>Sign up for a subscription - $realm</h3>\n";
 
+echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n";
+
+echo "<h4>Option 1 - shared free access credential</h4>\n";
+
 $row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
 if ($row && strlen($row['value']) > 0) {
   echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n";
 }
 
+echo "<h4>Option 2 - username/password credential</h4>\n";
+
 echo "<form action=\"add-mo.php\" method=\"POST\">\n";
 echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
 ?>
@@ -39,6 +50,8 @@
 </form>
 
 <?php
+echo "<h4>Option 3 - client certificate credential</h4>\n";
+
 echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n"
 ?>
 
diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php
index 002d028..f10e5ab 100644
--- a/hs20/server/www/spp.php
+++ b/hs20/server/www/spp.php
@@ -20,6 +20,11 @@
   die("Realm not specified");
 }
 
+if (isset($_GET["test"]))
+  $test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]);
+else
+  $test = "";
+
 unset($user);
 putenv("HS20CERT");
 
@@ -100,6 +105,7 @@
 putenv("HS20POST=$postdata");
 $addr = $_SERVER["REMOTE_ADDR"];
 putenv("HS20ADDR=$addr");
+putenv("HS20TEST=$test");
 
 $last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret);
 
diff --git a/hs20/server/www/terms.php b/hs20/server/www/terms.php
new file mode 100644
index 0000000..e269b3c
--- /dev/null
+++ b/hs20/server/www/terms.php
@@ -0,0 +1,81 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+   die($sqliteerror);
+}
+
+if (!isset($_GET["addr"])) {
+   die("Missing addr parameter");
+}
+$addr = $_GET["addr"];
+
+$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes";
+
+$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?");
+$res->execute(array($addr));
+$row = $res->fetch();
+if (!$row) {
+   die("No pending session for the specified MAC address");
+}
+$identity = $row[0];
+?>
+<html>
+<head><title>HS 2.0 Terms and Conditions</title></head>
+<body>
+
+<?php
+
+if (!$accept) {
+   echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n";
+   readfile($t_c_file);
+} else {
+   $res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?");
+   if (!$res->execute(array($t_c_timestamp, $identity))) {
+      echo "<p>Failed to update user account.</p>";
+   } else {
+      $res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?");
+      $res->execute(array($addr));
+
+      echo "<p>Terms and conditions were accepted.</p>";
+   }
+
+   $fp = fsockopen($hostapd_ctrl);
+   if (!$fp) {
+      die("Could not connect to hostapd(AS)");
+   }
+
+   fwrite($fp, "DAC_REQUEST coa $addr t_c_clear");
+   fclose($fp);
+
+   $waiting = true;
+   $ack = false;
+   for ($i = 1; $i <= 10; $i++) {
+      $res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?");
+      $res->execute(array($addr));
+      $row = $res->fetch();
+      if (!$row) {
+         die("No current session for the specified MAC address");
+      }
+      if (strlen($row[0]) > 0)
+            $waiting = $row[0] == 1;
+      if (strlen($row[1]) > 0)
+            $ack = $row[1] == 1;
+      $res->closeCursor();
+      if (!$waiting)
+         break;
+      sleep(1);
+   }
+   if ($ack) {
+      echo "<P>Filtering disabled.</P>\n";
+   } else {
+      echo "<P>Failed to disable filtering.</P>\n";
+   }
+}
+
+?>
+
+</body>
+</html>
diff --git a/hs20/server/www/users.php b/hs20/server/www/users.php
index c340a33..f546de3 100644
--- a/hs20/server/www/users.php
+++ b/hs20/server/www/users.php
@@ -107,6 +107,10 @@
   $db->exec("UPDATE users SET osu_user='$osu_user', osu_password='$osu_password' WHERE rowid=$id");
 }
 
+if ($cmd == 'clear-t-c' && $id > 0) {
+	$db->exec("UPDATE users SET t_c_timestamp=NULL WHERE rowid=$id");
+}
+
 $dump = 0;
 
 if ($id > 0) {
@@ -187,6 +191,9 @@
 }
 echo "<br>\n";
 
+if (strncmp($row['identity'], "cert-", 5) != 0)
+   echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n";
+
 echo "<form>Policy: <select name=\"policy\" " .
 	"onChange=\"window.location='users.php?cmd=policy&id=" .
 	$row['rowid'] . "&policy=' + this.value;\">\n";
@@ -234,6 +241,13 @@
 echo "<input type=\"submit\" value=\"Set OSU credentials\">\n";
 echo "</form>\n";
 
+if (strlen($row['t_c_timestamp']) > 0) {
+	echo "<br>\n";
+	echo "<a href=\"users.php?cmd=clear-t-c&id=" .
+		$row['rowid'] .
+		"\">Clear Terms and Conditions acceptance</a><br>\n";
+}
+
 echo "<hr>\n";
 
 $user = $row['identity'];
@@ -302,10 +316,10 @@
 echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] ";
 echo "<br>\n";
 
-echo "<table border=1>\n";
-echo "<tr><th>User<th>Realm<th>Remediation<th>Policy<th>Account type<th>Phase 2 method(s)<th>DevId\n";
+echo "<table border=1 cellspacing=0 cellpadding=0>\n";
+echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n";
 
-$res = $db->query('SELECT rowid,* FROM users WHERE phase2=1');
+$res = $db->query('SELECT rowid,* FROM users WHERE phase2=1 ORDER BY identity');
 foreach ($res as $row) {
 	echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " .
 	    $row['identity'] . " </a>";
@@ -313,7 +327,7 @@
 	$rem = $row['remediation'];
 	echo "<td>";
 	if ($rem == "") {
-		echo "Not required";
+		echo "-";
 	} else if ($rem == "user") {
 		echo "User";
 	} else if ($rem == "policy") {
@@ -328,16 +342,18 @@
 	  echo "<td>shared";
 	else
 	  echo "<td>default";
-	echo "<td>" . $row['methods'];
+	echo "<td><small>" . $row['methods'] . "</small>";
 	echo "<td>";
 	$xml = xml_parser_create();
 	xml_parse_into_struct($xml, $row['devinfo'], $devinfo);
 	foreach($devinfo as $k) {
 	  if ($k['tag'] == 'DEVID') {
-	    echo $k['value'];
+	    echo "<small>" . $k['value'] . "</small>";
 	    break;
 	  }
 	}
+	echo "<td><small>" . $row['mac_addr'] . "</small>";
+	echo "<td><small>" . $row['t_c_timestamp'] . "</small>";
 	echo "\n";
 }
 echo "</table>\n";
diff --git a/src/ap/Makefile b/src/ap/Makefile
index b8c167c..9b07ee1 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -10,6 +10,7 @@
 
 CFLAGS += -DHOSTAPD
 CFLAGS += -DNEED_AP_MLME
+CFLAGS += -DCONFIG_ETH_P_OUI
 CFLAGS += -DCONFIG_HS20
 CFLAGS += -DCONFIG_INTERWORKING
 CFLAGS += -DCONFIG_IEEE80211R
@@ -34,6 +35,7 @@
 	dhcp_snoop.o \
 	drv_callbacks.o \
 	eap_user_db.o \
+	eth_p_oui.o \
 	gas_serv.o \
 	hostapd.o \
 	hs20.o \
diff --git a/src/ap/acs.c b/src/ap/acs.c
index aa59058..6d4c041 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -314,7 +314,7 @@
 
 	/* TODO: figure out the best multiplier for noise floor base */
 	factor = pow(10, survey->nf / 5.0L) +
-		(busy / total) *
+		(total ? (busy / total) : 0) *
 		pow(2, pow(10, (long double) survey->nf / 10.0L) -
 		    pow(10, (long double) min_nf / 10.0L));
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 07310f9..f9b6f29 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "crypto/sha1.h"
+#include "crypto/tls.h"
 #include "radius/radius_client.h"
 #include "common/ieee802_11_defs.h"
 #include "common/eapol_common.h"
@@ -103,11 +104,13 @@
 	bss->rkh_neg_timeout = 60;
 	bss->rkh_pull_timeout = 1000;
 	bss->rkh_pull_retries = 4;
+	bss->r0_key_lifetime = 1209600;
 #endif /* CONFIG_IEEE80211R_AP */
 
 	bss->radius_das_time_window = 300;
 
 	bss->sae_anti_clogging_threshold = 5;
+	bss->sae_sync = 5;
 
 	bss->gas_frag_limit = 1400;
 
@@ -123,6 +126,11 @@
 #ifdef CONFIG_MBO
 	bss->mbo_cell_data_conn_pref = -1;
 #endif /* CONFIG_MBO */
+
+	/* Disable TLS v1.3 by default for now to avoid interoperability issue.
+	 * This can be enabled by default once the implementation has been fully
+	 * completed and tested with other implementations. */
+	bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
 }
 
 
@@ -407,6 +415,7 @@
 	hostapd_config_free_radius_attr(user->accept_attr);
 	os_free(user->identity);
 	bin_clear_free(user->password, user->password_len);
+	bin_clear_free(user->salt, user->salt_len);
 	os_free(user);
 }
 
@@ -473,6 +482,22 @@
 }
 
 
+static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
+{
+	struct sae_password_entry *pw, *tmp;
+
+	pw = conf->sae_passwords;
+	conf->sae_passwords = NULL;
+	while (pw) {
+		tmp = pw;
+		pw = pw->next;
+		str_clear_free(tmp->password);
+		os_free(tmp->identifier);
+		os_free(tmp);
+	}
+}
+
+
 void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
 	if (conf == NULL)
@@ -576,6 +601,7 @@
 
 	os_free(conf->roaming_consortium);
 	os_free(conf->venue_name);
+	os_free(conf->venue_url);
 	os_free(conf->nai_realm_data);
 	os_free(conf->network_auth_type);
 	os_free(conf->anqp_3gpp_cell_net);
@@ -605,11 +631,21 @@
 				os_free(p->icons[j]);
 			os_free(p->icons);
 			os_free(p->osu_nai);
+			os_free(p->osu_nai2);
 			os_free(p->service_desc);
 		}
 		os_free(conf->hs20_osu_providers);
 	}
+	if (conf->hs20_operator_icon) {
+		size_t i;
+
+		for (i = 0; i < conf->hs20_operator_icon_count; i++)
+			os_free(conf->hs20_operator_icon[i]);
+		os_free(conf->hs20_operator_icon);
+	}
 	os_free(conf->subscr_remediation_url);
+	os_free(conf->t_c_filename);
+	os_free(conf->t_c_server_url);
 #endif /* CONFIG_HS20 */
 
 	wpabuf_free(conf->vendor_elements);
@@ -640,7 +676,7 @@
 	wpabuf_free(conf->dpp_csign);
 #endif /* CONFIG_DPP */
 
-	os_free(conf->sae_password);
+	hostapd_config_free_sae_passwords(conf);
 
 	os_free(conf);
 }
@@ -936,7 +972,9 @@
 
 	if (full_config && bss->wps_state && bss->wpa &&
 	    (!(bss->wpa & 2) ||
-	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+				    WPA_CIPHER_CCMP_256 |
+				    WPA_CIPHER_GCMP_256)))) {
 		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
 			   "WPA2/CCMP/GCMP forced WPS to be disabled");
 		bss->wps_state = 0;
@@ -1046,8 +1084,12 @@
 
 	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
 		bss->rsn_pairwise = bss->wpa_pairwise;
-	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
-						    bss->rsn_pairwise);
+	if (bss->group_cipher)
+		bss->wpa_group = bss->group_cipher;
+	else
+		bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+							    bss->wpa_pairwise,
+							    bss->rsn_pairwise);
 	if (!bss->wpa_group_rekey_set)
 		bss->wpa_group_rekey = bss->wpa_group == WPA_CIPHER_TKIP ?
 			600 : 86400;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 89bf289..778366d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -160,6 +160,8 @@
 	} methods[EAP_MAX_METHODS];
 	u8 *password;
 	size_t password_len;
+	u8 *salt;
+	size_t salt_len; /* non-zero when password is salted */
 	int phase2;
 	int force_version;
 	unsigned int wildcard_prefix:1;
@@ -169,6 +171,7 @@
 	unsigned int macacl:1;
 	int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
 	struct hostapd_radius_attr *accept_attr;
+	u32 t_c_timestamp;
 };
 
 struct hostapd_radius_attr {
@@ -201,6 +204,12 @@
 	u8 name[252];
 };
 
+struct hostapd_venue_url {
+	u8 venue_number;
+	u8 url_len;
+	u8 url[254];
+};
+
 #define MAX_NAI_REALMS 10
 #define MAX_NAI_REALMLEN 255
 #define MAX_NAI_EAP_METHODS 5
@@ -230,6 +239,12 @@
 	char realm[];
 };
 
+struct sae_password_entry {
+	struct sae_password_entry *next;
+	char *password;
+	char *identifier;
+	u8 peer_addr[ETH_ALEN];
+};
 
 /**
  * struct hostapd_bss_config - Per-BSS configuration
@@ -248,7 +263,8 @@
 	int max_num_sta; /* maximum number of STAs in station table */
 
 	int dtim_period;
-	int bss_load_update_period;
+	unsigned int bss_load_update_period;
+	unsigned int chan_util_avg_period;
 
 	int ieee802_1x; /* use IEEE 802.1X */
 	int eapol_version;
@@ -325,6 +341,7 @@
 		PSK_RADIUS_REQUIRED = 2
 	} wpa_psk_radius;
 	int wpa_pairwise;
+	int group_cipher; /* wpa_group value override from configuation */
 	int wpa_group;
 	int wpa_group_rekey;
 	int wpa_group_rekey_set;
@@ -342,7 +359,7 @@
 	/* IEEE 802.11r - Fast BSS Transition */
 	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
 	u8 r1_key_holder[FT_R1KH_ID_LEN];
-	u32 r0_key_lifetime;
+	u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
 	int rkh_pos_timeout;
 	int rkh_neg_timeout;
 	int rkh_pull_timeout; /* ms */
@@ -353,6 +370,7 @@
 	int pmk_r1_push;
 	int ft_over_ds;
 	int ft_psk_generate_local;
+	int r1_max_key_lifetime;
 #endif /* CONFIG_IEEE80211R_AP */
 
 	char *ctrl_interface; /* directory for UNIX domain sockets */
@@ -479,6 +497,7 @@
 	int time_advertisement;
 	char *time_zone;
 	int wnm_sleep_mode;
+	int wnm_sleep_mode_no_keys;
 	int bss_transition;
 
 	/* IEEE 802.11u - Interworking */
@@ -501,6 +520,10 @@
 	unsigned int venue_name_count;
 	struct hostapd_lang_string *venue_name;
 
+	/* Venue URL duples */
+	unsigned int venue_url_count;
+	struct hostapd_venue_url *venue_url;
+
 	/* IEEE 802.11u - Network Authentication Type */
 	u8 *network_auth_type;
 	size_t network_auth_type_len;
@@ -562,13 +585,20 @@
 		char **icons;
 		size_t icons_count;
 		char *osu_nai;
+		char *osu_nai2;
 		unsigned int service_desc_count;
 		struct hostapd_lang_string *service_desc;
 	} *hs20_osu_providers, *last_osu;
 	size_t hs20_osu_providers_count;
+	size_t hs20_osu_providers_nai_count;
+	char **hs20_operator_icon;
+	size_t hs20_operator_icon_count;
 	unsigned int hs20_deauth_req_timeout;
 	char *subscr_remediation_url;
 	u8 subscr_remediation_method;
+	char *t_c_filename;
+	u32 t_c_timestamp;
+	char *t_c_server_url;
 #endif /* CONFIG_HS20 */
 
 	u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
@@ -581,8 +611,10 @@
 	struct wpabuf *assocresp_elements;
 
 	unsigned int sae_anti_clogging_threshold;
+	unsigned int sae_sync;
+	int sae_require_mfp;
 	int *sae_groups;
-	char *sae_password;
+	struct sae_password_entry *sae_passwords;
 
 	char *wowlan_triggers; /* Wake-on-WLAN triggers */
 
@@ -652,6 +684,8 @@
 	char owe_transition_ifname[IFNAMSIZ + 1];
 	int *owe_groups;
 #endif /* CONFIG_OWE */
+
+	int coloc_intf_reporting;
 };
 
 /**
@@ -796,6 +830,11 @@
 	struct he_phy_capabilities_info he_phy_capab;
 	struct he_operation he_op;
 #endif /* CONFIG_IEEE80211AX */
+
+	/* VHT enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_VHT_ENABLED BIT(0)
+#define CH_SWITCH_VHT_DISABLED BIT(1)
+	unsigned int ch_switch_vht_config;
 };
 
 
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 8f4d839..728d7f0 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -185,6 +185,13 @@
 	}
 #endif /* CONFIG_MBO */
 
+#ifdef CONFIG_OWE
+	pos = hostapd_eid_owe_trans(hapd, buf, sizeof(buf));
+	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+	    add_buf_data(&proberesp, buf, pos - buf) < 0)
+		goto fail;
+#endif /* CONFIG_OWE */
+
 	add_buf(&beacon, hapd->conf->vendor_elements);
 	add_buf(&proberesp, hapd->conf->vendor_elements);
 	add_buf(&assocresp, hapd->conf->assocresp_elements);
@@ -736,6 +743,15 @@
 		sta = ap_get_sta(hapd, dst);
 		if (!sta || !(sta->flags & WLAN_STA_ASSOC))
 			bssid = wildcard_bssid;
+	} else if (is_broadcast_ether_addr(dst) &&
+		   len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+		/*
+		 * The only current use case of Public Action frames with
+		 * broadcast destination address is DPP PKEX. That case is
+		 * directing all devices and not just the STAs within the BSS,
+		 * so have to use the wildcard BSSID value.
+		 */
+		bssid = wildcard_bssid;
 	}
 	return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
 					 hapd->own_addr, bssid, data, len, 0);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index bf8169d..db93fde 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -103,6 +103,14 @@
 				     unsigned int freq,
 				     unsigned int wait, const u8 *dst,
 				     const u8 *data, size_t len);
+static inline void
+hostapd_drv_send_action_cancel_wait(struct hostapd_data *hapd)
+{
+	if (!hapd->driver || !hapd->driver->send_action_cancel_wait ||
+	    !hapd->drv_priv)
+		return;
+	hapd->driver->send_action_cancel_wait(hapd->drv_priv);
+}
 int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
 			 u16 auth_alg);
 int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index a20f49f..95d004e 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -77,12 +77,20 @@
 			goto out;
 		user->password_len = eap_user->password_len;
 		user->password_hash = eap_user->password_hash;
+		if (eap_user->salt && eap_user->salt_len) {
+			user->salt = os_memdup(eap_user->salt,
+					       eap_user->salt_len);
+			if (!user->salt)
+				goto out;
+			user->salt_len = eap_user->salt_len;
+		}
 	}
 	user->force_version = eap_user->force_version;
 	user->macacl = eap_user->macacl;
 	user->ttls_auth = eap_user->ttls_auth;
 	user->remediation = eap_user->remediation;
 	user->accept_attr = eap_user->accept_attr;
+	user->t_c_timestamp = eap_user->t_c_timestamp;
 	rv = 0;
 
 out:
@@ -128,6 +136,7 @@
 #ifdef CONFIG_HS20
 	srv.subscr_remediation_url = conf->subscr_remediation_url;
 	srv.subscr_remediation_method = conf->subscr_remediation_method;
+	srv.t_c_server_url = conf->t_c_server_url;
 #endif /* CONFIG_HS20 */
 	srv.erp = conf->eap_server_erp;
 	srv.erp_domain = conf->erp_domain;
@@ -146,6 +155,40 @@
 #endif /* RADIUS_SERVER */
 
 
+#ifdef EAP_TLS_FUNCS
+static void authsrv_tls_event(void *ctx, enum tls_event ev,
+			      union tls_event_data *data)
+{
+	switch (ev) {
+	case TLS_CERT_CHAIN_SUCCESS:
+		wpa_printf(MSG_DEBUG, "authsrv: remote certificate verification success");
+		break;
+	case TLS_CERT_CHAIN_FAILURE:
+		wpa_printf(MSG_INFO, "authsrv: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
+			   data->cert_fail.reason,
+			   data->cert_fail.depth,
+			   data->cert_fail.subject,
+			   data->cert_fail.reason_txt);
+		break;
+	case TLS_PEER_CERTIFICATE:
+		wpa_printf(MSG_DEBUG, "authsrv: peer certificate: depth=%d serial_num=%s subject=%s",
+			   data->peer_cert.depth,
+			   data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
+			   data->peer_cert.subject);
+		break;
+	case TLS_ALERT:
+		if (data->alert.is_local)
+			wpa_printf(MSG_DEBUG, "authsrv: local TLS alert: %s",
+				   data->alert.description);
+		else
+			wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
+				   data->alert.description);
+		break;
+	}
+}
+#endif /* EAP_TLS_FUNCS */
+
+
 int authsrv_init(struct hostapd_data *hapd)
 {
 #ifdef EAP_TLS_FUNCS
@@ -158,6 +201,8 @@
 		os_memset(&conf, 0, sizeof(conf));
 		conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
 		conf.tls_flags = hapd->conf->tls_flags;
+		conf.event_cb = authsrv_tls_event;
+		conf.cb_ctx = hapd;
 		hapd->ssl_ctx = tls_init(&conf);
 		if (hapd->ssl_ctx == NULL) {
 			wpa_printf(MSG_ERROR, "Failed to initialize TLS");
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 3ea28a7..59bd4af 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -16,6 +16,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/hw_features_common.h"
+#include "common/wpa_ctrl.h"
 #include "wps/wps_defs.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
@@ -30,6 +31,7 @@
 #include "hs20.h"
 #include "dfs.h"
 #include "taxonomy.h"
+#include "ieee802_11_auth.h"
 
 
 #ifdef NEED_AP_MLME
@@ -363,67 +365,6 @@
 }
 
 
-#ifdef CONFIG_OWE
-static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
-{
-	return hapd->conf->owe_transition_ssid_len > 0 &&
-		!is_zero_ether_addr(hapd->conf->owe_transition_bssid);
-}
-#endif /* CONFIG_OWE */
-
-
-static size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
-{
-#ifdef CONFIG_OWE
-	if (!hostapd_eid_owe_trans_enabled(hapd))
-		return 0;
-	return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
-#else /* CONFIG_OWE */
-	return 0;
-#endif /* CONFIG_OWE */
-}
-
-
-static u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
-				  size_t len)
-{
-#ifdef CONFIG_OWE
-	u8 *pos = eid;
-	size_t elen;
-
-	if (hapd->conf->owe_transition_ifname[0] &&
-	    !hostapd_eid_owe_trans_enabled(hapd))
-		hostapd_owe_trans_get_info(hapd);
-
-	if (!hostapd_eid_owe_trans_enabled(hapd))
-		return pos;
-
-	elen = hostapd_eid_owe_trans_len(hapd);
-	if (len < elen) {
-		wpa_printf(MSG_DEBUG,
-			   "OWE: Not enough room in the buffer for OWE IE");
-		return pos;
-	}
-
-	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
-	*pos++ = elen - 2;
-	WPA_PUT_BE24(pos, OUI_WFA);
-	pos += 3;
-	*pos++ = OWE_OUI_TYPE;
-	os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
-	pos += ETH_ALEN;
-	*pos++ = hapd->conf->owe_transition_ssid_len;
-	os_memcpy(pos, hapd->conf->owe_transition_ssid,
-		  hapd->conf->owe_transition_ssid_len);
-	pos += hapd->conf->owe_transition_ssid_len;
-
-	return pos;
-#else /* CONFIG_OWE */
-	return eid;
-#endif /* CONFIG_OWE */
-}
-
-
 static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 				   const struct ieee80211_mgmt *req,
 				   int is_p2p, size_t *resp_len)
@@ -512,8 +453,9 @@
 	/* Extended supported rates */
 	pos = hostapd_eid_ext_supp_rates(hapd, pos);
 
-	/* RSN, MDIE, WPA */
-	pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+	/* RSN, MDIE */
+	if (hapd->conf->wpa != WPA_PROTO_WPA)
+		pos = hostapd_eid_wpa(hapd, pos, epos - pos);
 
 	pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
 
@@ -576,6 +518,10 @@
 		pos = hostapd_eid_vendor_vht(hapd, pos);
 #endif /* CONFIG_IEEE80211AC */
 
+	/* WPA */
+	if (hapd->conf->wpa == WPA_PROTO_WPA)
+		pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
 	/* Wi-Fi Alliance WMM */
 	pos = hostapd_eid_wmm(hapd, pos);
 
@@ -791,6 +737,11 @@
 	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;
 
 	if (len < IEEE80211_HDRLEN)
 		return;
@@ -799,6 +750,17 @@
 		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);
+	if (ret == HOSTAPD_ACL_REJECT) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"Ignore Probe Request frame from " MACSTR
+			" due to ACL reject ", MAC2STR(mgmt->sa));
+		return;
+	}
+
 	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
 		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
 					    mgmt->sa, mgmt->da, mgmt->bssid,
@@ -993,6 +955,9 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
+	wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
+		     " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+
 	resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
 				      &resp_len);
 	if (resp == NULL)
@@ -1192,9 +1157,11 @@
 	/* Extended supported rates */
 	tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
 
-	/* RSN, MDIE, WPA */
-	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
-				  tailpos);
+	/* RSN, MDIE */
+	if (hapd->conf->wpa != WPA_PROTO_WPA)
+		tailpos = hostapd_eid_wpa(hapd, tailpos,
+					  tail + BEACON_TAIL_BUF_SIZE -
+					  tailpos);
 
 	tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
 					       tail + BEACON_TAIL_BUF_SIZE -
@@ -1263,6 +1230,12 @@
 		tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AC */
 
+	/* WPA */
+	if (hapd->conf->wpa == WPA_PROTO_WPA)
+		tailpos = hostapd_eid_wpa(hapd, tailpos,
+					  tail + BEACON_TAIL_BUF_SIZE -
+					  tailpos);
+
 	/* Wi-Fi Alliance WMM */
 	tailpos = hostapd_eid_wmm(hapd, tailpos);
 
diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c
index fb63942..725d3cd 100644
--- a/src/ap/bss_load.c
+++ b/src/ap/bss_load.c
@@ -16,11 +16,35 @@
 #include "beacon.h"
 
 
+static int get_bss_load_update_timeout(struct hostapd_data *hapd,
+				       unsigned int *sec, unsigned int *usec)
+{
+	unsigned int update_period = hapd->conf->bss_load_update_period;
+	unsigned int beacon_int = hapd->iconf->beacon_int;
+	unsigned int update_timeout;
+
+	if (!update_period || !beacon_int) {
+		wpa_printf(MSG_ERROR,
+			   "BSS Load: Invalid BSS load update configuration (period=%u beacon_int=%u)",
+			   update_period, beacon_int);
+		return -1;
+	}
+
+	update_timeout = update_period * beacon_int;
+
+	*sec = ((update_timeout / 1000) * 1024) / 1000;
+	*usec = (update_timeout % 1000) * 1024;
+
+	return 0;
+}
+
+
 static void update_channel_utilization(void *eloop_data, void *user_data)
 {
 	struct hostapd_data *hapd = eloop_data;
 	unsigned int sec, usec;
 	int err;
+	struct hostapd_iface *iface = hapd->iface;
 
 	if (!(hapd->beacon_set_done && hapd->started))
 		return;
@@ -33,8 +57,24 @@
 
 	ieee802_11_set_beacon(hapd);
 
-	sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
-	usec = (hapd->bss_load_update_timeout % 1000) * 1024;
+	if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
+		return;
+
+	if (hapd->conf->chan_util_avg_period) {
+		iface->chan_util_samples_sum += iface->channel_utilization;
+		iface->chan_util_num_sample_periods +=
+			hapd->conf->bss_load_update_period;
+		if (iface->chan_util_num_sample_periods >=
+		    hapd->conf->chan_util_avg_period) {
+			iface->chan_util_average =
+				iface->chan_util_samples_sum /
+				(iface->chan_util_num_sample_periods /
+				 hapd->conf->bss_load_update_period);
+			iface->chan_util_samples_sum = 0;
+			iface->chan_util_num_sample_periods = 0;
+		}
+	}
+
 	eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
 			       NULL);
 }
@@ -42,17 +82,11 @@
 
 int bss_load_update_init(struct hostapd_data *hapd)
 {
-	struct hostapd_bss_config *conf = hapd->conf;
-	struct hostapd_config *iconf = hapd->iconf;
 	unsigned int sec, usec;
 
-	if (!conf->bss_load_update_period || !iconf->beacon_int)
+	if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
 		return -1;
 
-	hapd->bss_load_update_timeout = conf->bss_load_update_period *
-					iconf->beacon_int;
-	sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
-	usec = (hapd->bss_load_update_timeout % 1000) * 1024;
 	eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
 			       NULL);
 	return 0;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1a2b4e5..21b813e 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -26,6 +26,30 @@
 #include "taxonomy.h"
 
 
+static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
+					   size_t curr_len, const u8 *mcs_set)
+{
+	int ret;
+	size_t len = curr_len;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "ht_mcs_bitmask=");
+	if (os_snprintf_error(buflen - len, ret))
+		return len;
+	len += ret;
+
+	/* 77 first bits (+ 3 reserved bits) */
+	len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
+
+	ret = os_snprintf(buf + len, buflen - len, "\n");
+	if (os_snprintf_error(buflen - len, ret))
+		return curr_len;
+	len += ret;
+
+	return len;
+}
+
+
 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
 				 struct sta_info *sta,
 				 char *buf, size_t buflen)
@@ -111,6 +135,31 @@
 	if (!os_snprintf_error(buflen - len, ret))
 		len += ret;
 
+	if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "rx_vht_mcs_map=%04x\n"
+				  "tx_vht_mcs_map=%04x\n",
+				  le_to_host16(sta->vht_capabilities->
+					       vht_supported_mcs_set.rx_map),
+				  le_to_host16(sta->vht_capabilities->
+					       vht_supported_mcs_set.tx_map));
+		if (!os_snprintf_error(buflen - len, ret))
+			len += ret;
+	}
+
+	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
+		len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
+						   sta->ht_capabilities->
+						   supported_mcs_set);
+	}
+
+	if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "last_ack_signal=%d\n", data.last_ack_rssi);
+		if (!os_snprintf_error(buflen - len, ret))
+			len += ret;
+	}
+
 	return len;
 }
 
@@ -245,6 +294,53 @@
 		len += os_snprintf(buf + len, buflen - len, "\n");
 	}
 
+	if (sta->power_capab) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "min_txpower=%d\n"
+				  "max_txpower=%d\n",
+				  sta->min_tx_power, sta->max_tx_power);
+		if (!os_snprintf_error(buflen - len, ret))
+			len += ret;
+	}
+
+#ifdef CONFIG_IEEE80211AC
+	if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
+		res = os_snprintf(buf + len, buflen - len,
+				  "vht_caps_info=0x%08x\n",
+				  le_to_host32(sta->vht_capabilities->
+					       vht_capabilities_info));
+		if (!os_snprintf_error(buflen - len, res))
+			len += res;
+	}
+#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",
+				  le_to_host16(sta->ht_capabilities->
+					       ht_capabilities_info));
+		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])) {
+		len += os_snprintf(buf + len, buflen - len, "ext_capab=");
+		len += wpa_snprintf_hex(buf + len, buflen - len,
+					sta->ext_capability + 1,
+					sta->ext_capability[0]);
+		len += os_snprintf(buf + len, buflen - len, "\n");
+	}
+
+	if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "wds_sta_ifname=%s\n", sta->ifname_wds);
+		if (!os_snprintf_error(buflen - len, ret))
+			len += ret;
+	}
+
 	return len;
 }
 
@@ -546,7 +642,8 @@
 			      size_t buflen)
 {
 	struct hostapd_iface *iface = hapd->iface;
-	int len = 0, ret;
+	struct hostapd_hw_modes *mode = iface->current_mode;
+	int len = 0, ret, j;
 	size_t i;
 
 	ret = os_snprintf(buf + len, buflen - len,
@@ -606,13 +703,17 @@
 			  "channel=%u\n"
 			  "secondary_channel=%d\n"
 			  "ieee80211n=%d\n"
-			  "ieee80211ac=%d\n",
+			  "ieee80211ac=%d\n"
+			  "beacon_int=%u\n"
+			  "dtim_period=%d\n",
 			  iface->conf->channel,
 			  iface->conf->ieee80211n && !hapd->conf->disable_11n ?
 			  iface->conf->secondary_channel : 0,
 			  iface->conf->ieee80211n && !hapd->conf->disable_11n,
 			  iface->conf->ieee80211ac &&
-			  !hapd->conf->disable_11ac);
+			  !hapd->conf->disable_11ac,
+			  iface->conf->beacon_int,
+			  hapd->conf->dtim_period);
 	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
@@ -620,15 +721,76 @@
 		ret = os_snprintf(buf + len, buflen - len,
 				  "vht_oper_chwidth=%d\n"
 				  "vht_oper_centr_freq_seg0_idx=%d\n"
-				  "vht_oper_centr_freq_seg1_idx=%d\n",
+				  "vht_oper_centr_freq_seg1_idx=%d\n"
+				  "vht_caps_info=%08x\n",
 				  iface->conf->vht_oper_chwidth,
 				  iface->conf->vht_oper_centr_freq_seg0_idx,
-				  iface->conf->vht_oper_centr_freq_seg1_idx);
+				  iface->conf->vht_oper_centr_freq_seg1_idx,
+				  iface->conf->vht_capab);
 		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
 
+	if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
+		u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
+		u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
+
+		ret = os_snprintf(buf + len, buflen - len,
+				  "rx_vht_mcs_map=%04x\n"
+				  "tx_vht_mcs_map=%04x\n",
+				  rxmap, txmap);
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+	}
+
+	if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "ht_caps_info=%04x\n",
+				  hapd->iconf->ht_capab);
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+	}
+
+	if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
+		len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
+						   mode->mcs_set);
+	}
+
+	if (iface->current_rates && iface->num_rates) {
+		ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+
+		for (j = 0; j < iface->num_rates; j++) {
+			ret = os_snprintf(buf + len, buflen - len, "%s%02x",
+					  j > 0 ? " " : "",
+					  iface->current_rates[j].rate / 5);
+			if (os_snprintf_error(buflen - len, ret))
+				return len;
+			len += ret;
+		}
+		ret = os_snprintf(buf + len, buflen - len, "\n");
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+	}
+
+	for (j = 0; mode && j < mode->num_channels; j++) {
+		if (mode->channels[j].freq == iface->freq) {
+			ret = os_snprintf(buf + len, buflen - len,
+					  "max_txpower=%u\n",
+					  mode->channels[j].max_tx_power);
+			if (os_snprintf_error(buflen - len, ret))
+				return len;
+			len += ret;
+			break;
+		}
+	}
+
 	for (i = 0; i < iface->num_bss; i++) {
 		struct hostapd_data *bss = iface->bss[i];
 		ret = os_snprintf(buf + len, buflen - len,
@@ -647,6 +809,15 @@
 		len += ret;
 	}
 
+	if (hapd->conf->chan_util_avg_period) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "chan_util_avg=%u\n",
+				  iface->chan_util_average);
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+	}
+
 	return len;
 }
 
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 5a0d781..993dd19 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -1111,7 +1111,8 @@
 		return 1;
 	}
 
-	if (ieee80211_is_dfs(iface->freq)) {
+	if (ieee80211_is_dfs(iface->freq, iface->hw_features,
+			     iface->num_hw_features)) {
 		wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
 			   __func__, iface->freq);
 		return 0;
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index aae2910..4ec044e 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -20,7 +20,10 @@
 #include "dpp_hostapd.h"
 
 
+static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
 static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
+static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
+static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
 
 static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -30,7 +33,7 @@
 {
 	struct dpp_configurator *conf;
 
-	dl_list_for_each(conf, &hapd->dpp_configurator,
+	dl_list_for_each(conf, &hapd->iface->interfaces->dpp_configurator,
 			 struct dpp_configurator, list) {
 		if (conf->id == id)
 			return conf;
@@ -44,8 +47,8 @@
 	struct dpp_bootstrap_info *bi;
 	unsigned int max_id = 0;
 
-	dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info,
-			 list) {
+	dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
+			 struct dpp_bootstrap_info, list) {
 		if (bi->id > max_id)
 			max_id = bi->id;
 	}
@@ -69,12 +72,16 @@
 		return -1;
 
 	bi->id = hapd_dpp_next_id(hapd);
-	dl_list_add(&hapd->dpp_bootstrap, &bi->list);
+	dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
 
 	if (auth && auth->response_pending &&
 	    dpp_notify_new_qr_code(auth, bi) == 1) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Sending out pending authentication response");
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+			" freq=%u type=%d",
+			MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+			DPP_PA_AUTHENTICATION_RESP);
 		hostapd_drv_send_action(hapd, auth->curr_freq, 0,
 					auth->peer_mac_addr,
 					wpabuf_head(hapd->dpp_auth->resp_msg),
@@ -175,7 +182,7 @@
 		    info ? "I:" : "", info ? info : "", info ? ";" : "",
 		    pk);
 	bi->id = hapd_dpp_next_id(hapd);
-	dl_list_add(&hapd->dpp_bootstrap, &bi->list);
+	dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
 	ret = bi->id;
 	bi = NULL;
 fail:
@@ -196,8 +203,8 @@
 {
 	struct dpp_bootstrap_info *bi;
 
-	dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info,
-			 list) {
+	dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
+			 struct dpp_bootstrap_info, list) {
 		if (bi->id == id)
 			return bi;
 	}
@@ -205,12 +212,12 @@
 }
 
 
-static int dpp_bootstrap_del(struct hostapd_data *hapd, unsigned int id)
+static int dpp_bootstrap_del(struct hapd_interfaces *ifaces, unsigned int id)
 {
 	struct dpp_bootstrap_info *bi, *tmp;
 	int found = 0;
 
-	dl_list_for_each_safe(bi, tmp, &hapd->dpp_bootstrap,
+	dl_list_for_each_safe(bi, tmp, &ifaces->dpp_bootstrap,
 			      struct dpp_bootstrap_info, list) {
 		if (id && bi->id != id)
 			continue;
@@ -237,7 +244,7 @@
 			return -1;
 	}
 
-	return dpp_bootstrap_del(hapd, id_val);
+	return dpp_bootstrap_del(hapd->iface->interfaces, id_val);
 }
 
 
@@ -274,11 +281,72 @@
 }
 
 
+static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
+						void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct dpp_authentication *auth = hapd->dpp_auth;
+
+	if (!auth || !auth->resp_msg)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Retry Authentication Response after timeout");
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d",
+		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+		DPP_PA_AUTHENTICATION_RESP);
+	hostapd_drv_send_action(hapd, auth->curr_freq, 500, auth->peer_mac_addr,
+				wpabuf_head(auth->resp_msg),
+				wpabuf_len(auth->resp_msg));
+}
+
+
+static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
+{
+	struct dpp_authentication *auth = hapd->dpp_auth;
+	unsigned int wait_time, max_tries;
+
+	if (!auth || !auth->resp_msg)
+		return;
+
+	if (hapd->dpp_resp_max_tries)
+		max_tries = hapd->dpp_resp_max_tries;
+	else
+		max_tries = 5;
+	auth->auth_resp_tries++;
+	if (auth->auth_resp_tries >= max_tries) {
+		wpa_printf(MSG_INFO,
+			   "DPP: No confirm received from initiator - stopping exchange");
+		hostapd_drv_send_action_cancel_wait(hapd);
+		dpp_auth_deinit(hapd->dpp_auth);
+		hapd->dpp_auth = NULL;
+		return;
+	}
+
+	if (hapd->dpp_resp_retry_time)
+		wait_time = hapd->dpp_resp_retry_time;
+	else
+		wait_time = 1000;
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Schedule retransmission of Authentication Response frame in %u ms",
+		wait_time);
+	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+	eloop_register_timeout(wait_time / 1000,
+			       (wait_time % 1000) * 1000,
+			       hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+}
+
+
 void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
 			   const u8 *data, size_t data_len, int ok)
 {
+	struct dpp_authentication *auth = hapd->dpp_auth;
+
 	wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d",
 		   MAC2STR(dst), ok);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+		" result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
 
 	if (!hapd->dpp_auth) {
 		wpa_printf(MSG_DEBUG,
@@ -289,6 +357,12 @@
 	if (hapd->dpp_auth->remove_on_tx_status) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Terminate authentication exchange due to an earlier error");
+		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+				     hapd, NULL);
+		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
+				     NULL);
+		hostapd_drv_send_action_cancel_wait(hapd);
 		dpp_auth_deinit(hapd->dpp_auth);
 		hapd->dpp_auth = NULL;
 		return;
@@ -296,6 +370,120 @@
 
 	if (hapd->dpp_auth_ok_on_ack)
 		hostapd_dpp_auth_success(hapd, 1);
+
+	if (!is_broadcast_ether_addr(dst) && !ok) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Unicast DPP Action frame was not ACKed");
+		if (auth->waiting_auth_resp) {
+			/* In case of DPP Authentication Request frame, move to
+			 * the next channel immediately. */
+			hostapd_drv_send_action_cancel_wait(hapd);
+			hostapd_dpp_auth_init_next(hapd);
+			return;
+		}
+		if (auth->waiting_auth_conf) {
+			hostapd_dpp_auth_resp_retry(hapd);
+			return;
+		}
+	}
+
+	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
+		/* Allow timeout handling to stop iteration if no response is
+		 * received from a peer that has ACKed a request. */
+		auth->auth_req_ack = 1;
+	}
+
+	if (!hapd->dpp_auth_ok_on_ack && hapd->dpp_auth->neg_freq > 0 &&
+	    hapd->dpp_auth->curr_freq != hapd->dpp_auth->neg_freq) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
+			   hapd->dpp_auth->curr_freq,
+			   hapd->dpp_auth->neg_freq);
+		hostapd_drv_send_action_cancel_wait(hapd);
+
+		if (hapd->dpp_auth->neg_freq !=
+		    (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
+			/* TODO: Listen operation on non-operating channel */
+			wpa_printf(MSG_INFO,
+				   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+				   hapd->dpp_auth->neg_freq, hapd->iface->freq);
+		}
+	}
+
+	if (hapd->dpp_auth_ok_on_ack)
+		hapd->dpp_auth_ok_on_ack = 0;
+}
+
+
+static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct dpp_authentication *auth = hapd->dpp_auth;
+	unsigned int freq;
+	struct os_reltime now, diff;
+	unsigned int wait_time, diff_ms;
+
+	if (!auth || !auth->waiting_auth_resp)
+		return;
+
+	wait_time = hapd->dpp_resp_wait_time ?
+		hapd->dpp_resp_wait_time : 2000;
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &hapd->dpp_last_init, &diff);
+	diff_ms = diff.sec * 1000 + diff.usec / 1000;
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
+		   wait_time, diff_ms);
+
+	if (auth->auth_req_ack && diff_ms >= wait_time) {
+		/* Peer ACK'ed Authentication Request frame, but did not reply
+		 * with Authentication Response frame within two seconds. */
+		wpa_printf(MSG_INFO,
+			   "DPP: No response received from responder - stopping initiation attempt");
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+		hostapd_drv_send_action_cancel_wait(hapd);
+		hostapd_dpp_listen_stop(hapd);
+		dpp_auth_deinit(auth);
+		hapd->dpp_auth = NULL;
+		return;
+	}
+
+	if (diff_ms >= wait_time) {
+		/* Authentication Request frame was not ACK'ed and no reply
+		 * was receiving within two seconds. */
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Continue Initiator channel iteration");
+		hostapd_drv_send_action_cancel_wait(hapd);
+		hostapd_dpp_listen_stop(hapd);
+		hostapd_dpp_auth_init_next(hapd);
+		return;
+	}
+
+	/* Driver did not support 2000 ms long wait_time with TX command, so
+	 * schedule listen operation to continue waiting for the response.
+	 *
+	 * DPP listen operations continue until stopped, so simply schedule a
+	 * new call to this function at the point when the two second reply
+	 * wait has expired. */
+	wait_time -= diff_ms;
+
+	freq = auth->curr_freq;
+	if (auth->neg_freq > 0)
+		freq = auth->neg_freq;
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Continue reply wait on channel %u MHz for %u ms",
+		   freq, wait_time);
+	hapd->dpp_in_response_listen = 1;
+
+	if (freq != (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
+		/* TODO: Listen operation on non-operating channel */
+		wpa_printf(MSG_INFO,
+			   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+			   freq, hapd->iface->freq);
+	}
+
+	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+			       hostapd_dpp_reply_wait_timeout, hapd, NULL);
 }
 
 
@@ -330,6 +518,7 @@
 	size_t pass_len = 0;
 	u8 psk[PMK_LEN];
 	int psk_set = 0;
+	char *group_id = NULL;
 
 	if (!cmd)
 		return;
@@ -365,14 +554,35 @@
 		psk_set = 1;
 	}
 
+	pos = os_strstr(cmd, " group_id=");
+	if (pos) {
+		size_t group_id_len;
+
+		pos += 10;
+		end = os_strchr(pos, ' ');
+		group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
+		group_id = os_malloc(group_id_len + 1);
+		if (!group_id)
+			goto fail;
+		os_memcpy(group_id, pos, group_id_len);
+		group_id[group_id_len] = '\0';
+	}
+
 	if (os_strstr(cmd, " conf=sta-")) {
 		conf_sta = os_zalloc(sizeof(struct dpp_configuration));
 		if (!conf_sta)
 			goto fail;
 		os_memcpy(conf_sta->ssid, ssid, ssid_len);
 		conf_sta->ssid_len = ssid_len;
-		if (os_strstr(cmd, " conf=sta-psk")) {
-			conf_sta->dpp = 0;
+		if (os_strstr(cmd, " conf=sta-psk") ||
+		    os_strstr(cmd, " conf=sta-sae") ||
+		    os_strstr(cmd, " conf=sta-psk-sae")) {
+			if (os_strstr(cmd, " conf=sta-psk-sae"))
+				conf_sta->akm = DPP_AKM_PSK_SAE;
+			else if (os_strstr(cmd, " conf=sta-sae"))
+				conf_sta->akm = DPP_AKM_SAE;
+			else
+				conf_sta->akm = DPP_AKM_PSK;
 			if (psk_set) {
 				os_memcpy(conf_sta->psk, psk, PMK_LEN);
 			} else {
@@ -381,10 +591,14 @@
 					goto fail;
 			}
 		} else if (os_strstr(cmd, " conf=sta-dpp")) {
-			conf_sta->dpp = 1;
+			conf_sta->akm = DPP_AKM_DPP;
 		} else {
 			goto fail;
 		}
+		if (os_strstr(cmd, " group_id=")) {
+			conf_sta->group_id = group_id;
+			group_id = NULL;
+		}
 	}
 
 	if (os_strstr(cmd, " conf=ap-")) {
@@ -393,8 +607,15 @@
 			goto fail;
 		os_memcpy(conf_ap->ssid, ssid, ssid_len);
 		conf_ap->ssid_len = ssid_len;
-		if (os_strstr(cmd, " conf=ap-psk")) {
-			conf_ap->dpp = 0;
+		if (os_strstr(cmd, " conf=ap-psk") ||
+		    os_strstr(cmd, " conf=ap-sae") ||
+		    os_strstr(cmd, " conf=ap-psk-sae")) {
+			if (os_strstr(cmd, " conf=ap-psk-sae"))
+				conf_ap->akm = DPP_AKM_PSK_SAE;
+			else if (os_strstr(cmd, " conf=ap-sae"))
+				conf_ap->akm = DPP_AKM_SAE;
+			else
+				conf_ap->akm = DPP_AKM_PSK;
 			if (psk_set) {
 				os_memcpy(conf_ap->psk, psk, PMK_LEN);
 			} else {
@@ -403,10 +624,14 @@
 					goto fail;
 			}
 		} else if (os_strstr(cmd, " conf=ap-dpp")) {
-			conf_ap->dpp = 1;
+			conf_ap->akm = DPP_AKM_DPP;
 		} else {
 			goto fail;
 		}
+		if (os_strstr(cmd, " group_id=")) {
+			conf_ap->group_id = group_id;
+			group_id = NULL;
+		}
 	}
 
 	pos = os_strstr(cmd, " expiry=");
@@ -437,12 +662,112 @@
 	auth->conf_sta = conf_sta;
 	auth->conf_ap = conf_ap;
 	auth->conf = conf;
+	os_free(group_id);
 	return;
 
 fail:
 	wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
 	dpp_configuration_free(conf_sta);
 	dpp_configuration_free(conf_ap);
+	os_free(group_id);
+}
+
+
+static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+
+	if (!hapd->dpp_auth)
+		return;
+	wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
+	hostapd_dpp_auth_init_next(hapd);
+}
+
+
+static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
+{
+	struct dpp_authentication *auth = hapd->dpp_auth;
+	const u8 *dst;
+	unsigned int wait_time, max_wait_time, freq, max_tries, used;
+	struct os_reltime now, diff;
+
+	if (!auth)
+		return -1;
+
+	if (auth->freq_idx == 0)
+		os_get_reltime(&hapd->dpp_init_iter_start);
+
+	if (auth->freq_idx >= auth->num_freq) {
+		auth->num_freq_iters++;
+		if (hapd->dpp_init_max_tries)
+			max_tries = hapd->dpp_init_max_tries;
+		else
+			max_tries = 5;
+		if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
+			wpa_printf(MSG_INFO,
+				   "DPP: No response received from responder - stopping initiation attempt");
+			wpa_msg(hapd->msg_ctx, MSG_INFO,
+				DPP_EVENT_AUTH_INIT_FAILED);
+			eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+					     hapd, NULL);
+			hostapd_drv_send_action_cancel_wait(hapd);
+			dpp_auth_deinit(hapd->dpp_auth);
+			hapd->dpp_auth = NULL;
+			return -1;
+		}
+		auth->freq_idx = 0;
+		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+		if (hapd->dpp_init_retry_time)
+			wait_time = hapd->dpp_init_retry_time;
+		else
+			wait_time = 10000;
+		os_get_reltime(&now);
+		os_reltime_sub(&now, &hapd->dpp_init_iter_start, &diff);
+		used = diff.sec * 1000 + diff.usec / 1000;
+		if (used > wait_time)
+			wait_time = 0;
+		else
+			wait_time -= used;
+		wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
+			   wait_time);
+		eloop_register_timeout(wait_time / 1000,
+				       (wait_time % 1000) * 1000,
+				       hostapd_dpp_init_timeout, hapd,
+				       NULL);
+		return 0;
+	}
+	freq = auth->freq[auth->freq_idx++];
+	auth->curr_freq = freq;
+
+	if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+		dst = broadcast;
+	else
+		dst = auth->peer_bi->mac_addr;
+	hapd->dpp_auth_ok_on_ack = 0;
+	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+	wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
+	max_wait_time = hapd->dpp_resp_wait_time ?
+		hapd->dpp_resp_wait_time : 2000;
+	if (wait_time > max_wait_time)
+		wait_time = max_wait_time;
+	wait_time += 10; /* give the driver some extra time to complete */
+	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+			       hostapd_dpp_reply_wait_timeout, hapd, NULL);
+	wait_time -= 10;
+	if (auth->neg_freq > 0 && freq != auth->neg_freq) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
+			   freq, auth->neg_freq);
+	}
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d",
+		MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
+	auth->auth_req_ack = 0;
+	os_get_reltime(&hapd->dpp_last_init);
+	return hostapd_drv_send_action(hapd, freq, wait_time,
+				       dst,
+				       wpabuf_head(hapd->dpp_auth->req_msg),
+				       wpabuf_len(hapd->dpp_auth->req_msg));
 }
 
 
@@ -450,10 +775,8 @@
 {
 	const char *pos;
 	struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
-	const u8 *dst;
-	int res;
-	int configurator = 1;
-	struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
+	u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+	unsigned int neg_freq = 0;
 
 	pos = os_strstr(cmd, " peer=");
 	if (!pos)
@@ -488,77 +811,102 @@
 	if (pos) {
 		pos += 6;
 		if (os_strncmp(pos, "configurator", 12) == 0)
-			configurator = 1;
+			allowed_roles = DPP_CAPAB_CONFIGURATOR;
 		else if (os_strncmp(pos, "enrollee", 8) == 0)
-			configurator = 0;
+			allowed_roles = DPP_CAPAB_ENROLLEE;
+		else if (os_strncmp(pos, "either", 6) == 0)
+			allowed_roles = DPP_CAPAB_CONFIGURATOR |
+				DPP_CAPAB_ENROLLEE;
 		else
 			goto fail;
 	}
 
-	if (hapd->dpp_auth)
+	pos = os_strstr(cmd, " neg_freq=");
+	if (pos)
+		neg_freq = atoi(pos + 10);
+
+	if (hapd->dpp_auth) {
+		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+				     hapd, NULL);
+		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
+				     NULL);
+		hostapd_drv_send_action_cancel_wait(hapd);
 		dpp_auth_deinit(hapd->dpp_auth);
-	hapd->dpp_auth = dpp_auth_init(hapd, peer_bi, own_bi, configurator);
+	}
+
+	hapd->dpp_auth = dpp_auth_init(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);
 	hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd);
 
-	/* TODO: Support iteration over all frequencies and filtering of
-	 * frequencies based on locally enabled channels that allow initiation
-	 * of transmission. */
-	if (peer_bi->num_freq > 0)
-		hapd->dpp_auth->curr_freq = peer_bi->freq[0];
-	else
-		hapd->dpp_auth->curr_freq = 2412;
+	hapd->dpp_auth->neg_freq = neg_freq;
 
-	if (is_zero_ether_addr(peer_bi->mac_addr)) {
-		dst = broadcast;
-	} else {
-		dst = peer_bi->mac_addr;
+	if (!is_zero_ether_addr(peer_bi->mac_addr))
 		os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
 			  ETH_ALEN);
-	}
-	hapd->dpp_auth_ok_on_ack = 0;
 
-	res = hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
-				      dst, wpabuf_head(hapd->dpp_auth->req_msg),
-				      wpabuf_len(hapd->dpp_auth->req_msg));
-
-	return res;
+	return hostapd_dpp_auth_init_next(hapd);
 fail:
-	dpp_configuration_free(conf_sta);
-	dpp_configuration_free(conf_ap);
 	return -1;
 }
 
 
+int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
+{
+	int freq;
+
+	freq = atoi(cmd);
+	if (freq <= 0)
+		return -1;
+
+	if (os_strstr(cmd, " role=configurator"))
+		hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
+	else if (os_strstr(cmd, " role=enrollee"))
+		hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+	else
+		hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
+			DPP_CAPAB_ENROLLEE;
+	hapd->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
+
+	if (freq != hapd->iface->freq && hapd->iface->freq > 0) {
+		/* TODO: Listen operation on non-operating channel */
+		wpa_printf(MSG_INFO,
+			   "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+			   freq, hapd->iface->freq);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
+{
+	/* TODO: Stop listen operation on non-operating channel */
+}
+
+
 static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
 				    const u8 *hdr, const u8 *buf, size_t len,
 				    unsigned int freq)
 {
-	const u8 *r_bootstrap, *i_bootstrap, *wrapped_data;
-	u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len;
+	const u8 *r_bootstrap, *i_bootstrap;
+	u16 r_bootstrap_len, i_bootstrap_len;
 	struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
 
 	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
 		   MAC2STR(src));
 
-	wrapped_data = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA,
-				    &wrapped_data_len);
-	if (!wrapped_data) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing required Wrapped data attribute");
-		return;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped data",
-		    wrapped_data, wrapped_data_len);
-
 	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
 				   &r_bootstrap_len);
-	if (!r_bootstrap || r_bootstrap > wrapped_data ||
-	    r_bootstrap_len != SHA256_MAC_LEN) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+	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",
@@ -566,10 +914,9 @@
 
 	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
 				   &i_bootstrap_len);
-	if (!i_bootstrap || i_bootstrap > wrapped_data ||
-	    i_bootstrap_len != SHA256_MAC_LEN) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Initiator Bootstrapping Key Hash attribute");
 		return;
 	}
 	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
@@ -577,8 +924,8 @@
 
 	/* Try to find own and peer bootstrapping key matches based on the
 	 * received hash values */
-	dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info,
-			 list) {
+	dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
+			 struct dpp_bootstrap_info, list) {
 		if (!own_bi && bi->own &&
 		    os_memcmp(bi->pubkey_hash, r_bootstrap,
 			      SHA256_MAC_LEN) == 0) {
@@ -600,22 +947,21 @@
 	}
 
 	if (!own_bi) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No matching own bootstrapping key found - ignore message");
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"No matching own bootstrapping key found - ignore message");
 		return;
 	}
 
 	if (hapd->dpp_auth) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Already in DPP authentication exchange - ignore new one");
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Already in DPP authentication exchange - ignore new one");
 		return;
 	}
 
 	hapd->dpp_auth_ok_on_ack = 0;
 	hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
 					 hapd->dpp_qr_mutual,
-					 peer_bi, own_bi, freq, hdr, buf,
-					 wrapped_data, wrapped_data_len);
+					 peer_bi, own_bi, freq, hdr, buf, len);
 	if (!hapd->dpp_auth) {
 		wpa_printf(MSG_DEBUG, "DPP: No response generated");
 		return;
@@ -625,55 +971,22 @@
 				     hapd->dpp_configurator_params);
 	os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN);
 
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d",
+		MAC2STR(src), hapd->dpp_auth->curr_freq,
+		DPP_PA_AUTHENTICATION_RESP);
 	hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
 				src, wpabuf_head(hapd->dpp_auth->resp_msg),
 				wpabuf_len(hapd->dpp_auth->resp_msg));
 }
 
 
-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,
-				    const struct wpabuf *resp, u16 status_code)
+static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+					  struct dpp_authentication *auth)
 {
-	struct hostapd_data *hapd = ctx;
-	const u8 *pos;
-	struct dpp_authentication *auth = hapd->dpp_auth;
-
-	if (!auth || !auth->auth_success) {
-		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
-		return;
-	}
-	if (!resp || status_code != WLAN_STATUS_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
-		goto fail;
-	}
-
-	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
-			adv_proto);
-	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
-			resp);
-
-	if (wpabuf_len(adv_proto) != 10 ||
-	    !(pos = wpabuf_head(adv_proto)) ||
-	    pos[0] != WLAN_EID_ADV_PROTO ||
-	    pos[1] != 8 ||
-	    pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
-	    pos[4] != 5 ||
-	    WPA_GET_BE24(&pos[5]) != OUI_WFA ||
-	    pos[8] != 0x1a ||
-	    pos[9] != 1) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Not a DPP Advertisement Protocol ID");
-		goto fail;
-	}
-
-	if (dpp_conf_resp_rx(auth, resp) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
-		goto fail;
-	}
-
 	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
+		dpp_akm_str(auth->akm));
 	if (auth->ssid_len)
 		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
 			wpa_ssid_txt(auth->ssid, auth->ssid_len));
@@ -736,6 +1049,52 @@
 			os_free(hex);
 		}
 	}
+}
+
+
+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,
+				    const struct wpabuf *resp, u16 status_code)
+{
+	struct hostapd_data *hapd = ctx;
+	const u8 *pos;
+	struct dpp_authentication *auth = hapd->dpp_auth;
+
+	if (!auth || !auth->auth_success) {
+		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+		return;
+	}
+	if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
+		goto fail;
+	}
+
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
+			adv_proto);
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
+			resp);
+
+	if (wpabuf_len(adv_proto) != 10 ||
+	    !(pos = wpabuf_head(adv_proto)) ||
+	    pos[0] != WLAN_EID_ADV_PROTO ||
+	    pos[1] != 8 ||
+	    pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
+	    pos[4] != 5 ||
+	    WPA_GET_BE24(&pos[5]) != OUI_WFA ||
+	    pos[8] != 0x1a ||
+	    pos[9] != 1) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Not a DPP Advertisement Protocol ID");
+		goto fail;
+	}
+
+	if (dpp_conf_resp_rx(auth, resp) < 0) {
+		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
+		goto fail;
+	}
+
+	hostapd_dpp_handle_config_obj(hapd, auth);
 	dpp_auth_deinit(hapd->dpp_auth);
 	hapd->dpp_auth = NULL;
 	return;
@@ -811,6 +1170,17 @@
 	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
 	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d",
 		initiator);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at Authentication Confirm");
+		if (hapd->dpp_auth->configurator) {
+			/* Prevent GAS response */
+			hapd->dpp_auth->auth_success = 0;
+		}
+		return;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	if (!hapd->dpp_auth->configurator)
 		hostapd_dpp_start_gas_client(hapd);
@@ -818,7 +1188,8 @@
 
 
 static void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src,
-				     const u8 *hdr, const u8 *buf, size_t len)
+				     const u8 *hdr, const u8 *buf, size_t len,
+				     unsigned int freq)
 {
 	struct dpp_authentication *auth = hapd->dpp_auth;
 	struct wpabuf *msg;
@@ -839,6 +1210,15 @@
 		return;
 	}
 
+	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+
+	if (auth->curr_freq != freq && auth->neg_freq == freq) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Responder accepted request for different negotiation channel");
+		auth->curr_freq = freq;
+	}
+
+	eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
 	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
 	if (!msg) {
 		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
@@ -850,6 +1230,9 @@
 	}
 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
 
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d", MAC2STR(src), auth->curr_freq,
+		DPP_PA_AUTHENTICATION_CONF);
 	hostapd_drv_send_action(hapd, auth->curr_freq, 0, src,
 				wpabuf_head(msg), wpabuf_len(msg));
 	wpabuf_free(msg);
@@ -886,6 +1269,98 @@
 }
 
 
+static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
+					    const u8 *src, unsigned int freq,
+					    u8 trans_id,
+					    enum dpp_status_error status)
+{
+	struct wpabuf *msg;
+
+	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
+			    5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
+	if (!msg)
+		return;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
+		goto skip_trans_id;
+	}
+	if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
+		trans_id ^= 0x01;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* Transaction ID */
+	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+	wpabuf_put_le16(msg, 1);
+	wpabuf_put_u8(msg, trans_id);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_trans_id:
+	if (dpp_test == DPP_TEST_NO_STATUS_PEER_DISC_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+		goto skip_status;
+	}
+	if (dpp_test == DPP_TEST_INVALID_STATUS_PEER_DISC_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+		status = 254;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* DPP Status */
+	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
+	wpabuf_put_le16(msg, 1);
+	wpabuf_put_u8(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+	if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
+		goto skip_connector;
+	}
+	if (status == DPP_STATUS_OK &&
+	    dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP) {
+		char *connector;
+
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
+		connector = dpp_corrupt_connector_signature(
+			hapd->conf->dpp_connector);
+		if (!connector) {
+			wpabuf_free(msg);
+			return;
+		}
+		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+		wpabuf_put_le16(msg, os_strlen(connector));
+		wpabuf_put_str(msg, connector);
+		os_free(connector);
+		goto skip_connector;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* DPP Connector */
+	if (status == DPP_STATUS_OK) {
+		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+		wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
+		wpabuf_put_str(msg, hapd->conf->dpp_connector);
+	}
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_connector:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
+		   " status=%d", MAC2STR(src), status);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d status=%d", MAC2STR(src), freq,
+		DPP_PA_PEER_DISCOVERY_RESP, status);
+	hostapd_drv_send_action(hapd, freq, 0, src,
+				wpabuf_head(msg), wpabuf_len(msg));
+	wpabuf_free(msg);
+}
+
+
 static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 					 const u8 *src,
 					 const u8 *buf, size_t len,
@@ -897,7 +1372,7 @@
 	struct dpp_introduction intro;
 	os_time_t expire;
 	int expiration;
-	struct wpabuf *msg;
+	enum dpp_status_error res;
 
 	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
 		   MAC2STR(src));
@@ -917,7 +1392,7 @@
 	os_get_time(&now);
 
 	if (hapd->conf->dpp_netaccesskey_expiry &&
-	    hapd->conf->dpp_netaccesskey_expiry < now.sec) {
+	    (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
 		wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
 		return;
 	}
@@ -937,18 +1412,28 @@
 		return;
 	}
 
-	if (dpp_peer_intro(&intro, hapd->conf->dpp_connector,
-			   wpabuf_head(hapd->conf->dpp_netaccesskey),
-			   wpabuf_len(hapd->conf->dpp_netaccesskey),
-			   wpabuf_head(hapd->conf->dpp_csign),
-			   wpabuf_len(hapd->conf->dpp_csign),
-			   connector, connector_len, &expire) < 0) {
+	res = dpp_peer_intro(&intro, hapd->conf->dpp_connector,
+			     wpabuf_head(hapd->conf->dpp_netaccesskey),
+			     wpabuf_len(hapd->conf->dpp_netaccesskey),
+			     wpabuf_head(hapd->conf->dpp_csign),
+			     wpabuf_len(hapd->conf->dpp_csign),
+			     connector, connector_len, &expire);
+	if (res == 255) {
 		wpa_printf(MSG_INFO,
-			   "DPP: Network Introduction protocol resulted in failure");
+			   "DPP: Network Introduction protocol resulted in internal failure (peer "
+			   MACSTR ")", MAC2STR(src));
+		return;
+	}
+	if (res != DPP_STATUS_OK) {
+		wpa_printf(MSG_INFO,
+			   "DPP: Network Introduction protocol resulted in failure (peer "
+			   MACSTR " status %d)", MAC2STR(src), res);
+		hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
+						res);
 		return;
 	}
 
-	if (!expire || hapd->conf->dpp_netaccesskey_expiry < expire)
+	if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
 		expire = hapd->conf->dpp_netaccesskey_expiry;
 	if (expire)
 		expiration = expire - now.sec;
@@ -962,26 +1447,8 @@
 		return;
 	}
 
-	msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
-			    5 + 4 + os_strlen(hapd->conf->dpp_connector));
-	if (!msg)
-		return;
-
-	/* Transaction ID */
-	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
-	wpabuf_put_le16(msg, 1);
-	wpabuf_put_u8(msg, trans_id[0]);
-
-	/* DPP Connector */
-	wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
-	wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
-	wpabuf_put_str(msg, hapd->conf->dpp_connector);
-
-	wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR,
-		   MAC2STR(src));
-	hostapd_drv_send_action(hapd, freq, 0, src,
-				wpabuf_head(msg), wpabuf_len(msg));
-	wpabuf_free(msg);
+	hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
+					DPP_STATUS_OK);
 }
 
 
@@ -1011,7 +1478,8 @@
 		return;
 	}
 
-	hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->dpp_pkex_bi,
+	hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
+						  hapd->dpp_pkex_bi,
 						  hapd->own_addr, src,
 						  hapd->dpp_pkex_identifier,
 						  hapd->dpp_pkex_code,
@@ -1023,8 +1491,19 @@
 	}
 
 	msg = hapd->dpp_pkex->exchange_resp;
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d", MAC2STR(src), freq,
+		DPP_PA_PKEX_EXCHANGE_RESP);
 	hostapd_drv_send_action(hapd, freq, 0, src,
 				wpabuf_head(msg), wpabuf_len(msg));
+	if (hapd->dpp_pkex->failed) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Terminate PKEX exchange due to an earlier error");
+		if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+			hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t;
+		dpp_pkex_free(hapd->dpp_pkex);
+		hapd->dpp_pkex = NULL;
+	}
 }
 
 
@@ -1046,8 +1525,7 @@
 		return;
 	}
 
-	os_memcpy(hapd->dpp_pkex->peer_mac, src, ETH_ALEN);
-	msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, buf, len);
+	msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
 	if (!msg) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
 		return;
@@ -1056,6 +1534,9 @@
 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
 		   MAC2STR(src));
 
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d", MAC2STR(src), freq,
+		DPP_PA_PKEX_COMMIT_REVEAL_REQ);
 	hostapd_drv_send_action(hapd, freq, 0, src,
 				wpabuf_head(msg), wpabuf_len(msg));
 	wpabuf_free(msg);
@@ -1082,12 +1563,23 @@
 	msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
 	if (!msg) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
+		if (hapd->dpp_pkex->failed) {
+			wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+			if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+				hapd->dpp_pkex->own_bi->pkex_t =
+					hapd->dpp_pkex->t;
+			dpp_pkex_free(hapd->dpp_pkex);
+			hapd->dpp_pkex = NULL;
+		}
 		return;
 	}
 
 	wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
 		   MACSTR, MAC2STR(src));
 
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d", MAC2STR(src), freq,
+		DPP_PA_PKEX_COMMIT_REVEAL_RESP);
 	hostapd_drv_send_action(hapd, freq, 0, src,
 				wpabuf_head(msg), wpabuf_len(msg));
 	wpabuf_free(msg);
@@ -1109,7 +1601,7 @@
 		dpp_bootstrap_info_free(bi);
 		return;
 	}
-	dl_list_add(&hapd->dpp_bootstrap, &bi->list);
+	dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
 }
 
 
@@ -1156,7 +1648,7 @@
 		dpp_bootstrap_info_free(bi);
 		return;
 	}
-	dl_list_add(&hapd->dpp_bootstrap, &bi->list);
+	dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
 
 	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
 		    bi->id,
@@ -1178,6 +1670,7 @@
 	u8 crypto_suite;
 	enum dpp_public_action_frame_type type;
 	const u8 *hdr;
+	unsigned int pkex_t;
 
 	if (len < DPP_HDR_LEN)
 		return;
@@ -1197,18 +1690,27 @@
 	if (crypto_suite != 1) {
 		wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
 			   crypto_suite);
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+			" freq=%u type=%d ignore=unsupported-crypto-suite",
+			MAC2STR(src), freq, type);
 		return;
 	}
 	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
-	if (dpp_check_attrs(buf, len) < 0)
+	if (dpp_check_attrs(buf, len) < 0) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+			" freq=%u type=%d ignore=invalid-attributes",
+			MAC2STR(src), freq, type);
 		return;
+	}
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+		" freq=%u type=%d", MAC2STR(src), freq, type);
 
 	switch (type) {
 	case DPP_PA_AUTHENTICATION_REQ:
 		hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
 		break;
 	case DPP_PA_AUTHENTICATION_RESP:
-		hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len);
+		hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len, freq);
 		break;
 	case DPP_PA_AUTHENTICATION_CONF:
 		hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len);
@@ -1235,6 +1737,17 @@
 			   "DPP: Ignored unsupported frame subtype %d", type);
 		break;
 	}
+
+	if (hapd->dpp_pkex)
+		pkex_t = hapd->dpp_pkex->t;
+	else if (hapd->dpp_pkex_bi)
+		pkex_t = hapd->dpp_pkex_bi->pkex_t;
+	else
+		pkex_t = 0;
+	if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+		hostapd_dpp_pkex_remove(hapd, "*");
+	}
 }
 
 
@@ -1254,6 +1767,8 @@
 	wpa_hexdump(MSG_DEBUG,
 		    "DPP: Received Configuration Request (GAS Query Request)",
 		    query, query_len);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
+		MAC2STR(sa));
 	resp = dpp_conf_req_rx(auth, query, query_len);
 	if (!resp)
 		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
@@ -1261,12 +1776,30 @@
 }
 
 
+void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
+{
+	if (!hapd->dpp_auth)
+		return;
+
+	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+	hostapd_drv_send_action_cancel_wait(hapd);
+
+	if (ok)
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+	else
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+	dpp_auth_deinit(hapd->dpp_auth);
+	hapd->dpp_auth = NULL;
+}
+
+
 static unsigned int hostapd_dpp_next_configurator_id(struct hostapd_data *hapd)
 {
 	struct dpp_configurator *conf;
 	unsigned int max_id = 0;
 
-	dl_list_for_each(conf, &hapd->dpp_configurator,
+	dl_list_for_each(conf, &hapd->iface->interfaces->dpp_configurator,
 			 struct dpp_configurator, list) {
 		if (conf->id > max_id)
 			max_id = conf->id;
@@ -1300,7 +1833,7 @@
 		goto fail;
 
 	conf->id = hostapd_dpp_next_configurator_id(hapd);
-	dl_list_add(&hapd->dpp_configurator, &conf->list);
+	dl_list_add(&hapd->iface->interfaces->dpp_configurator, &conf->list);
 	ret = conf->id;
 	conf = NULL;
 fail:
@@ -1312,12 +1845,12 @@
 }
 
 
-static int dpp_configurator_del(struct hostapd_data *hapd, unsigned int id)
+static int dpp_configurator_del(struct hapd_interfaces *ifaces, unsigned int id)
 {
 	struct dpp_configurator *conf, *tmp;
 	int found = 0;
 
-	dl_list_for_each_safe(conf, tmp, &hapd->dpp_configurator,
+	dl_list_for_each_safe(conf, tmp, &ifaces->dpp_configurator,
 			      struct dpp_configurator, list) {
 		if (id && conf->id != id)
 			continue;
@@ -1344,7 +1877,45 @@
 			return -1;
 	}
 
-	return dpp_configurator_del(hapd, id_val);
+	return dpp_configurator_del(hapd->iface->interfaces, id_val);
+}
+
+
+int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
+{
+	struct dpp_authentication *auth;
+	int ret = -1;
+	char *curve = NULL;
+
+	auth = os_zalloc(sizeof(*auth));
+	if (!auth)
+		return -1;
+
+	curve = get_param(cmd, " curve=");
+	hostapd_dpp_set_configurator(hapd, auth, cmd);
+
+	if (dpp_configurator_own_config(auth, curve, 1) == 0) {
+		hostapd_dpp_handle_config_obj(hapd, auth);
+		ret = 0;
+	}
+
+	dpp_auth_deinit(auth);
+	os_free(curve);
+
+	return ret;
+}
+
+
+int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
+				     char *buf, size_t buflen)
+{
+	struct dpp_configurator *conf;
+
+	conf = hostapd_dpp_configurator_get_id(hapd, id);
+	if (!conf)
+		return -1;
+
+	return dpp_configurator_get_key(conf, buf, buflen);
 }
 
 
@@ -1369,6 +1940,7 @@
 		return -1;
 	}
 	hapd->dpp_pkex_bi = own_bi;
+	own_bi->pkex_t = 0; /* clear pending errors on new code */
 
 	os_free(hapd->dpp_pkex_identifier);
 	hapd->dpp_pkex_identifier = NULL;
@@ -1398,7 +1970,8 @@
 
 		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
 		dpp_pkex_free(hapd->dpp_pkex);
-		hapd->dpp_pkex = dpp_pkex_init(own_bi, hapd->own_addr,
+		hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
+					       hapd->own_addr,
 					       hapd->dpp_pkex_identifier,
 					       hapd->dpp_pkex_code);
 		if (!hapd->dpp_pkex)
@@ -1406,6 +1979,9 @@
 
 		msg = hapd->dpp_pkex->exchange_req;
 		/* TODO: Which channel to use? */
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+			" freq=%u type=%d", MAC2STR(broadcast), 2437,
+			DPP_PA_PKEX_EXCHANGE_REQ);
 		hostapd_drv_send_action(hapd, 2437, 0, broadcast,
 					wpabuf_head(msg), wpabuf_len(msg));
 	}
@@ -1449,10 +2025,17 @@
 }
 
 
+void hostapd_dpp_stop(struct hostapd_data *hapd)
+{
+	dpp_auth_deinit(hapd->dpp_auth);
+	hapd->dpp_auth = NULL;
+	dpp_pkex_free(hapd->dpp_pkex);
+	hapd->dpp_pkex = NULL;
+}
+
+
 int hostapd_dpp_init(struct hostapd_data *hapd)
 {
-	dl_list_init(&hapd->dpp_bootstrap);
-	dl_list_init(&hapd->dpp_configurator);
 	hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
 	hapd->dpp_init_done = 1;
 	return 0;
@@ -1472,8 +2055,9 @@
 #endif /* CONFIG_TESTING_OPTIONS */
 	if (!hapd->dpp_init_done)
 		return;
-	dpp_bootstrap_del(hapd, 0);
-	dpp_configurator_del(hapd, 0);
+	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+	eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
 	dpp_auth_deinit(hapd->dpp_auth);
 	hapd->dpp_auth = NULL;
 	hostapd_dpp_pkex_remove(hapd, "*");
@@ -1481,3 +2065,20 @@
 	os_free(hapd->dpp_configurator_params);
 	hapd->dpp_configurator_params = NULL;
 }
+
+
+void hostapd_dpp_init_global(struct hapd_interfaces *ifaces)
+{
+	dl_list_init(&ifaces->dpp_bootstrap);
+	dl_list_init(&ifaces->dpp_configurator);
+	ifaces->dpp_init_done = 1;
+}
+
+
+void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces)
+{
+	if (!ifaces->dpp_init_done)
+		return;
+	dpp_bootstrap_del(ifaces, 0);
+	dpp_configurator_del(ifaces, 0);
+}
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index d870b20..3ef7c14 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -17,6 +17,8 @@
 int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
 			       char *reply, int reply_size);
 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);
 void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
 			   const u8 *buf, size_t len, unsigned int freq);
 void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -24,11 +26,18 @@
 struct wpabuf *
 hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
 			    const u8 *query, size_t query_len);
+void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok);
 int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
+int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
+				     char *buf, size_t buflen);
 int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd);
 int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id);
+void hostapd_dpp_stop(struct hostapd_data *hapd);
 int hostapd_dpp_init(struct hostapd_data *hapd);
 void hostapd_dpp_deinit(struct hostapd_data *hapd);
+void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
+void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
 
 #endif /* DPP_HOSTAPD_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 648f20e..1135aea 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -109,10 +109,10 @@
 	struct ieee802_11_elems elems;
 	const u8 *ie;
 	size_t ielen;
-#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
 	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
 	u8 *p = buf;
-#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS */
+#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
 	u16 reason = WLAN_REASON_UNSPECIFIED;
 	u16 status = WLAN_STATUS_SUCCESS;
 	const u8 *p2p_dev_addr = NULL;
@@ -235,6 +235,14 @@
 						 elems.hs20_len - 4);
 	} else
 		sta->hs20_ie = NULL;
+
+	wpabuf_free(sta->roaming_consortium);
+	if (elems.roaming_cons_sel)
+		sta->roaming_consortium = wpabuf_alloc_copy(
+			elems.roaming_cons_sel + 4,
+			elems.roaming_cons_sel_len - 4);
+	else
+		sta->roaming_consortium = NULL;
 #endif /* CONFIG_HS20 */
 
 #ifdef CONFIG_FST
@@ -262,7 +270,9 @@
 #endif /* CONFIG_WPS */
 
 			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
-			return -1;
+			reason = WLAN_REASON_INVALID_IE;
+			status = WLAN_STATUS_INVALID_IE;
+			goto fail;
 		}
 #ifdef CONFIG_WPS
 		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
@@ -317,8 +327,8 @@
 				reason = WLAN_REASON_INVALID_IE;
 				status = WLAN_STATUS_INVALID_IE;
 			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
-				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
-				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+				reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+				status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
 			}
 #endif /* CONFIG_IEEE80211W */
 			else {
@@ -328,10 +338,14 @@
 			goto fail;
 		}
 #ifdef CONFIG_IEEE80211W
-		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+		    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+		    !sta->sa_query_timed_out &&
 		    sta->sa_query_count > 0)
 			ap_check_sa_query_timeout(hapd, sta);
-		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+		    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+		    !sta->sa_query_timed_out &&
 		    (sta->auth_alg != WLAN_AUTH_FT)) {
 			/*
 			 * STA has already been associated with MFP and SA
@@ -443,6 +457,10 @@
 #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);
+	if (!p) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
 #endif /* CONFIG_IEEE80211R_AP */
 
 #ifdef CONFIG_FILS
@@ -520,7 +538,32 @@
 	}
 #endif /* CONFIG_FILS */
 
-#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS)
+#ifdef CONFIG_OWE
+	if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+	    elems.owe_dh) {
+		u8 *npos;
+
+		npos = owe_assoc_req_process(hapd, sta,
+					     elems.owe_dh, elems.owe_dh_len,
+					     p, sizeof(buf) - (p - buf),
+					     &reason);
+		if (npos)
+			p = npos;
+		if (!npos &&
+		    reason == 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)
+			goto fail;
+	}
+#endif /* CONFIG_OWE */
+
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
 	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
 
 	if (sta->auth_alg == WLAN_AUTH_FT ||
@@ -615,7 +658,7 @@
 {
 	struct sta_info *sta = ap_get_sta(hapd, addr);
 
-	if (!sta || !hapd->conf->disassoc_low_ack)
+	if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
 		return;
 
 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
@@ -626,6 +669,73 @@
 }
 
 
+void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
+				      enum smps_mode smps_mode,
+				      enum chan_width chan_width, u8 rx_nss)
+{
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	const char *txt;
+
+	if (!sta)
+		return;
+
+	switch (smps_mode) {
+	case SMPS_AUTOMATIC:
+		txt = "automatic";
+		break;
+	case SMPS_OFF:
+		txt = "off";
+		break;
+	case SMPS_DYNAMIC:
+		txt = "dynamic";
+		break;
+	case SMPS_STATIC:
+		txt = "static";
+		break;
+	default:
+		txt = NULL;
+		break;
+	}
+	if (txt) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
+			MACSTR " %s", MAC2STR(addr), txt);
+	}
+
+	switch (chan_width) {
+	case CHAN_WIDTH_20_NOHT:
+		txt = "20(no-HT)";
+		break;
+	case CHAN_WIDTH_20:
+		txt = "20";
+		break;
+	case CHAN_WIDTH_40:
+		txt = "40";
+		break;
+	case CHAN_WIDTH_80:
+		txt = "80";
+		break;
+	case CHAN_WIDTH_80P80:
+		txt = "80+80";
+		break;
+	case CHAN_WIDTH_160:
+		txt = "160";
+		break;
+	default:
+		txt = NULL;
+		break;
+	}
+	if (txt) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
+			MACSTR " %s", MAC2STR(addr), txt);
+	}
+
+	if (rx_nss != 0xff) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
+			MACSTR " %d", MAC2STR(addr), rx_nss);
+	}
+}
+
+
 void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 			     int offset, int width, int cf1, int cf2)
 {
@@ -635,9 +745,9 @@
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO,
-		       "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
-		       freq, ht, offset, width, channel_width_to_string(width),
-		       cf1, cf2);
+		       "driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+		       freq, ht, hapd->iconf->ch_switch_vht_config, offset,
+		       width, channel_width_to_string(width), cf1, cf2);
 
 	hapd->iface->freq = freq;
 
@@ -682,14 +792,26 @@
 
 	hapd->iconf->channel = channel;
 	hapd->iconf->ieee80211n = ht;
-	if (!ht)
+	if (!ht) {
 		hapd->iconf->ieee80211ac = 0;
+	} else if (hapd->iconf->ch_switch_vht_config) {
+		/* CHAN_SWITCH VHT config */
+		if (hapd->iconf->ch_switch_vht_config &
+		    CH_SWITCH_VHT_ENABLED)
+			hapd->iconf->ieee80211ac = 1;
+		else if (hapd->iconf->ch_switch_vht_config &
+			 CH_SWITCH_VHT_DISABLED)
+			hapd->iconf->ieee80211ac = 0;
+	}
+	hapd->iconf->ch_switch_vht_config = 0;
+
 	hapd->iconf->secondary_channel = offset;
 	hapd->iconf->vht_oper_chwidth = chwidth;
 	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
 	hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
 
-	is_dfs = ieee80211_is_dfs(freq);
+	is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
+				  hapd->iface->num_hw_features);
 
 	if (hapd->csa_in_progress &&
 	    freq == hapd->cs_freq_params.freq) {
@@ -1095,6 +1217,7 @@
 	}
 
 	os_memset(&fi, 0, sizeof(fi));
+	fi.freq = rx_mgmt->freq;
 	fi.datarate = rx_mgmt->datarate;
 	fi.ssi_signal = rx_mgmt->ssi_signal;
 
@@ -1378,6 +1501,28 @@
 #endif /* NEED_AP_MLME */
 
 
+static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
+						   int istatus,
+						   const char *ifname,
+						   const u8 *addr)
+{
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+
+	if (sta) {
+		os_free(sta->ifname_wds);
+		if (istatus == INTERFACE_ADDED)
+			sta->ifname_wds = os_strdup(ifname);
+		else
+			sta->ifname_wds = NULL;
+	}
+
+	wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
+		istatus == INTERFACE_ADDED ?
+		WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
+		ifname, MAC2STR(addr));
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -1570,7 +1715,10 @@
 			 * Try to re-enable interface if the driver stopped it
 			 * when the interface got disabled.
 			 */
-			wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+			if (hapd->wpa_auth)
+				wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+			else
+				hostapd_reconfig_encryption(hapd);
 			hapd->reenable_beacon = 1;
 			ieee802_11_set_beacon(hapd);
 		}
@@ -1586,6 +1734,18 @@
 					     &data->acs_selected_channels);
 		break;
 #endif /* CONFIG_ACS */
+	case EVENT_STATION_OPMODE_CHANGED:
+		hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
+						 data->sta_opmode.smps_mode,
+						 data->sta_opmode.chan_width,
+						 data->sta_opmode.rx_nss);
+		break;
+	case EVENT_WDS_STA_INTERFACE_STATUS:
+		hostapd_event_wds_sta_interface_status(
+			hapd, data->wds_sta_interface.istatus,
+			data->wds_sta_interface.ifname,
+			data->wds_sta_interface.sta_addr);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index 082d0f5..fab307f 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -91,6 +91,8 @@
 			set_user_methods(user, argv[i]);
 		} else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
 			user->remediation = strlen(argv[i]) > 0;
+		} else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
+			user->t_c_timestamp = strtol(argv[i], 0, 10);
 		}
 	}
 
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index fadb740..a7df810 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -181,8 +181,12 @@
 		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
 	if (hapd->conf->hs20_osu_providers_count)
 		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
+	if (hapd->conf->hs20_osu_providers_nai_count)
+		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
 	if (hapd->conf->hs20_icons_count)
 		wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
+	if (hapd->conf->hs20_operator_icon_count)
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
 	gas_anqp_set_element_len(buf, len);
 }
 #endif /* CONFIG_HS20 */
@@ -288,7 +292,7 @@
 #endif /* CONFIG_FILS */
 	if (get_anqp_elem(hapd, ANQP_CAG))
 		wpabuf_put_le16(buf, ANQP_CAG);
-	if (get_anqp_elem(hapd, ANQP_VENUE_URL))
+	if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
 		wpabuf_put_le16(buf, ANQP_VENUE_URL);
 	if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
 		wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
@@ -328,6 +332,29 @@
 }
 
 
+static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+	if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
+		return;
+
+	if (hapd->conf->venue_url) {
+		u8 *len;
+		unsigned int i;
+
+		len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
+		for (i = 0; i < hapd->conf->venue_url_count; i++) {
+			struct hostapd_venue_url *url;
+
+			url = &hapd->conf->venue_url[i];
+			wpabuf_put_u8(buf, 1 + url->url_len);
+			wpabuf_put_u8(buf, url->venue_number);
+			wpabuf_put_data(buf, url->url, url->url_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
 static void anqp_add_network_auth_type(struct hostapd_data *hapd,
 				       struct wpabuf *buf)
 {
@@ -680,6 +707,29 @@
 }
 
 
+static void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
+			  const char *name)
+{
+	size_t j;
+	struct hs20_icon *icon = NULL;
+
+	for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
+		if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
+			icon = &bss->hs20_icons[j];
+	}
+	if (!icon)
+		return; /* icon info not found */
+
+	wpabuf_put_le16(buf, icon->width);
+	wpabuf_put_le16(buf, icon->height);
+	wpabuf_put_data(buf, icon->language, 3);
+	wpabuf_put_u8(buf, os_strlen(icon->type));
+	wpabuf_put_str(buf, icon->type);
+	wpabuf_put_u8(buf, os_strlen(icon->name));
+	wpabuf_put_str(buf, icon->name);
+}
+
+
 static void anqp_add_osu_provider(struct wpabuf *buf,
 				  struct hostapd_bss_config *bss,
 				  struct hs20_osu_provider *p)
@@ -714,26 +764,8 @@
 
 	/* Icons Available */
 	len2 = wpabuf_put(buf, 2);
-	for (i = 0; i < p->icons_count; i++) {
-		size_t j;
-		struct hs20_icon *icon = NULL;
-
-		for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
-			if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
-			    0)
-				icon = &bss->hs20_icons[j];
-		}
-		if (!icon)
-			continue; /* icon info not found */
-
-		wpabuf_put_le16(buf, icon->width);
-		wpabuf_put_le16(buf, icon->height);
-		wpabuf_put_data(buf, icon->language, 3);
-		wpabuf_put_u8(buf, os_strlen(icon->type));
-		wpabuf_put_str(buf, icon->type);
-		wpabuf_put_u8(buf, os_strlen(icon->name));
-		wpabuf_put_str(buf, icon->name);
-	}
+	for (i = 0; i < p->icons_count; i++)
+		anqp_add_icon(buf, bss, p->icons[i]);
 	WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
 
 	/* OSU_NAI */
@@ -787,6 +819,40 @@
 }
 
 
+static void anqp_add_osu_provider_nai(struct wpabuf *buf,
+				      struct hs20_osu_provider *p)
+{
+	/* OSU_NAI for shared BSS (Single SSID) */
+	if (p->osu_nai2) {
+		wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
+		wpabuf_put_str(buf, p->osu_nai2);
+	} else {
+		wpabuf_put_u8(buf, 0);
+	}
+}
+
+
+static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
+					    struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_osu_providers_nai_count) {
+		size_t i;
+		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+
+		for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
+			anqp_add_osu_provider_nai(
+				buf, &hapd->conf->hs20_osu_providers[i]);
+		}
+
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
 static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
 				      struct wpabuf *buf,
 				      const u8 *name, size_t name_len)
@@ -842,6 +908,30 @@
 	gas_anqp_set_element_len(buf, len);
 }
 
+
+static void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
+					    struct wpabuf *buf)
+{
+	struct hostapd_bss_config *bss = hapd->conf;
+	size_t i;
+	u8 *len;
+
+	if (!bss->hs20_operator_icon_count)
+		return;
+
+	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+
+	wpabuf_put_be24(buf, OUI_WFA);
+	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+	wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
+	wpabuf_put_u8(buf, 0); /* Reserved */
+
+	for (i = 0; i < bss->hs20_operator_icon_count; i++)
+		anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
+
+	gas_anqp_set_element_len(buf, len);
+}
+
 #endif /* CONFIG_HS20 */
 
 
@@ -946,6 +1036,10 @@
 			continue;
 		}
 #endif /* CONFIG_FILS */
+		if (extra_req[i] == ANQP_VENUE_URL) {
+			anqp_add_venue_url(hapd, buf);
+			continue;
+		}
 		anqp_add_elem(hapd, buf, extra_req[i]);
 	}
 
@@ -964,6 +1058,10 @@
 		anqp_add_osu_providers_list(hapd, buf);
 	if (request & ANQP_REQ_ICON_REQUEST)
 		anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
+	if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
+		anqp_add_operator_icon_metadata(hapd, buf);
+	if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
+		anqp_add_osu_providers_nai_list(hapd, buf);
 #endif /* CONFIG_HS20 */
 
 #ifdef CONFIG_MBO
@@ -1082,7 +1180,10 @@
 				   "ANQP: FILS Realm Information (local)");
 		} else
 #endif /* CONFIG_FILS */
-		if (!get_anqp_elem(hapd, info_id)) {
+		if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
+			wpa_printf(MSG_DEBUG,
+				   "ANQP: Venue URL (local)");
+		} else if (!get_anqp_elem(hapd, info_id)) {
 			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
 				   info_id);
 			break;
@@ -1148,6 +1249,16 @@
 		set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
 			     hapd->conf->hs20_osu_providers_count, qi);
 		break;
+	case HS20_STYPE_OPERATOR_ICON_METADATA:
+		set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
+			     "Operator Icon Metadata",
+			     hapd->conf->hs20_operator_icon_count, qi);
+		break;
+	case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
+		set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
+			     "OSU Providers NAI List",
+			     hapd->conf->hs20_osu_providers_nai_count, qi);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
 			   subtype);
@@ -1460,7 +1571,7 @@
 			gas_serv_write_dpp_adv_proto(tx_buf);
 			wpabuf_put_le16(tx_buf, wpabuf_len(buf));
 			wpabuf_put_buf(tx_buf, buf);
-			wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+			hostapd_dpp_gas_status_handler(hapd, 1);
 		}
 		wpabuf_free(buf);
 	}
@@ -1702,7 +1813,7 @@
 			"SD response sent");
 #ifdef CONFIG_DPP
 		if (dialog->dpp)
-			wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+			hostapd_dpp_gas_status_handler(hapd, 1);
 #endif /* CONFIG_DPP */
 		gas_serv_dialog_clear(dialog);
 		gas_serv_free_dialogs(hapd, sa);
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 3a30298..2cf1817 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -60,6 +60,10 @@
 	(0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
 #define ANQP_REQ_ICON_REQUEST \
 	(0x10000 << HS20_STYPE_ICON_REQUEST)
+#define ANQP_REQ_OPERATOR_ICON_METADATA \
+	(0x10000 << HS20_STYPE_OPERATOR_ICON_METADATA)
+#define ANQP_REQ_OSU_PROVIDERS_NAI_LIST \
+	(0x10000 << HS20_STYPE_OSU_PROVIDERS_NAI_LIST)
 /* The first MBO ANQP-element can be included in the optimized bitmap. */
 #define ANQP_REQ_MBO_CELL_DATA_CONN_PREF \
 	(BIT(29) << MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 12911df..117ee08 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -49,6 +49,7 @@
 #include "rrm.h"
 #include "fils_hlp.h"
 #include "acs.h"
+#include "hs20.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -56,6 +57,8 @@
 static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
 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,
+						    void *timeout_ctx);
 
 
 int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -75,6 +78,16 @@
 }
 
 
+void hostapd_reconfig_encryption(struct hostapd_data *hapd)
+{
+	if (hapd->wpa_auth)
+		return;
+
+	hostapd_set_privacy(hapd, 0);
+	hostapd_setup_encryption(hapd->conf->iface, hapd);
+}
+
+
 static void hostapd_reload_bss(struct hostapd_data *hapd)
 {
 	struct hostapd_ssid *ssid;
@@ -82,6 +95,9 @@
 	if (!hapd->started)
 		return;
 
+	if (hapd->conf->wmm_enabled < 0)
+		hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
+
 #ifndef CONFIG_NO_RADIUS
 	radius_client_reconfig(hapd->radius, hapd->conf->radius);
 #endif /* CONFIG_NO_RADIUS */
@@ -426,6 +442,8 @@
 {
 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+	eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+			     NULL);
 
 	hostapd_cleanup_iface_partial(iface);
 	hostapd_config_free(iface->conf);
@@ -893,6 +911,48 @@
 	return RADIUS_DAS_SUCCESS;
 }
 
+
+#ifdef CONFIG_HS20
+static enum radius_das_res
+hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	int multi;
+
+	if (hostapd_das_nas_mismatch(hapd, attr))
+		return RADIUS_DAS_NAS_MISMATCH;
+
+	sta = hostapd_das_find_sta(hapd, attr, &multi);
+	if (!sta) {
+		if (multi) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS DAS: Multiple sessions match - not supported");
+			return RADIUS_DAS_MULTI_SESSION_MATCH;
+		}
+		wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
+		return RADIUS_DAS_SESSION_NOT_FOUND;
+	}
+
+	wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
+		   " - CoA", MAC2STR(sta->addr));
+
+	if (attr->hs20_t_c_filtering) {
+		if (attr->hs20_t_c_filtering[0] & BIT(0)) {
+			wpa_printf(MSG_DEBUG,
+				   "HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
+			return RADIUS_DAS_COA_FAILED;
+		}
+
+		hs20_t_c_filtering(hapd, sta, 0);
+	}
+
+	return RADIUS_DAS_SUCCESS;
+}
+#else /* CONFIG_HS20 */
+#define hostapd_das_coa NULL
+#endif /* CONFIG_HS20 */
+
 #endif /* CONFIG_NO_RADIUS */
 
 
@@ -1067,6 +1127,7 @@
 			conf->radius_das_require_message_authenticator;
 		das_conf.ctx = hapd;
 		das_conf.disconnect = hostapd_das_disconnect;
+		das_conf.coa = hostapd_das_coa;
 		hapd->radius_das = radius_das_init(&das_conf);
 		if (hapd->radius_das == NULL) {
 			wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
@@ -1776,6 +1837,20 @@
 }
 
 
+static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
+						    void *timeout_ctx)
+{
+	struct hostapd_iface *iface = eloop_ctx;
+	struct hostapd_data *hapd;
+
+	if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
+		return;
+	hapd = iface->bss[0];
+	if (hapd->setup_complete_cb)
+		hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+}
+
+
 static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
 						 int err)
 {
@@ -1976,8 +2051,19 @@
 		iface->fst = NULL;
 	}
 #endif /* CONFIG_FST */
-	if (iface->interfaces && iface->interfaces->terminate_on_error)
+
+	if (iface->interfaces && iface->interfaces->terminate_on_error) {
 		eloop_terminate();
+	} else if (hapd->setup_complete_cb) {
+		/*
+		 * Calling hapd->setup_complete_cb directly may cause iface
+		 * deinitialization which may be accessed later by the caller.
+		 */
+		eloop_register_timeout(0, 0,
+				       hostapd_interface_setup_failure_handler,
+				       iface, NULL);
+	}
+
 	return -1;
 }
 
@@ -2159,12 +2245,6 @@
 
 	hostapd_set_state(iface, HAPD_IFACE_DISABLED);
 
-#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 */
 	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
 	iface->wait_channel_update = 0;
 
@@ -2180,6 +2260,13 @@
 			break;
 		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 */
 }
 
 
@@ -2533,6 +2620,11 @@
 		!!(hapd_iface->drv_flags &
 		   WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
 
+#ifdef NEED_AP_MLME
+	for (j = 0; j < hapd_iface->num_bss; j++)
+		hostapd_cleanup_cs_params(hapd_iface->bss[j]);
+#endif /* NEED_AP_MLME */
+
 	/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
 	for (j = 0; j < hapd_iface->num_bss; j++) {
 		struct hostapd_data *hapd = hapd_iface->bss[j];
@@ -3294,6 +3386,19 @@
 }
 
 
+void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
+{
+	if (vht_enabled)
+		hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
+	else
+		hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
+
+	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
+		       hapd->iconf->ch_switch_vht_config);
+}
+
+
 int hostapd_switch_channel(struct hostapd_data *hapd,
 			   struct csa_settings *settings)
 {
@@ -3328,7 +3433,6 @@
 				const struct hostapd_freq_params *freq_params)
 {
 	int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
-	unsigned int i;
 
 	wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
 
@@ -3370,10 +3474,8 @@
 	/*
 	 * cs_params must not be cleared earlier because the freq_params
 	 * argument may actually point to one of these.
+	 * These params will be cleared during interface disable below.
 	 */
-	for (i = 0; i < iface->num_bss; i++)
-		hostapd_cleanup_cs_params(iface->bss[i]);
-
 	hostapd_disable_iface(iface);
 	hostapd_enable_iface(iface);
 }
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index d7c6720..28b3a1c 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -57,6 +57,12 @@
 	struct dl_list eth_p_oui; /* OUI Extended EtherType handlers */
 #endif /* CONFIG_ETH_P_OUI */
 	int eloop_initialized;
+
+#ifdef CONFIG_DPP
+	int dpp_init_done;
+	struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
+	struct dl_list dpp_configurator; /* struct dpp_configurator */
+#endif /* CONFIG_DPP */
 };
 
 enum hostapd_chan_status {
@@ -79,6 +85,7 @@
 };
 
 struct hostapd_frame_info {
+	unsigned int freq;
 	u32 channel;
 	u32 datarate;
 	int ssi_signal; /* dBm */
@@ -257,9 +264,6 @@
 	unsigned int cs_c_off_ecsa_beacon;
 	unsigned int cs_c_off_ecsa_proberesp;
 
-	/* BSS Load */
-	unsigned int bss_load_update_timeout;
-
 #ifdef CONFIG_P2P
 	struct p2p_data *p2p;
 	struct p2p_group *p2p_group;
@@ -338,13 +342,12 @@
 	int dhcp_sock; /* UDP socket used with the DHCP server */
 
 #ifdef CONFIG_DPP
-	struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
-	struct dl_list dpp_configurator; /* struct dpp_configurator */
 	int dpp_init_done;
 	struct dpp_authentication *dpp_auth;
 	u8 dpp_allowed_roles;
 	int dpp_qr_mutual;
 	int dpp_auth_ok_on_ack;
+	int dpp_in_response_listen;
 	struct gas_query_ap *gas;
 	struct dpp_pkex *dpp_pkex;
 	struct dpp_bootstrap_info *dpp_pkex_bi;
@@ -352,6 +355,13 @@
 	char *dpp_pkex_identifier;
 	char *dpp_pkex_auth_cmd;
 	char *dpp_configurator_params;
+	struct os_reltime dpp_last_init;
+	struct os_reltime dpp_init_iter_start;
+	unsigned int dpp_init_max_tries;
+	unsigned int dpp_init_retry_time;
+	unsigned int dpp_resp_wait_time;
+	unsigned int dpp_resp_max_tries;
+	unsigned int dpp_resp_retry_time;
 #ifdef CONFIG_TESTING_OPTIONS
 	char *dpp_config_obj_override;
 	char *dpp_discovery_override;
@@ -497,6 +507,10 @@
 	u64 last_channel_time_busy;
 	u8 channel_utilization;
 
+	unsigned int chan_util_samples_sum;
+	unsigned int chan_util_num_sample_periods;
+	unsigned int chan_util_average;
+
 	/* eCSA IE will be added only if operating class is specified */
 	u8 cs_oper_class;
 
@@ -525,6 +539,7 @@
 			       int (*cb)(struct hostapd_iface *iface,
 					 void *ctx), void *ctx);
 int hostapd_reload_config(struct hostapd_iface *iface);
+void hostapd_reconfig_encryption(struct hostapd_data *hapd);
 struct hostapd_data *
 hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
 		       struct hostapd_config *conf,
@@ -551,6 +566,7 @@
 void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
 const char * hostapd_state_text(enum hostapd_iface_state s);
 int hostapd_csa_in_progress(struct hostapd_iface *iface);
+void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
 int hostapd_switch_channel(struct hostapd_data *hapd,
 			   struct csa_settings *settings);
 void
@@ -595,6 +611,9 @@
 
 struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
 					const char *ifname);
+void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
+				      enum smps_mode smps_mode,
+				      enum chan_width chan_width, u8 rx_nss);
 
 #ifdef CONFIG_FST
 void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index d7909fa..98d016d 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -11,9 +11,11 @@
 
 #include "common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
+#include "sta_info.h"
 #include "hs20.h"
 
 
@@ -175,3 +177,71 @@
 
 	return ret;
 }
+
+
+int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
+				   const u8 *addr, const char *url)
+{
+	struct wpabuf *buf;
+	int ret;
+	size_t url_len = os_strlen(url);
+
+	if (!url) {
+		wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available");
+		return -1;
+	}
+
+	if (5 + url_len > 255) {
+		wpa_printf(MSG_INFO,
+			   "HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'",
+			   url);
+		return -1;
+	}
+
+	buf = wpabuf_alloc(4 + 7 + url_len);
+	if (!buf)
+		return -1;
+
+	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, 1); /* Type - 1 reserved for WFA */
+
+	/* Terms and Conditions Acceptance subelement */
+	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+	wpabuf_put_u8(buf, 4 + 1 + url_len);
+	wpabuf_put_be24(buf, OUI_WFA);
+	wpabuf_put_u8(buf, HS20_WNM_T_C_ACCEPTANCE);
+	wpabuf_put_u8(buf, url_len);
+	wpabuf_put_str(buf, url);
+
+	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+				      wpabuf_head(buf), wpabuf_len(buf));
+
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
+			int enabled)
+{
+	if (enabled) {
+		wpa_printf(MSG_DEBUG,
+			   "HS 2.0: Terms and Conditions filtering required for "
+			   MACSTR, MAC2STR(sta->addr));
+		sta->hs20_t_c_filtering = 1;
+		/* TODO: Enable firewall filtering for the STA */
+		wpa_msg(hapd->msg_ctx, MSG_INFO, HS20_T_C_FILTERING_ADD MACSTR,
+			MAC2STR(sta->addr));
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "HS 2.0: Terms and Conditions filtering not required for "
+			   MACSTR, MAC2STR(sta->addr));
+		sta->hs20_t_c_filtering = 0;
+		/* TODO: Disable firewall filtering for the STA */
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			HS20_T_C_FILTERING_REMOVE MACSTR, MAC2STR(sta->addr));
+	}
+}
diff --git a/src/ap/hs20.h b/src/ap/hs20.h
index 152439f..e99e26e 100644
--- a/src/ap/hs20.h
+++ b/src/ap/hs20.h
@@ -18,5 +18,9 @@
 int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
 					  const u8 *addr,
 					  const struct wpabuf *payload);
+int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
+				   const u8 *addr, const char *url);
+void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
+			int enabled);
 
 #endif /* HS20_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 84e74ee..5279abc 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -679,7 +679,8 @@
 	if (!ieee80211n_supported_ht_capab(iface))
 		return -1;
 #ifdef CONFIG_IEEE80211AC
-	if (!ieee80211ac_supported_vht_capab(iface))
+	if (iface->conf->ieee80211ac &&
+	    !ieee80211ac_supported_vht_capab(iface))
 		return -1;
 #endif /* CONFIG_IEEE80211AC */
 	ret = ieee80211n_check_40mhz(iface);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 65c4d88..90788de 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -277,7 +277,7 @@
 static int send_auth_reply(struct hostapd_data *hapd,
 			   const u8 *dst, const u8 *bssid,
 			   u16 auth_alg, u16 auth_transaction, u16 resp,
-			   const u8 *ies, size_t ies_len)
+			   const u8 *ies, size_t ies_len, const char *dbg)
 {
 	struct ieee80211_mgmt *reply;
 	u8 *buf;
@@ -304,9 +304,9 @@
 		os_memcpy(reply->u.auth.variable, ies, ies_len);
 
 	wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
-		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
+		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
 		   MAC2STR(dst), auth_alg, auth_transaction,
-		   resp, (unsigned long) ies_len);
+		   resp, (unsigned long) ies_len, dbg);
 	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
 		wpa_printf(MSG_INFO, "send_auth_reply: send failed");
 	else
@@ -328,7 +328,8 @@
 	int reply_res;
 
 	reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
-				    auth_transaction, status, ies, ies_len);
+				    auth_transaction, status, ies, ies_len,
+				    "auth-ft-finish");
 
 	sta = ap_get_sta(hapd, dst);
 	if (sta == NULL)
@@ -354,16 +355,39 @@
 
 #ifdef CONFIG_SAE
 
-#define dot11RSNASAESync 5		/* attempts */
+static void sae_set_state(struct sta_info *sta, enum sae_state state,
+			  const char *reason)
+{
+	wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
+		   sae_state_txt(sta->sae->state), sae_state_txt(state),
+		   MAC2STR(sta->addr), reason);
+	sta->sae->state = state;
+}
 
 
 static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
 					     struct sta_info *sta, int update)
 {
 	struct wpabuf *buf;
-	const char *password;
+	const char *password = NULL;
+	struct sae_password_entry *pw;
+	const char *rx_id = NULL;
 
-	password = hapd->conf->sae_password;
+	if (sta->sae->tmp)
+		rx_id = sta->sae->tmp->pw_id;
+
+	for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+		if (!is_broadcast_ether_addr(pw->peer_addr) &&
+		    os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+			continue;
+		if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
+			continue;
+		if (rx_id && pw->identifier &&
+		    os_strcmp(rx_id, pw->identifier) != 0)
+			continue;
+		password = pw->password;
+		break;
+	}
 	if (!password)
 		password = hapd->conf->ssid.wpa_passphrase;
 	if (!password) {
@@ -373,17 +397,18 @@
 
 	if (update &&
 	    sae_prepare_commit(hapd->own_addr, sta->addr,
-			       (u8 *) password, os_strlen(password),
+			       (u8 *) password, os_strlen(password), rx_id,
 			       sta->sae) < 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
 		return NULL;
 	}
 
-	buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
+	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);
+			 sta->sae->tmp->anti_clogging_token : NULL, rx_id);
 
 	return buf;
 }
@@ -412,12 +437,14 @@
 	int reply_res;
 
 	data = auth_build_sae_commit(hapd, sta, update);
+	if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
+		return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
 	if (data == NULL)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
 	reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
 				    WLAN_STATUS_SUCCESS, wpabuf_head(data),
-				    wpabuf_len(data));
+				    wpabuf_len(data), "sae-send-commit");
 
 	wpabuf_free(data);
 
@@ -438,7 +465,7 @@
 
 	reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
 				    WLAN_STATUS_SUCCESS, wpabuf_head(data),
-				    wpabuf_len(data));
+				    wpabuf_len(data), "sae-send-confirm");
 
 	wpabuf_free(data);
 
@@ -517,10 +544,10 @@
 }
 
 
-static int sae_check_big_sync(struct sta_info *sta)
+static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
 {
-	if (sta->sae->sync > dot11RSNASAESync) {
-		sta->sae->state = SAE_NOTHING;
+	if (sta->sae->sync > hapd->conf->sae_sync) {
+		sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
 		sta->sae->sync = 0;
 		return -1;
 	}
@@ -534,12 +561,13 @@
 	struct sta_info *sta = eloop_data;
 	int ret;
 
-	if (sae_check_big_sync(sta))
+	if (sae_check_big_sync(hapd, sta))
 		return;
 	sta->sae->sync++;
 	wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
-		   " (sync=%d state=%d)",
-		   MAC2STR(sta->addr), sta->sae->sync, sta->sae->state);
+		   " (sync=%d state=%s)",
+		   MAC2STR(sta->addr), sta->sae->sync,
+		   sae_state_txt(sta->sae->state));
 
 	switch (sta->sae->state) {
 	case SAE_COMMITTED:
@@ -588,7 +616,7 @@
 	sta->auth_alg = WLAN_AUTH_SAE;
 	mlme_authenticate_indication(hapd, sta);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
-	sta->sae->state = SAE_ACCEPTED;
+	sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
 	wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
 			       sta->sae->pmk, sta->sae->pmkid);
 }
@@ -602,13 +630,16 @@
 	if (auth_transaction != 1 && auth_transaction != 2)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
+	wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
+		   MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
+		   auth_transaction);
 	switch (sta->sae->state) {
 	case SAE_NOTHING:
 		if (auth_transaction == 1) {
 			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
 			if (ret)
 				return ret;
-			sta->sae->state = SAE_COMMITTED;
+			sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
 
 			if (sae_process_commit(sta->sae) < 0)
 				return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -630,7 +661,8 @@
 				ret = auth_sae_send_confirm(hapd, sta, bssid);
 				if (ret)
 					return ret;
-				sta->sae->state = SAE_CONFIRMED;
+				sae_set_state(sta, SAE_CONFIRMED,
+					      "Sent Confirm (mesh)");
 			} else {
 				/*
 				 * For infrastructure BSS, send only the Commit
@@ -659,7 +691,7 @@
 			ret = auth_sae_send_confirm(hapd, sta, bssid);
 			if (ret)
 				return ret;
-			sta->sae->state = SAE_CONFIRMED;
+			sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
 			sta->sae->sync = 0;
 			sae_set_retransmit_timer(hapd, sta);
 		} else if (hapd->conf->mesh & MESH_ENABLED) {
@@ -667,7 +699,7 @@
 			 * In mesh case, follow SAE finite state machine and
 			 * send Commit now, if sync count allows.
 			 */
-			if (sae_check_big_sync(sta))
+			if (sae_check_big_sync(hapd, sta))
 				return WLAN_STATUS_SUCCESS;
 			sta->sae->sync++;
 
@@ -686,7 +718,7 @@
 			if (ret)
 				return ret;
 
-			sta->sae->state = SAE_CONFIRMED;
+			sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
 
 			/*
 			 * Since this was triggered on Confirm RX, run another
@@ -699,7 +731,7 @@
 	case SAE_CONFIRMED:
 		sae_clear_retransmit_timer(hapd, sta);
 		if (auth_transaction == 1) {
-			if (sae_check_big_sync(sta))
+			if (sae_check_big_sync(hapd, sta))
 				return WLAN_STATUS_SUCCESS;
 			sta->sae->sync++;
 
@@ -716,18 +748,31 @@
 
 			sae_set_retransmit_timer(hapd, sta);
 		} else {
+			sta->sae->send_confirm = 0xffff;
 			sae_accept_sta(hapd, sta);
 		}
 		break;
 	case SAE_ACCEPTED:
-		if (auth_transaction == 1) {
+		if (auth_transaction == 1 &&
+		    (hapd->conf->mesh & MESH_ENABLED)) {
 			wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
 				   ") doing reauthentication",
 				   MAC2STR(sta->addr));
 			ap_free_sta(hapd, sta);
 			wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+		} else if (auth_transaction == 1) {
+			wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
+			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+			if (ret)
+				return ret;
+			sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
+
+			if (sae_process_commit(sta->sae) < 0)
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+			sta->sae->sync = 0;
+			sae_set_retransmit_timer(hapd, sta);
 		} else {
-			if (sae_check_big_sync(sta))
+			if (sae_check_big_sync(hapd, sta))
 				return WLAN_STATUS_SUCCESS;
 			sta->sae->sync++;
 
@@ -799,7 +844,8 @@
 		pos = mgmt->u.auth.variable;
 		end = ((const u8 *) mgmt) + len;
 		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
-				auth_transaction, resp, pos, end - pos);
+				auth_transaction, resp, pos, end - pos,
+				"auth-sae-reflection-attack");
 		goto remove_sta;
 	}
 
@@ -808,7 +854,8 @@
 		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
 				auth_transaction, resp,
 				wpabuf_head(hapd->conf->sae_commit_override),
-				wpabuf_len(hapd->conf->sae_commit_override));
+				wpabuf_len(hapd->conf->sae_commit_override),
+				"sae-commit-override");
 		goto remove_sta;
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
@@ -823,7 +870,7 @@
 			resp = -1;
 			goto remove_sta;
 		}
-		sta->sae->state = SAE_NOTHING;
+		sae_set_state(sta, SAE_NOTHING, "Init");
 		sta->sae->sync = 0;
 	}
 
@@ -886,7 +933,8 @@
 					   "SAE: Failed to send commit message");
 				goto remove_sta;
 			}
-			sta->sae->state = SAE_COMMITTED;
+			sae_set_state(sta, SAE_COMMITTED,
+				      "Sent Commit (anti-clogging token case in mesh)");
 			sta->sae->sync = 0;
 			sae_set_retransmit_timer(hapd, sta);
 			return;
@@ -905,6 +953,20 @@
 		if (status_code != WLAN_STATUS_SUCCESS)
 			goto remove_sta;
 
+		if (!(hapd->conf->mesh & MESH_ENABLED) &&
+		    sta->sae->state == SAE_COMMITTED) {
+			/* This is needed in the infrastructure BSS case to
+			 * address a sequence where a STA entry may remain in
+			 * hostapd across two attempts to do SAE authentication
+			 * by the same STA. The second attempt may end up trying
+			 * to use a different group and that would not be
+			 * allowed if we remain in Committed state with the
+			 * previously set parameters. */
+			sae_set_state(sta, SAE_NOTHING,
+				      "Clear existing state to allow restart");
+			sae_clear_data(sta->sae);
+		}
+
 		resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
 					((const u8 *) mgmt) + len -
 					mgmt->u.auth.variable, &token,
@@ -915,6 +977,17 @@
 				   MAC2STR(sta->addr));
 			goto remove_sta;
 		}
+
+		if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
+			wpa_msg(hapd->msg_ctx, MSG_INFO,
+				WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
+				MACSTR, MAC2STR(sta->addr));
+			sae_clear_retransmit_timer(hapd, sta);
+			sae_set_state(sta, SAE_NOTHING,
+				      "Unknown Password Identifier");
+			goto remove_sta;
+		}
+
 		if (token && check_sae_token(hapd, sta->addr, token, token_len)
 		    < 0) {
 			wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
@@ -935,7 +1008,8 @@
 						    sta->addr);
 			resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
 			if (hapd->conf->mesh & MESH_ENABLED)
-				sta->sae->state = SAE_NOTHING;
+				sae_set_state(sta, SAE_NOTHING,
+					      "Request anti-clogging token case in mesh");
 			goto reply;
 		}
 
@@ -949,12 +1023,36 @@
 			goto remove_sta;
 		if (sta->sae->state >= SAE_CONFIRMED ||
 		    !(hapd->conf->mesh & MESH_ENABLED)) {
-			if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
-					      ((u8 *) mgmt) + len -
-					      mgmt->u.auth.variable) < 0) {
+			const u8 *var;
+			size_t var_len;
+			u16 peer_send_confirm;
+
+			var = mgmt->u.auth.variable;
+			var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
+			if (var_len < 2) {
 				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 				goto reply;
 			}
+
+			peer_send_confirm = WPA_GET_LE16(var);
+
+			if (sta->sae->state == SAE_ACCEPTED &&
+			    (peer_send_confirm <= sta->sae->rc ||
+			     peer_send_confirm == 0xffff)) {
+				wpa_printf(MSG_DEBUG,
+					   "SAE: Silently ignore unexpected Confirm from peer "
+					   MACSTR
+					   " (peer-send-confirm=%u Rc=%u)",
+					   MAC2STR(sta->addr),
+					   peer_send_confirm, sta->sae->rc);
+				return;
+			}
+
+			if (sae_check_confirm(sta->sae, var, var_len) < 0) {
+				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto reply;
+			}
+			sta->sae->rc = peer_send_confirm;
 		}
 		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
 	} else {
@@ -972,7 +1070,7 @@
 		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
 				auth_transaction, resp,
 				data ? wpabuf_head(data) : (u8 *) "",
-				data ? wpabuf_len(data) : 0);
+				data ? wpabuf_len(data) : 0, "auth-sae");
 	}
 
 remove_sta:
@@ -1009,7 +1107,7 @@
 	if (ret)
 		return -1;
 
-	sta->sae->state = SAE_COMMITTED;
+	sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
 	sta->sae->sync = 0;
 	sae_set_retransmit_timer(hapd, sta);
 
@@ -1033,7 +1131,7 @@
 	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_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+		return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
 #endif /* CONFIG_IEEE80211W */
 	if (res == WPA_INVALID_MDIE)
 		return WLAN_STATUS_INVALID_MDIE;
@@ -1374,8 +1472,11 @@
 	if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
 		/* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
 		int res;
+		int use_sha384 = wpa_key_mgmt_sha384(
+			wpa_auth_sta_key_mgmt(sta->wpa_sm));
 
-		res = wpa_auth_write_fte(hapd->wpa_auth, wpabuf_put(data, 0),
+		res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
+					 wpabuf_put(data, 0),
 					 wpabuf_tailroom(data));
 		if (res < 0) {
 			*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1430,15 +1531,24 @@
 		if (sta->fils_erp_pmkid_set) {
 			/* TODO: get PMKLifetime from WPA parameters */
 			unsigned int dot11RSNAConfigPMKLifetime = 43200;
+			int session_timeout;
+
+			session_timeout = dot11RSNAConfigPMKLifetime;
+			if (sta->session_timeout_set) {
+				struct os_reltime now, diff;
+
+				os_get_reltime(&now);
+				os_reltime_sub(&sta->session_timeout, &now,
+					       &diff);
+				session_timeout = diff.sec;
+			}
 
 			sta->fils_erp_pmkid_set = 0;
 			if (wpa_auth_pmksa_add2(
 				    hapd->wpa_auth, sta->addr,
 				    pmk, pmk_len,
 				    sta->fils_erp_pmkid,
-				    sta->session_timeout_set ?
-				    sta->session_timeout :
-				    dot11RSNAConfigPMKLifetime,
+				    session_timeout,
 				    wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
 				wpa_printf(MSG_ERROR,
 					   "FILS: Failed to add PMKSA cache entry based on ERP");
@@ -1496,7 +1606,7 @@
 		WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
 	send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
 			data ? wpabuf_head(data) : (u8 *) "",
-			data ? wpabuf_len(data) : 0);
+			data ? wpabuf_len(data) : 0, "auth-fils-finish");
 	wpabuf_free(data);
 
 	if (resp == WLAN_STATUS_SUCCESS) {
@@ -1538,25 +1648,28 @@
 #endif /* CONFIG_FILS */
 
 
-static int
+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)
+			   char **identity, char **radius_cui, int is_probe_req)
 {
 	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);
+				      vlan_id, psk, identity, radius_cui,
+				      is_probe_req);
 
 	if (res == HOSTAPD_ACL_REJECT) {
-		wpa_printf(MSG_INFO,
-			   "Station " MACSTR " not allowed to authenticate",
-			   MAC2STR(addr));
+		if (!is_probe_req)
+			wpa_printf(MSG_DEBUG,
+				   "Station " MACSTR
+				   " not allowed to authenticate",
+				   MAC2STR(addr));
 		return HOSTAPD_ACL_REJECT;
 	}
 
@@ -1605,17 +1718,25 @@
 		sta->psk = NULL;
 	}
 
+	os_free(sta->identity);
 	sta->identity = *identity;
 	*identity = NULL;
+
+	os_free(sta->radius_cui);
 	sta->radius_cui = *radius_cui;
 	*radius_cui = NULL;
 
 	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
 		sta->acct_interim_interval = acct_interim_interval;
-	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
+		sta->session_timeout_set = 1;
+		os_get_reltime(&sta->session_timeout);
+		sta->session_timeout.sec += session_timeout;
 		ap_sta_session_timeout(hapd, sta, session_timeout);
-	else
+	} else {
+		sta->session_timeout_set = 0;
 		ap_sta_no_session_timeout(hapd, sta);
+	}
 
 	return 0;
 }
@@ -1686,7 +1807,9 @@
 #endif /* CONFIG_NO_RC4 */
 
 	if (hapd->tkip_countermeasures) {
-		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+		wpa_printf(MSG_DEBUG,
+			   "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
 
@@ -1787,8 +1910,12 @@
 
 	res = ieee802_11_allowed_address(
 		hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
-		&acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui);
+		&acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
+		0);
 	if (res == HOSTAPD_ACL_REJECT) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"Ignore Authentication frame from " MACSTR
+			" due to ACL reject", MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -1839,6 +1966,7 @@
 
 		sta = ap_sta_add(hapd, mgmt->sa);
 		if (!sta) {
+			wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
 			resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 			goto fail;
 		}
@@ -1850,6 +1978,7 @@
 		hapd, sta, res, session_timeout, acct_interim_interval,
 		&vlan_id, &psk, &identity, &radius_cui);
 	if (res) {
+		wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -1887,6 +2016,7 @@
 		 * updated. To handle this, station's added_unassoc flag is
 		 * cleared once the station has completed association.
 		 */
+		ap_sta_set_authorized(hapd, sta, 0);
 		hostapd_drv_sta_remove(hapd, sta->addr);
 		sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
 				WLAN_STA_AUTHORIZED);
@@ -1918,6 +2048,9 @@
 	case WLAN_AUTH_SHARED_KEY:
 		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
 				       fc & WLAN_FC_ISWEP);
+		if (resp != 0)
+			wpa_printf(MSG_DEBUG,
+				   "auth_shared_key() failed: status=%d", resp);
 		sta->auth_alg = WLAN_AUTH_SHARED_KEY;
 		mlme_authenticate_indication(hapd, sta);
 		if (sta->challenge && auth_transaction == 1) {
@@ -1988,7 +2121,7 @@
 
 	reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
 				    auth_transaction + 1, resp, resp_ies,
-				    resp_ies_len);
+				    resp_ies_len, "handle-auth");
 
 	if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
 					  reply_res != WLAN_STATUS_SUCCESS)) {
@@ -2123,8 +2256,16 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
-	if (ext_capab_ie_len > 0)
+	if (ext_capab_ie_len > 0) {
 		sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
+		os_free(sta->ext_capability);
+		sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
+		if (sta->ext_capability) {
+			sta->ext_capability[0] = ext_capab_ie_len;
+			os_memcpy(sta->ext_capability + 1, ext_capab_ie,
+				  ext_capab_ie_len);
+		}
+	}
 
 	return WLAN_STATUS_SUCCESS;
 }
@@ -2444,10 +2585,14 @@
 		if (resp != WLAN_STATUS_SUCCESS)
 			return resp;
 #ifdef CONFIG_IEEE80211W
-		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+		    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+		    !sta->sa_query_timed_out &&
 		    sta->sa_query_count > 0)
 			ap_check_sa_query_timeout(hapd, sta);
-		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+		    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+		    !sta->sa_query_timed_out &&
 		    (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
 			/*
 			 * STA has already been associated with MFP and SA
@@ -2486,6 +2631,10 @@
 #endif /* CONFIG_IEEE80211R_AP */
 
 #ifdef CONFIG_SAE
+		if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
+		    sta->sae->state == SAE_ACCEPTED)
+			wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
+
 		if (wpa_auth_uses_sae(sta->wpa_sm) &&
 		    sta->auth_alg == WLAN_AUTH_OPEN) {
 			struct rsn_pmksa_cache_entry *sa;
@@ -2568,6 +2717,14 @@
 						 elems.hs20_len - 4);
 	} else
 		sta->hs20_ie = NULL;
+
+	wpabuf_free(sta->roaming_consortium);
+	if (elems.roaming_cons_sel)
+		sta->roaming_consortium = wpabuf_alloc_copy(
+			elems.roaming_cons_sel + 4,
+			elems.roaming_cons_sel_len - 4);
+	else
+		sta->roaming_consortium = NULL;
 #endif /* CONFIG_HS20 */
 
 #ifdef CONFIG_FST
@@ -2599,6 +2756,14 @@
 		os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
 			  sizeof(sta->rrm_enabled_capa));
 
+	if (elems.power_capab) {
+		sta->min_tx_power = elems.power_capab[0];
+		sta->max_tx_power = elems.power_capab[1];
+		sta->power_capab = 1;
+	} else {
+		sta->power_capab = 0;
+	}
+
 	return WLAN_STATUS_SUCCESS;
 }
 
@@ -2747,6 +2912,12 @@
 		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
 						buf + buflen - p,
 						sta->auth_alg, ies, ies_len);
+		if (!p) {
+			wpa_printf(MSG_DEBUG,
+				   "FT: Failed to write AssocResp IEs");
+			res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto done;
+		}
 	}
 #endif /* CONFIG_IEEE80211R_AP */
 
@@ -2932,6 +3103,61 @@
 }
 
 
+#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)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->conf->own_ie_override) {
+		wpa_printf(MSG_DEBUG, "OWE: Using IE override");
+		*reason = WLAN_STATUS_SUCCESS;
+		return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+						     owe_buf_len, NULL, 0);
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
+		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;
+		return owe_buf;
+	}
+
+	*reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+	if (*reason != WLAN_STATUS_SUCCESS)
+		return NULL;
+
+	owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+						owe_buf_len, NULL, 0);
+
+	if (sta->owe_ecdh && owe_buf) {
+		struct wpabuf *pub;
+
+		pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+		if (!pub) {
+			*reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			return owe_buf;
+		}
+
+		/* OWE Diffie-Hellman Parameter element */
+		*owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
+		*owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
+		*owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
+							 */
+		WPA_PUT_LE16(owe_buf, sta->owe_group);
+		owe_buf += 2;
+		os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
+		owe_buf += wpabuf_len(pub);
+		wpabuf_free(pub);
+	}
+
+	return owe_buf;
+}
+#endif /* CONFIG_OWE */
+
+
 #ifdef CONFIG_FILS
 
 void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
@@ -3079,8 +3305,12 @@
 			acl_res = ieee802_11_allowed_address(
 				hapd, mgmt->sa, (const u8 *) mgmt, len,
 				&session_timeout, &acct_interim_interval,
-				&vlan_id, &psk, &identity, &radius_cui);
+				&vlan_id, &psk, &identity, &radius_cui, 0);
 			if (acl_res == HOSTAPD_ACL_REJECT) {
+				wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+					"Ignore Association Request frame from "
+					MACSTR " due to ACL reject",
+					MAC2STR(mgmt->sa));
 				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 				goto fail;
 			}
@@ -3144,7 +3374,7 @@
 		WLAN_FC_STYPE_ASSOC_REQ;
 
 	if (hapd->tkip_countermeasures) {
-		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
 
@@ -3174,6 +3404,8 @@
 	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
 	    sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
 	    sta->auth_alg == WLAN_AUTH_FILS_PK) {
+		int res;
+
 		/* The end of the payload is encrypted. Need to decrypt it
 		 * before parsing. */
 
@@ -3183,13 +3415,14 @@
 			goto fail;
 		}
 
-		left = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
-					  len, tmp, left);
-		if (left < 0) {
+		res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
+					 len, tmp, left);
+		if (res < 0) {
 			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 			goto fail;
 		}
 		pos = tmp;
+		left = res;
 	}
 #endif /* CONFIG_FILS */
 
@@ -3208,7 +3441,8 @@
 
 	sta->listen_interval = listen_interval;
 
-	if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
 		sta->flags |= WLAN_STA_NONERP;
 	for (i = 0; i < sta->supported_rates_len; i++) {
 		if ((sta->supported_rates[i] & 0x7f) > 22) {
@@ -3227,7 +3461,8 @@
 	    !sta->no_short_slot_time_set) {
 		sta->no_short_slot_time_set = 1;
 		hapd->iface->num_sta_no_short_slot_time++;
-		if (hapd->iface->current_mode->mode ==
+		if (hapd->iface->current_mode &&
+		    hapd->iface->current_mode->mode ==
 		    HOSTAPD_MODE_IEEE80211G &&
 		    hapd->iface->num_sta_no_short_slot_time == 1)
 			ieee802_11_set_beacons(hapd->iface);
@@ -3242,7 +3477,8 @@
 	    !sta->no_short_preamble_set) {
 		sta->no_short_preamble_set = 1;
 		hapd->iface->num_sta_no_short_preamble++;
-		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		if (hapd->iface->current_mode &&
+		    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
 		    && hapd->iface->num_sta_no_short_preamble == 1)
 			ieee802_11_set_beacons(hapd->iface);
 	}
@@ -3512,7 +3748,8 @@
 
 
 static int handle_action(struct hostapd_data *hapd,
-			 const struct ieee80211_mgmt *mgmt, size_t len)
+			 const struct ieee80211_mgmt *mgmt, size_t len,
+			 unsigned int freq)
 {
 	struct sta_info *sta;
 	sta = ap_get_sta(hapd, mgmt->sa);
@@ -3601,9 +3838,6 @@
 		if (len >= IEEE80211_HDRLEN + 2 &&
 		    mgmt->u.action.u.public_action.action ==
 		    WLAN_PA_20_40_BSS_COEX) {
-			wpa_printf(MSG_DEBUG,
-				   "HT20/40 coex mgmt frame received from STA "
-				   MACSTR, MAC2STR(mgmt->sa));
 			hostapd_2040_coex_action(hapd, mgmt, len);
 			return 1;
 		}
@@ -3621,7 +3855,7 @@
 			pos = mgmt->u.action.u.vs_public_action.oui;
 			end = ((const u8 *) mgmt) + len;
 			hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
-					      hapd->iface->freq);
+					      freq);
 			return 1;
 		}
 		if (len >= IEEE80211_HDRLEN + 2 &&
@@ -3720,10 +3954,17 @@
 	struct ieee80211_mgmt *mgmt;
 	u16 fc, stype;
 	int ret = 0;
+	unsigned int freq;
+	int ssi_signal = fi ? fi->ssi_signal : 0;
 
 	if (len < 24)
 		return 0;
 
+	if (fi && fi->freq)
+		freq = fi->freq;
+	else
+		freq = hapd->iface->freq;
+
 	mgmt = (struct ieee80211_mgmt *) buf;
 	fc = le_to_host16(mgmt->frame_control);
 	stype = WLAN_FC_GET_STYPE(fc);
@@ -3750,7 +3991,7 @@
 
 
 	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
-		handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
+		handle_probe_req(hapd, mgmt, len, ssi_signal);
 		return 1;
 	}
 
@@ -3765,7 +4006,7 @@
 	}
 
 	if (hapd->iconf->track_sta_max_num)
-		sta_track_add(hapd->iface, mgmt->sa, fi->ssi_signal);
+		sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
 
 	switch (stype) {
 	case WLAN_FC_STYPE_AUTH:
@@ -3795,7 +4036,7 @@
 		break;
 	case WLAN_FC_STYPE_ACTION:
 		wpa_printf(MSG_DEBUG, "mgmt::action");
-		ret = handle_action(hapd, mgmt, len);
+		ret = handle_action(hapd, mgmt, len, freq);
 		break;
 	default:
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -3815,9 +4056,22 @@
 	u16 auth_alg, auth_transaction, status_code;
 	struct sta_info *sta;
 
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+		wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+			   (unsigned long) len);
+
+		/*
+		 * Initialize status_code here because we are not able to read
+		 * it from the short payload.
+		 */
+		status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
-		wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+		wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
+			   " not found",
 			   MAC2STR(mgmt->da));
 		return;
 	}
@@ -3833,12 +4087,6 @@
 		goto fail;
 	}
 
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
-			   (unsigned long) len);
-		goto fail;
-	}
-
 	if (status_code == WLAN_STATUS_SUCCESS &&
 	    ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
 	     (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 3b381b4..2f3b4da 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -16,6 +16,8 @@
 struct ieee80211_ht_capabilities;
 struct ieee80211_vht_capabilities;
 struct ieee80211_mgmt;
+struct vlan_description;
+struct hostapd_sta_wpa_psk_short;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 		    struct hostapd_frame_info *fi);
@@ -142,6 +144,9 @@
 				 struct sta_info *sta, int success,
 				 struct wpabuf *erp_resp,
 				 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);
 void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
 void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
 void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
@@ -151,4 +156,14 @@
 				 struct sta_info *sta,
 				 u16 resp, struct wpabuf *data, int pub));
 
+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);
+
 #endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 3308398..5cb7fb1 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -244,6 +244,7 @@
  * @psk: Linked list buffer for returning WPA PSK
  * @identity: Buffer for returning identity (from RADIUS)
  * @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
@@ -254,7 +255,8 @@
 			    u32 *acct_interim_interval,
 			    struct vlan_description *vlan_id,
 			    struct hostapd_sta_wpa_psk_short **psk,
-			    char **identity, char **radius_cui)
+			    char **identity, char **radius_cui,
+			    int is_probe_req)
 {
 	int res;
 
@@ -281,6 +283,12 @@
 #else /* CONFIG_NO_RADIUS */
 		struct hostapd_acl_query_data *query;
 
+		if (is_probe_req) {
+			/* Skip RADIUS queries for Probe Request frames to avoid
+			 * excessive load on the authentication server. */
+			return HOSTAPD_ACL_ACCEPT;
+		};
+
 		/* 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,
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 71f53b9..5aece51 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -23,7 +23,8 @@
 			    u32 *acct_interim_interval,
 			    struct vlan_description *vlan_id,
 			    struct hostapd_sta_wpa_psk_short **psk,
-			    char **identity, char **radius_cui);
+			    char **identity, char **radius_cui,
+			    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);
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 146e447..214855d 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -236,17 +236,29 @@
 	int i;
 	const u8 *start = (const u8 *) mgmt;
 	const u8 *data = start + IEEE80211_HDRLEN + 2;
+	struct sta_info *sta;
+
+	wpa_printf(MSG_DEBUG,
+		   "HT: Received 20/40 BSS Coexistence Management frame from "
+		   MACSTR, MAC2STR(mgmt->sa));
 
 	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
 		       mgmt->u.action.u.public_action.action);
 
-	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+		wpa_printf(MSG_DEBUG,
+			   "Ignore 20/40 BSS Coexistence Management frame since 40 MHz capability is not enabled");
 		return;
+	}
 
-	if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
+	if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) {
+		wpa_printf(MSG_DEBUG,
+			   "Ignore too short 20/40 BSS Coexistence Management frame");
 		return;
+	}
 
+	/* 20/40 BSS Coexistence element */
 	bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
 	if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
 	    bc_ie->length < 1) {
@@ -254,13 +266,35 @@
 			   bc_ie->element_id, bc_ie->length);
 		return;
 	}
-	if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
+	if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) {
+		wpa_printf(MSG_DEBUG,
+			   "Truncated 20/40 BSS Coexistence element");
 		return;
+	}
 	data += 2 + bc_ie->length;
 
-	wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
-		   bc_ie->coex_param);
+	wpa_printf(MSG_DEBUG,
+		   "20/40 BSS Coexistence Information field: 0x%x (%s%s%s%s%s%s)",
+		   bc_ie->coex_param,
+		   (bc_ie->coex_param & BIT(0)) ? "[InfoReq]" : "",
+		   (bc_ie->coex_param & BIT(1)) ? "[40MHzIntolerant]" : "",
+		   (bc_ie->coex_param & BIT(2)) ? "[20MHzBSSWidthReq]" : "",
+		   (bc_ie->coex_param & BIT(3)) ? "[OBSSScanExemptionReq]" : "",
+		   (bc_ie->coex_param & BIT(4)) ?
+		   "[OBSSScanExemptionGrant]" : "",
+		   (bc_ie->coex_param & (BIT(5) | BIT(6) | BIT(7))) ?
+		   "[Reserved]" : "");
+
 	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
+		/* Intra-BSS communication prohibiting 20/40 MHz BSS operation
+		 */
+		sta = ap_get_sta(hapd, mgmt->sa);
+		if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+			wpa_printf(MSG_DEBUG,
+				   "Ignore intra-BSS 20/40 BSS Coexistence Management frame from not-associated STA");
+			return;
+		}
+
 		hostapd_logger(hapd, mgmt->sa,
 			       HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -269,6 +303,8 @@
 	}
 
 	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+		/* Inter-BSS communication prohibiting 20/40 MHz BSS operation
+		 */
 		hostapd_logger(hapd, mgmt->sa,
 			       HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -276,12 +312,16 @@
 		is_ht40_allowed = 0;
 	}
 
-	if (start + len - data >= 3 &&
-	    data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
+	/* 20/40 BSS Intolerant Channel Report element (zero or more times) */
+	while (start + len - data >= 3 &&
+	       data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
 		u8 ielen = data[1];
 
-		if (ielen > start + len - data - 2)
+		if (ielen > start + len - data - 2) {
+			wpa_printf(MSG_DEBUG,
+				   "Truncated 20/40 BSS Intolerant Channel Report element");
 			return;
+		}
 		ic_report = (struct ieee80211_2040_intol_chan_report *) data;
 		wpa_printf(MSG_DEBUG,
 			   "20/40 BSS Intolerant Channel Report: Operating Class %u",
@@ -292,8 +332,10 @@
 		for (i = 0; i < ielen - 1; i++) {
 			u8 chan = ic_report->variable[i];
 
+			if (chan == iface->conf->channel)
+				continue; /* matching own primary channel */
 			if (is_40_allowed(iface, chan))
-				continue;
+				continue; /* not within affected channels */
 			hostapd_logger(hapd, mgmt->sa,
 				       HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_DEBUG,
@@ -301,6 +343,8 @@
 				       chan);
 			is_ht40_allowed = 0;
 		}
+
+		data += 2 + ielen;
 	}
 	wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
 		   is_ht40_allowed, iface->num_sta_ht40_intolerant);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 902f64f..c481399 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -178,6 +178,10 @@
 	case 1: /* Bits 8-15 */
 		if (hapd->conf->proxy_arp)
 			*pos |= 0x10; /* Bit 12 - Proxy ARP */
+		if (hapd->conf->coloc_intf_reporting) {
+			/* Bit 13 - Collocated Interference Reporting */
+			*pos |= 0x20;
+		}
 		break;
 	case 2: /* Bits 16-23 */
 		if (hapd->conf->wnm_sleep_mode)
@@ -225,6 +229,7 @@
 			*pos |= 0x40; /* Bit 70 - FTM responder */
 		if (hapd->conf->ftm_initiator)
 			*pos |= 0x80; /* Bit 71 - FTM initiator */
+		break;
 	case 9: /* Bits 72-79 */
 #ifdef CONFIG_FILS
 		if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
@@ -445,7 +450,7 @@
 {
 	size_t len;
 
-	if (hapd->conf->time_advertisement != 2)
+	if (hapd->conf->time_advertisement != 2 || !hapd->conf->time_zone)
 		return eid;
 
 	len = os_strlen(hapd->conf->time_zone);
@@ -607,6 +612,67 @@
 #endif /* CONFIG_MBO */
 
 
+#ifdef CONFIG_OWE
+static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
+{
+	return hapd->conf->owe_transition_ssid_len > 0 &&
+		!is_zero_ether_addr(hapd->conf->owe_transition_bssid);
+}
+#endif /* CONFIG_OWE */
+
+
+size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_OWE
+	if (!hostapd_eid_owe_trans_enabled(hapd))
+		return 0;
+	return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
+#else /* CONFIG_OWE */
+	return 0;
+#endif /* CONFIG_OWE */
+}
+
+
+u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
+				  size_t len)
+{
+#ifdef CONFIG_OWE
+	u8 *pos = eid;
+	size_t elen;
+
+	if (hapd->conf->owe_transition_ifname[0] &&
+	    !hostapd_eid_owe_trans_enabled(hapd))
+		hostapd_owe_trans_get_info(hapd);
+
+	if (!hostapd_eid_owe_trans_enabled(hapd))
+		return pos;
+
+	elen = hostapd_eid_owe_trans_len(hapd);
+	if (len < elen) {
+		wpa_printf(MSG_DEBUG,
+			   "OWE: Not enough room in the buffer for OWE IE");
+		return pos;
+	}
+
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = elen - 2;
+	WPA_PUT_BE24(pos, OUI_WFA);
+	pos += 3;
+	*pos++ = OWE_OUI_TYPE;
+	os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
+	pos += ETH_ALEN;
+	*pos++ = hapd->conf->owe_transition_ssid_len;
+	os_memcpy(pos, hapd->conf->owe_transition_ssid,
+		  hapd->conf->owe_transition_ssid_len);
+	pos += hapd->conf->owe_transition_ssid_len;
+
+	return pos;
+#else /* CONFIG_OWE */
+	return eid;
+#endif /* CONFIG_OWE */
+}
+
+
 void ap_copy_sta_supp_op_classes(struct sta_info *sta,
 				 const u8 *supp_op_classes,
 				 size_t supp_op_classes_len)
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 793d381..985f8b7 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -712,6 +712,41 @@
 				goto fail;
 			}
 		}
+
+		if (sta->roaming_consortium &&
+		    !radius_msg_add_wfa(
+			    msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM,
+			    wpabuf_head(sta->roaming_consortium),
+			    wpabuf_len(sta->roaming_consortium))) {
+			wpa_printf(MSG_ERROR,
+				   "Could not add HS 2.0 Roaming Consortium");
+			goto fail;
+		}
+
+		if (hapd->conf->t_c_filename) {
+			be32 timestamp;
+
+			if (!radius_msg_add_wfa(
+				    msg,
+				    RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME,
+				    (const u8 *) hapd->conf->t_c_filename,
+				    os_strlen(hapd->conf->t_c_filename))) {
+				wpa_printf(MSG_ERROR,
+					   "Could not add HS 2.0 T&C Filename");
+				goto fail;
+			}
+
+			timestamp = host_to_be32(hapd->conf->t_c_timestamp);
+			if (!radius_msg_add_wfa(
+				    msg,
+				    RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP,
+				    (const u8 *) &timestamp,
+				    sizeof(timestamp))) {
+				wpa_printf(MSG_ERROR,
+					   "Could not add HS 2.0 Timestamp");
+				goto fail;
+			}
+		}
 	}
 #endif /* CONFIG_HS20 */
 
@@ -1177,7 +1212,7 @@
 		sta->eapol_sm->portValid = TRUE;
 		if (sta->eapol_sm->eap)
 			eap_sm_notify_cached(sta->eapol_sm->eap);
-		/* TODO: get vlan_id from R0KH using RRB message */
+		ap_sta_bind_vlan(hapd, sta);
 		return;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
@@ -1587,6 +1622,33 @@
 	ap_sta_session_warning_timeout(hapd, sta, warning_time);
 }
 
+
+static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd,
+					  struct sta_info *sta, u8 *pos,
+					  size_t len)
+{
+	if (len < 4)
+		return; /* Malformed information */
+	wpa_printf(MSG_DEBUG,
+		   "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
+		   pos[0], pos[1], pos[2], pos[3]);
+	hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0));
+}
+
+
+static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd,
+				    struct sta_info *sta, u8 *pos, size_t len)
+{
+	os_free(sta->t_c_url);
+	sta->t_c_url = os_malloc(len + 1);
+	if (!sta->t_c_url)
+		return;
+	os_memcpy(sta->t_c_url, pos, len);
+	sta->t_c_url[len] = '\0';
+	wpa_printf(MSG_DEBUG,
+		   "HS 2.0: Terms and Conditions URL %s", sta->t_c_url);
+}
+
 #endif /* CONFIG_HS20 */
 
 
@@ -1634,6 +1696,12 @@
 			ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
 						     session_timeout);
 			break;
+		case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING:
+			ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen);
+			break;
+		case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL:
+			ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen);
+			break;
 		}
 	}
 #endif /* CONFIG_HS20 */
@@ -1691,6 +1759,7 @@
 	struct sta_info *sta;
 	u32 session_timeout = 0, termination_action, acct_interim_interval;
 	int session_timeout_set;
+	u32 reason_code;
 	struct eapol_state_machine *sm;
 	int override_eapReq = 0;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
@@ -1816,14 +1885,17 @@
 			break;
 
 		sta->session_timeout_set = !!session_timeout_set;
-		sta->session_timeout = session_timeout;
+		os_get_reltime(&sta->session_timeout);
+		sta->session_timeout.sec += session_timeout;
 
 		/* RFC 3580, Ch. 3.17 */
 		if (session_timeout_set && termination_action ==
-		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
+		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
 			sm->reAuthPeriod = session_timeout;
-		} else if (session_timeout_set)
+		else if (session_timeout_set)
 			ap_sta_session_timeout(hapd, sta, session_timeout);
+		else
+			ap_sta_no_session_timeout(hapd, sta);
 
 		sm->eap_if->aaaSuccess = TRUE;
 		override_eapReq = 1;
@@ -1839,6 +1911,13 @@
 	case RADIUS_CODE_ACCESS_REJECT:
 		sm->eap_if->aaaFail = TRUE;
 		override_eapReq = 1;
+		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
+					      &reason_code) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for "
+				   MACSTR, reason_code, MAC2STR(sta->addr));
+			sta->disconnect_reason_code = reason_code;
+		}
 		break;
 	case RADIUS_CODE_ACCESS_CHALLENGE:
 		sm->eap_if->aaaEapReq = TRUE;
@@ -2081,6 +2160,13 @@
 			goto out;
 		user->password_len = eap_user->password_len;
 		user->password_hash = eap_user->password_hash;
+		if (eap_user->salt && eap_user->salt_len) {
+			user->salt = os_memdup(eap_user->salt,
+					       eap_user->salt_len);
+			if (!user->salt)
+				goto out;
+			user->salt_len = eap_user->salt_len;
+		}
 	}
 	user->force_version = eap_user->force_version;
 	user->macacl = eap_user->macacl;
@@ -2693,6 +2779,15 @@
 		hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
 						      sta->hs20_deauth_req);
 	}
+
+	if (sta->hs20_t_c_filtering) {
+		wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+			   MACSTR " to indicate Terms and Conditions filtering",
+			   MAC2STR(sta->addr));
+		hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url);
+		os_free(sta->t_c_url);
+		sta->t_c_url = NULL;
+	}
 }
 #endif /* CONFIG_HS20 */
 
@@ -2706,6 +2801,7 @@
 	/* TODO: get PMKLifetime from WPA parameters */
 	static const int dot11RSNAConfigPMKLifetime = 43200;
 	unsigned int session_timeout;
+	struct os_reltime now, remaining;
 
 #ifdef CONFIG_HS20
 	if (remediation && !sta->remediation) {
@@ -2716,7 +2812,8 @@
 		sta->remediation_method = 1; /* SOAP-XML SPP */
 	}
 
-	if (success && (sta->remediation || sta->hs20_deauth_req)) {
+	if (success && (sta->remediation || sta->hs20_deauth_req ||
+			sta->hs20_t_c_filtering)) {
 		wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
 			   MACSTR " in 100 ms", MAC2STR(sta->addr));
 		eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
@@ -2726,10 +2823,13 @@
 #endif /* CONFIG_HS20 */
 
 	key = ieee802_1x_get_key(sta->eapol_sm, &len);
-	if (sta->session_timeout_set)
-		session_timeout = sta->session_timeout;
-	else
+	if (sta->session_timeout_set) {
+		os_get_reltime(&now);
+		os_reltime_sub(&sta->session_timeout, &now, &remaining);
+		session_timeout = (remaining.sec > 0) ? remaining.sec : 1;
+	} else {
 		session_timeout = dot11RSNAConfigPMKLifetime;
+	}
 	if (success && key && len >= PMK_LEN && !sta->remediation &&
 	    !sta->hs20_deauth_requested &&
 	    wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index b1fde3c..179cf43 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -197,7 +197,8 @@
 	if (sta->no_short_slot_time_set) {
 		sta->no_short_slot_time_set = 0;
 		hapd->iface->num_sta_no_short_slot_time--;
-		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		if (hapd->iface->current_mode &&
+		    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
 		    && hapd->iface->num_sta_no_short_slot_time == 0)
 			set_beacon++;
 	}
@@ -205,7 +206,8 @@
 	if (sta->no_short_preamble_set) {
 		sta->no_short_preamble_set = 0;
 		hapd->iface->num_sta_no_short_preamble--;
-		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		if (hapd->iface->current_mode &&
+		    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
 		    && hapd->iface->num_sta_no_short_preamble == 0)
 			set_beacon++;
 	}
@@ -319,6 +321,7 @@
 	wpabuf_free(sta->wps_ie);
 	wpabuf_free(sta->p2p_ie);
 	wpabuf_free(sta->hs20_ie);
+	wpabuf_free(sta->roaming_consortium);
 #ifdef CONFIG_FST
 	wpabuf_free(sta->mb_ies);
 #endif /* CONFIG_FST */
@@ -329,6 +332,7 @@
 	os_free(sta->identity);
 	os_free(sta->radius_cui);
 	os_free(sta->remediation_url);
+	os_free(sta->t_c_url);
 	wpabuf_free(sta->hs20_deauth_req);
 	os_free(sta->hs20_session_info_url);
 
@@ -357,6 +361,14 @@
 	crypto_ecdh_deinit(sta->owe_ecdh);
 #endif /* CONFIG_OWE */
 
+	os_free(sta->ext_capability);
+
+#ifdef CONFIG_WNM_AP
+	eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
+#endif /* CONFIG_WNM_AP */
+
+	os_free(sta->ifname_wds);
+
 	os_free(sta);
 }
 
@@ -1342,7 +1354,7 @@
 	int res;
 
 	buf[0] = '\0';
-	res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+	res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
 			  (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
 			  (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
 			  (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1359,6 +1371,7 @@
 			  (flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
 			  (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
 			  (flags & WLAN_STA_GAS ? "[GAS]" : ""),
+			  (flags & WLAN_STA_HT ? "[HT]" : ""),
 			  (flags & WLAN_STA_VHT ? "[VHT]" : ""),
 			  (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
 			  (flags & WLAN_STA_WNM_SLEEP_MODE ?
@@ -1374,13 +1387,16 @@
 {
 	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
+	u16 reason;
 
 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
 		"IEEE 802.1X: Scheduled disconnection of " MACSTR
 		" after EAP-Failure", MAC2STR(sta->addr));
 
-	ap_sta_disconnect(hapd, sta, sta->addr,
-			  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+	reason = sta->disconnect_reason_code;
+	if (!reason)
+		reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
+	ap_sta_disconnect(hapd, sta, sta->addr, reason);
 	if (sta->flags & WLAN_STA_WPS)
 		hostapd_wps_eap_completed(hapd);
 }
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 3fb60f6..9cac6f1 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -9,11 +9,7 @@
 #ifndef STA_INFO_H
 #define STA_INFO_H
 
-#ifdef CONFIG_MESH
-/* needed for mesh_plink_state enum */
 #include "common/defs.h"
-#endif /* CONFIG_MESH */
-
 #include "list.h"
 #include "vlan.h"
 #include "common/wpa_common.h"
@@ -71,6 +67,7 @@
 	be32 ipaddr;
 	struct dl_list ip6addr; /* list head for struct ip6addr */
 	u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+	u16 disconnect_reason_code; /* RADIUS server override */
 	u32 flags; /* Bitfield of WLAN_STA_* */
 	u16 capability;
 	u16 listen_interval; /* or beacon_int for APs */
@@ -117,6 +114,9 @@
 	unsigned int ecsa_supported:1;
 	unsigned int added_unassoc:1;
 	unsigned int pending_wds_enable:1;
+	unsigned int power_capab:1;
+	unsigned int agreed_to_steer:1;
+	unsigned int hs20_t_c_filtering:1;
 
 	u16 auth_alg;
 
@@ -183,8 +183,11 @@
 	struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
 	struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
 	struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+	/* Hotspot 2.0 Roaming Consortium from (Re)Association Request */
+	struct wpabuf *roaming_consortium;
 	u8 remediation_method;
 	char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
+	char *t_c_url; /* HS 2.0 Terms and Conditions Server URL */
 	struct wpabuf *hs20_deauth_req;
 	char *hs20_session_info_url;
 	int hs20_disassoc_timer;
@@ -199,7 +202,8 @@
 	unsigned int mesh_sae_pmksa_caching:1;
 #endif /* CONFIG_SAE */
 
-	u32 session_timeout; /* valid only if session_timeout_set == 1 */
+	/* valid only if session_timeout_set == 1 */
+	struct os_reltime session_timeout;
 
 	/* Last Authentication/(Re)Association Request/Action frame sequence
 	 * control */
@@ -218,6 +222,9 @@
 
 	u8 rrm_enabled_capa[5];
 
+	s8 min_tx_power;
+	s8 max_tx_power;
+
 #ifdef CONFIG_TAXONOMY
 	struct wpabuf *probe_ie_taxonomy;
 	struct wpabuf *assoc_ie_taxonomy;
@@ -251,6 +258,9 @@
 	u16 owe_group;
 #endif /* CONFIG_OWE */
 
+	u8 *ext_capability;
+	char *ifname_wds; /* WDS ifname, if in use */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	enum wpa_alg last_tk_alg;
 	int last_tk_key_idx;
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 4725e2b..557570c 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -71,6 +71,11 @@
 	struct os_reltime now;
 	int ret = 0;
 
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO,
+		       "Michael MIC failure detected in received frame%s",
+		       local ? " (local)" : "");
+
 	if (addr && local) {
 		struct sta_info *sta = ap_get_sta(hapd, addr);
 		if (sta != NULL) {
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 31e4fc6..01fecee 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -138,6 +138,8 @@
 	    !hapd->conf->vlan) {
 		/* dynamic vlans enabled but no (or empty) vlan_file given */
 		struct hostapd_vlan *vlan;
+		int ret;
+
 		vlan = os_zalloc(sizeof(*vlan));
 		if (vlan == NULL) {
 			wpa_printf(MSG_ERROR, "Out of memory while assigning "
@@ -146,8 +148,16 @@
 		}
 
 		vlan->vlan_id = VLAN_ID_WILDCARD;
-		os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
-			    hapd->conf->iface);
+		ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
+				  hapd->conf->iface);
+		if (ret >= (int) sizeof(vlan->ifname)) {
+			wpa_printf(MSG_WARNING,
+				   "VLAN: Interface name was truncated to %s",
+				   vlan->ifname);
+		} else if (ret < 0) {
+			os_free(vlan);
+			return ret;
+		}
 		vlan->next = hapd->conf->vlan;
 		hapd->conf->vlan = vlan;
 	}
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index adb66c1..61d2f65 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -109,6 +109,7 @@
 	pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
 	/* add key data if MFP is enabled */
 	if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+	    hapd->conf->wnm_sleep_mode_no_keys ||
 	    action_type != WNM_SLEEP_MODE_EXIT) {
 		mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
 	} else {
@@ -173,7 +174,8 @@
 			wpa_set_wnmsleep(sta->wpa_sm, 0);
 			hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
 					     addr, NULL, NULL);
-			if (!wpa_auth_uses_mfp(sta->wpa_sm))
+			if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+			    hapd->conf->wnm_sleep_mode_no_keys)
 				wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
 		}
 	} else
@@ -200,6 +202,13 @@
 	u8 *tfsreq_ie_end = NULL;
 	u16 tfsreq_ie_len = 0;
 
+	if (!hapd->conf->wnm_sleep_mode) {
+		wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
+			   MACSTR " since WNM-Sleep Mode is disabled",
+			   MAC2STR(addr));
+		return;
+	}
+
 	if (len < 1) {
 		wpa_printf(MSG_DEBUG,
 			   "WNM: Ignore too short WNM-Sleep Mode Request from "
@@ -302,6 +311,20 @@
 {
 	u8 dialog_token, reason;
 	const u8 *pos, *end;
+	int enabled = hapd->conf->bss_transition;
+
+#ifdef CONFIG_MBO
+	if (hapd->conf->mbo_enabled)
+		enabled = 1;
+#endif /* CONFIG_MBO */
+	if (!enabled) {
+		wpa_printf(MSG_DEBUG,
+			   "Ignore BSS Transition Management Query from "
+			   MACSTR
+			   " since BSS Transition Management is disabled",
+			   MAC2STR(addr));
+		return;
+	}
 
 	if (len < 2) {
 		wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
@@ -325,12 +348,40 @@
 }
 
 
+void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	if (sta->agreed_to_steer) {
+		wpa_printf(MSG_DEBUG, "%s: Reset steering flag for STA " MACSTR,
+			   hapd->conf->iface, MAC2STR(sta->addr));
+		sta->agreed_to_steer = 0;
+	}
+}
+
+
 static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
 					      const u8 *addr, const u8 *frm,
 					      size_t len)
 {
 	u8 dialog_token, status_code, bss_termination_delay;
 	const u8 *pos, *end;
+	int enabled = hapd->conf->bss_transition;
+	struct sta_info *sta;
+
+#ifdef CONFIG_MBO
+	if (hapd->conf->mbo_enabled)
+		enabled = 1;
+#endif /* CONFIG_MBO */
+	if (!enabled) {
+		wpa_printf(MSG_DEBUG,
+			   "Ignore BSS Transition Management Response from "
+			   MACSTR
+			   " since BSS Transition Management is disabled",
+			   MAC2STR(addr));
+		return;
+	}
 
 	if (len < 3) {
 		wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
@@ -349,11 +400,23 @@
 		   "bss_termination_delay=%u", MAC2STR(addr), dialog_token,
 		   status_code, bss_termination_delay);
 
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+			   " not found for received BSS TM Response",
+			   MAC2STR(addr));
+		return;
+	}
+
 	if (status_code == WNM_BSS_TM_ACCEPT) {
 		if (end - pos < ETH_ALEN) {
 			wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
 			return;
 		}
+		sta->agreed_to_steer = 1;
+		eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
+		eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
+				       hapd, sta);
 		wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
 			   MAC2STR(pos));
 		wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
@@ -363,6 +426,7 @@
 			MAC2STR(pos));
 		pos += ETH_ALEN;
 	} else {
+		sta->agreed_to_steer = 0;
 		wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
 			" status_code=%u bss_termination_delay=%u",
 			MAC2STR(addr), status_code, bss_termination_delay);
@@ -396,6 +460,48 @@
 }
 
 
+static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd,
+						const u8 *addr, const u8 *buf,
+						size_t len)
+{
+	u8 dialog_token;
+	char *hex;
+	size_t hex_len;
+
+	if (!hapd->conf->coloc_intf_reporting) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Ignore unexpected Collocated Interference Report from "
+			   MACSTR, MAC2STR(addr));
+		return;
+	}
+
+	if (len < 1) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Ignore too short Collocated Interference Report from "
+			   MACSTR, MAC2STR(addr));
+		return;
+	}
+	dialog_token = *buf++;
+	len--;
+
+	wpa_printf(MSG_DEBUG,
+		   "WNM: Received Collocated Interference Report frame from "
+		   MACSTR " (dialog_token=%u)",
+		   MAC2STR(addr), dialog_token);
+	wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements",
+		    buf, len);
+
+	hex_len = 2 * len + 1;
+	hex = os_malloc(hex_len);
+	if (!hex)
+		return;
+	wpa_snprintf_hex(hex, hex_len, buf, len);
+	wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s",
+		     MAC2STR(addr), dialog_token, hex);
+	os_free(hex);
+}
+
+
 int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
 				const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -426,6 +532,10 @@
 		ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
 						   plen);
 		return 0;
+	case WNM_COLLOCATED_INTERFERENCE_REPORT:
+		ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload,
+						    plen);
+		return 0;
 	}
 
 	wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
@@ -624,3 +734,40 @@
 
 	return 0;
 }
+
+
+int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
+			    unsigned int auto_report, unsigned int timeout)
+{
+	u8 buf[100], *pos;
+	struct ieee80211_mgmt *mgmt;
+	u8 dialog_token = 1;
+
+	if (auto_report > 3 || timeout > 63)
+		return -1;
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.coloc_intf_req.action =
+		WNM_COLLOCATED_INTERFERENCE_REQ;
+	mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token;
+	mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2);
+	pos = &mgmt->u.action.u.coloc_intf_req.req_info;
+	pos++;
+
+	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) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Failed to send Collocated Interference Request frame");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index a44eadb..1806ba0 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -23,5 +23,8 @@
 			const u8 *bss_term_dur, const char *url,
 			const u8 *nei_rep, size_t nei_rep_len,
 			const u8 *mbo_attrs, size_t mbo_len);
+void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx);
+int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
+			    unsigned int auto_report, unsigned int timeout);
 
 #endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 8265fa1..34969e7 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,6 +19,7 @@
 #include "crypto/crypto.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/sha384.h"
 #include "crypto/random.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "ap_config.h"
@@ -237,23 +238,6 @@
 }
 
 
-static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
-{
-	int ret = 0;
-#ifdef CONFIG_IEEE80211R_AP
-	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-		ret = 1;
-#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
-	if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
-		ret = 1;
-#endif /* CONFIG_IEEE80211W */
-	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
-		ret = 1;
-	return ret;
-}
-
-
 static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_authenticator *wpa_auth = eloop_ctx;
@@ -698,9 +682,10 @@
 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
 				"strict rekeying - force GTK rekey since STA "
 				"is leaving");
-		eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
-		eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
-				       NULL);
+		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);
 	}
 
 	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
@@ -859,6 +844,12 @@
 					       sm->p2p_dev_addr, pmk, &pmk_len);
 			if (pmk == NULL)
 				break;
+#ifdef CONFIG_IEEE80211R_AP
+			if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+				os_memcpy(sm->xxkey, pmk, pmk_len);
+				sm->xxkey_len = pmk_len;
+			}
+#endif /* CONFIG_IEEE80211R_AP */
 		} else {
 			pmk = sm->PMK;
 			pmk_len = sm->pmk_len;
@@ -873,7 +864,8 @@
 			break;
 		}
 
-		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+		    wpa_key_mgmt_sae(sm->wpa_key_mgmt))
 			break;
 	}
 
@@ -1001,10 +993,8 @@
 		u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
 		if (sm->pairwise == WPA_CIPHER_CCMP ||
 		    sm->pairwise == WPA_CIPHER_GCMP) {
-			if (wpa_use_aes_cmac(sm) &&
-			    sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
-			    !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
-			    !wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+			if (wpa_use_cmac(sm->wpa_key_mgmt) &&
+			    !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
 			    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
 				wpa_auth_logger(wpa_auth, sm->addr,
 						LOGGER_WARNING,
@@ -1014,11 +1004,8 @@
 				return;
 			}
 
-			if (!wpa_use_aes_cmac(sm) &&
-			    !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
-			    !wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
-			    sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE &&
-			    sm->wpa_key_mgmt != WPA_KEY_MGMT_DPP &&
+			if (!wpa_use_cmac(sm->wpa_key_mgmt) &&
+			    !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
 			    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 				wpa_auth_logger(wpa_auth, sm->addr,
 						LOGGER_WARNING,
@@ -1028,10 +1015,7 @@
 			}
 		}
 
-		if ((wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
-		     wpa_key_mgmt_fils(sm->wpa_key_mgmt) ||
-		     sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
-		     sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) &&
+		if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
 		    ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
 					"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
@@ -1317,7 +1301,7 @@
 static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
 			  const u8 *gnonce, u8 *gtk, size_t gtk_len)
 {
-	u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16];
+	u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + WPA_GTK_MAX_LEN];
 	u8 *pos;
 	int ret = 0;
 
@@ -1328,21 +1312,30 @@
 	 * is done only at the Authenticator and as such, does not need to be
 	 * exactly same.
 	 */
+	os_memset(data, 0, sizeof(data));
 	os_memcpy(data, addr, ETH_ALEN);
 	os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
 	pos = data + ETH_ALEN + WPA_NONCE_LEN;
 	wpa_get_ntp_timestamp(pos);
 	pos += 8;
-	if (random_get_bytes(pos, 16) < 0)
+	if (random_get_bytes(pos, gtk_len) < 0)
 		ret = -1;
 
-#ifdef CONFIG_IEEE80211W
-	sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len);
-#else /* CONFIG_IEEE80211W */
-	if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len)
-	    < 0)
+#ifdef CONFIG_SHA384
+	if (sha384_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+		       gtk, gtk_len) < 0)
 		ret = -1;
-#endif /* CONFIG_IEEE80211W */
+#else /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA256
+	if (sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+		       gtk, gtk_len) < 0)
+		ret = -1;
+#else /* CONFIG_SHA256 */
+	if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+		     gtk, gtk_len) < 0)
+		ret = -1;
+#endif /* CONFIG_SHA256 */
+#endif /* CONFIG_SHA384 */
 
 	return ret;
 }
@@ -1383,13 +1376,9 @@
 
 	if (force_version)
 		version = force_version;
-	else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
-		 sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
-		 sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
-		 wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
-		 wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+	else if (wpa_use_akm_defined(sm->wpa_key_mgmt))
 		version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
-	else if (wpa_use_aes_cmac(sm))
+	else if (wpa_use_cmac(sm->wpa_key_mgmt))
 		version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
 	else if (sm->pairwise != WPA_CIPHER_TKIP)
 		version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@@ -1411,10 +1400,7 @@
 	key_data_len = kde_len;
 
 	if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
-	     sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
-	     sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
-	     sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
-	     wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+	     wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
 	     version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
 		pad_len = key_data_len % 8;
 		if (pad_len)
@@ -1474,7 +1460,7 @@
 		os_memcpy(key_data, kde, kde_len);
 		WPA_PUT_BE16(key_mic + mic_len, kde_len);
 #ifdef CONFIG_FILS
-	} else if (!mic_len) {
+	} else if (!mic_len && kde) {
 		const u8 *aad[1];
 		size_t aad_len[1];
 
@@ -1513,10 +1499,7 @@
 		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
 				buf, key_data_len);
 		if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
-		    sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
-		    sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
-		    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
-		    wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+		    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)",
@@ -1560,9 +1543,12 @@
 			return;
 		}
 
-		wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
-				  sm->wpa_key_mgmt, version,
-				  (u8 *) hdr, len, key_mic);
+		if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+				      sm->wpa_key_mgmt, version,
+				      (u8 *) hdr, len, key_mic) < 0) {
+			os_free(hdr);
+			return;
+		}
 #ifdef CONFIG_TESTING_OPTIONS
 		if (!pairwise &&
 		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1963,8 +1949,13 @@
 		sm->pmk_len = pmk_len;
 #ifdef CONFIG_IEEE80211R_AP
 		if (len >= 2 * PMK_LEN) {
-			os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
-			sm->xxkey_len = PMK_LEN;
+			if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
+				os_memcpy(sm->xxkey, msk, SHA384_MAC_LEN);
+				sm->xxkey_len = SHA384_MAC_LEN;
+			} else {
+				os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
+				sm->xxkey_len = PMK_LEN;
+			}
 		}
 #endif /* CONFIG_IEEE80211R_AP */
 	} else {
@@ -2035,8 +2026,18 @@
 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
 			"sending 1/4 msg of 4-Way Handshake");
 	/*
-	 * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
-	 * one possible PSK for this STA.
+	 * For infrastructure BSS cases, it is better for the AP not to include
+	 * the PMKID KDE in EAPOL-Key msg 1/4 since it could be used to initiate
+	 * offline search for the passphrase/PSK without having to be able to
+	 * capture a 4-way handshake from a STA that has access to the network.
+	 *
+	 * For IBSS cases, addition of PMKID KDE could be considered even with
+	 * WPA2-PSK cases that use multiple PSKs, but only if there is a single
+	 * possible PSK for this STA. However, this should not be done unless
+	 * there is support for using that information on the supplicant side.
+	 * The concern about exposing PMKID unnecessarily in infrastructure BSS
+	 * cases would also apply here, but at least in the IBSS case, this
+	 * would cover a potential real use case.
 	 */
 	if (sm->wpa == WPA_VERSION_WPA2 &&
 	    (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
@@ -2049,11 +2050,31 @@
 		pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
 		RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
 		if (sm->pmksa) {
+			wpa_hexdump(MSG_DEBUG,
+				    "RSN: Message 1/4 PMKID from PMKSA entry",
+				    sm->pmksa->pmkid, PMKID_LEN);
 			os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
 				  sm->pmksa->pmkid, PMKID_LEN);
 		} else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
 			/* No KCK available to derive PMKID */
+			wpa_printf(MSG_DEBUG,
+				   "RSN: No KCK available to derive PMKID for message 1/4");
 			pmkid = NULL;
+#ifdef CONFIG_SAE
+		} else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
+			if (sm->pmkid_set) {
+				wpa_hexdump(MSG_DEBUG,
+					    "RSN: Message 1/4 PMKID from SAE",
+					    sm->pmkid, PMKID_LEN);
+				os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+					  sm->pmkid, PMKID_LEN);
+			} else {
+				/* No PMKID available */
+				wpa_printf(MSG_DEBUG,
+					   "RSN: No SAE PMKID available for message 1/4");
+				pmkid = NULL;
+			}
+#endif /* CONFIG_SAE */
 		} else {
 			/*
 			 * Calculate PMKID since no PMKSA cache entry was
@@ -2062,6 +2083,9 @@
 			rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
 				  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
 				  sm->wpa_key_mgmt);
+			wpa_hexdump(MSG_DEBUG,
+				    "RSN: Message 1/4 PMKID derived from PMK",
+				    &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
 		}
 	}
 	wpa_send_eapol(sm->wpa_auth, sm,
@@ -2112,21 +2136,24 @@
 	if (fils_ft_len) {
 		struct wpa_authenticator *wpa_auth = sm->wpa_auth;
 		struct wpa_auth_config *conf = &wpa_auth->conf;
-		u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
+		u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+		int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+		size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
 
 		if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
 				      conf->ssid, conf->ssid_len,
 				      conf->mobility_domain,
 				      conf->r0_key_holder,
 				      conf->r0_key_holder_len,
-				      sm->addr, pmk_r0, pmk_r0_name) < 0)
+				      sm->addr, pmk_r0, pmk_r0_name,
+				      use_sha384) < 0)
 			return -1;
 
-		wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0", pmk_r0, PMK_LEN);
+		wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
+				pmk_r0, pmk_r0_len);
 		wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
 			    pmk_r0_name, WPA_PMK_NAME_LEN);
-		wpa_ft_store_pmk_r0(wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
-				    sm->pairwise);
+		wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
 		os_memset(fils_ft, 0, sizeof(fils_ft));
 	}
 #endif /* CONFIG_IEEE80211R_AP */
@@ -2507,7 +2534,8 @@
 	/* GTK KDE */
 	gtk = gsm->GTK[gsm->GN - 1];
 	gtk_len = gsm->GTK_len;
-	if (sm->wpa_auth->conf.disable_gtk) {
+	if (sm->wpa_auth->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.
@@ -2629,6 +2657,12 @@
 			if (pmk == NULL)
 				break;
 			psk_found = 1;
+#ifdef CONFIG_IEEE80211R_AP
+			if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+				os_memcpy(sm->xxkey, pmk, pmk_len);
+				sm->xxkey_len = pmk_len;
+			}
+#endif /* CONFIG_IEEE80211R_AP */
 		} else {
 			pmk = sm->PMK;
 			pmk_len = sm->pmk_len;
@@ -2654,7 +2688,8 @@
 		}
 #endif /* CONFIG_FILS */
 
-		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+		    wpa_key_mgmt_sae(sm->wpa_key_mgmt))
 			break;
 	}
 
@@ -2816,7 +2851,8 @@
 	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) {
+	if (sm->wpa_auth->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.
@@ -2894,7 +2930,8 @@
 		secure = 1;
 		gtk = gsm->GTK[gsm->GN - 1];
 		gtk_len = gsm->GTK_len;
-		if (sm->wpa_auth->conf.disable_gtk) {
+		if (sm->wpa_auth->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.
@@ -2987,7 +3024,10 @@
 				  2 + sm->assoc_resp_ftie[1]);
 			res = 2 + sm->assoc_resp_ftie[1];
 		} else {
-			res = wpa_write_ftie(conf, conf->r0_key_holder,
+			int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
+			res = wpa_write_ftie(conf, use_sha384,
+					     conf->r0_key_holder,
 					     conf->r0_key_holder_len,
 					     NULL, NULL, pos,
 					     kde + kde_len - pos,
@@ -3012,7 +3052,7 @@
 		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
 		*pos++ = 5;
 		*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
-		WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+		WPA_PUT_LE32(pos, conf->r0_key_lifetime);
 		pos += 4;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
@@ -3270,7 +3310,8 @@
 			"sending 1/2 msg of Group Key Handshake");
 
 	gtk = gsm->GTK[gsm->GN - 1];
-	if (sm->wpa_auth->conf.disable_gtk) {
+	if (sm->wpa_auth->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.
@@ -4047,6 +4088,13 @@
 }
 
 
+void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid)
+{
+	os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+	sm->pmkid_set = 1;
+}
+
+
 int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
 			int session_timeout, int akmp)
@@ -4505,11 +4553,12 @@
 
 
 #ifdef CONFIG_IEEE80211R_AP
-int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, u8 *buf, size_t len)
+int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
+		       u8 *buf, size_t len)
 {
 	struct wpa_auth_config *conf = &wpa_auth->conf;
 
-	return wpa_write_ftie(conf, conf->r0_key_holder,
+	return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
 			      conf->r0_key_holder_len,
 			      NULL, NULL, buf, len, NULL, 0);
 }
@@ -4529,7 +4578,7 @@
 #endif /* CONFIG_FILS */
 
 
-#if CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_TESTING_OPTIONS
 
 int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
 		       void (*cb)(void *ctx1, void *ctx2),
@@ -4557,7 +4606,10 @@
 		       void (*cb)(void *ctx1, void *ctx2),
 		       void *ctx1, void *ctx2)
 {
-	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, *opos;
+	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+#ifdef CONFIG_IEEE80211W
+	u8 *opos;
+#endif /* CONFIG_IEEE80211W */
 	size_t gtk_len, kde_len;
 	struct wpa_group *gsm = sm->group;
 	u8 *wpa_ie;
@@ -4654,12 +4706,15 @@
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gtk_len);
 	}
+#ifdef CONFIG_IEEE80211W
 	opos = pos;
 	pos = ieee80211w_kde_add(sm, pos);
-	if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) {
-		opos += 2; /* skip keyid */
+	if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
+		/* skip KDE header and keyid */
+		opos += 2 + RSN_SELECTOR_LEN + 2;
 		os_memset(opos, 0, 6); /* clear PN */
 	}
+#endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -4673,7 +4728,10 @@
 				  2 + sm->assoc_resp_ftie[1]);
 			res = 2 + sm->assoc_resp_ftie[1];
 		} else {
-			res = wpa_write_ftie(conf, conf->r0_key_holder,
+			int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
+			res = wpa_write_ftie(conf, use_sha384,
+					     conf->r0_key_holder,
 					     conf->r0_key_holder_len,
 					     NULL, NULL, pos,
 					     kde + kde_len - pos,
@@ -4698,7 +4756,7 @@
 		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
 		*pos++ = 5;
 		*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
-		WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+		WPA_PUT_LE32(pos, conf->r0_key_lifetime);
 		pos += 4;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
@@ -4722,7 +4780,10 @@
 	u8 rsc[WPA_KEY_RSC_LEN];
 	struct wpa_group *gsm = sm->group;
 	const u8 *kde;
-	u8 *kde_buf = NULL, *pos, *opos, hdr[2];
+	u8 *kde_buf = NULL, *pos, hdr[2];
+#ifdef CONFIG_IEEE80211W
+	u8 *opos;
+#endif /* CONFIG_IEEE80211W */
 	size_t kde_len;
 	u8 *gtk;
 
@@ -4745,12 +4806,16 @@
 		hdr[1] = 0;
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gsm->GTK_len);
+#ifdef CONFIG_IEEE80211W
 		opos = pos;
 		pos = ieee80211w_kde_add(sm, pos);
-		if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) {
-			opos += 2; /* skip keyid */
+		if (pos - opos >=
+		    2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
+			/* skip KDE header and keyid */
+			opos += 2 + RSN_SELECTOR_LEN + 2;
 			os_memset(opos, 0, 6); /* clear PN */
 		}
+#endif /* CONFIG_IEEE80211W */
 		kde_len = pos - kde;
 	} else {
 		kde = gtk;
@@ -4773,4 +4838,13 @@
 	return 0;
 }
 
+
+int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
+{
+	if (!wpa_auth)
+		return -1;
+	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+	return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 22f33dd..fad5536 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -14,6 +14,8 @@
 #include "common/wpa_common.h"
 #include "common/ieee802_11_defs.h"
 
+struct vlan_description;
+
 #define MAX_OWN_IE_OVERRIDE 256
 
 #ifdef _MSC_VER
@@ -77,6 +79,14 @@
 #define FT_RRB_PMK_R1        10 /* PMK_LEN */
 
 #define FT_RRB_PAIRWISE      11 /* le16 */
+#define FT_RRB_EXPIRES_IN    12 /* le16 seconds */
+
+#define FT_RRB_VLAN_UNTAGGED 13 /* le16 */
+#define FT_RRB_VLAN_TAGGED   14 /* n times le16 */
+
+#define FT_RRB_IDENTITY      15
+#define FT_RRB_RADIUS_CUI    16
+#define FT_RRB_SESSION_TIMEOUT  17 /* le32 seconds */
 
 struct ft_rrb_tlv {
 	le16 type;
@@ -92,6 +102,8 @@
 
 /* session TLVs:
  *   required: PMK_R1, PMK_R1_NAME, PAIRWISE
+ *   optional: VLAN_UNTAGGED, VLAN_TAGGED, EXPIRES_IN, IDENTITY, RADIUS_CUI,
+ *		 SESSION_TIMEOUT
  *
  * pull frame TLVs:
  *   auth:
@@ -177,6 +189,7 @@
 #ifdef CONFIG_IEEE80211W
 	enum mfp_options ieee80211w;
 	int group_mgmt_cipher;
+	int sae_require_mfp;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R_AP
 	u8 ssid[SSID_MAX_LEN];
@@ -185,11 +198,12 @@
 	u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
 	size_t r0_key_holder_len;
 	u8 r1_key_holder[FT_R1KH_ID_LEN];
-	u32 r0_key_lifetime;
+	u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
 	int rkh_pos_timeout;
 	int rkh_neg_timeout;
 	int rkh_pull_timeout; /* ms */
 	int rkh_pull_retries;
+	int r1_max_key_lifetime;
 	u32 reassociation_deadline;
 	struct ft_remote_r0kh **r0kh_list;
 	struct ft_remote_r1kh **r1kh_list;
@@ -253,6 +267,20 @@
 			size_t data_len);
 #ifdef CONFIG_IEEE80211R_AP
 	struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+	int (*set_vlan)(void *ctx, const u8 *sta_addr,
+			struct vlan_description *vlan);
+	int (*get_vlan)(void *ctx, const u8 *sta_addr,
+			struct vlan_description *vlan);
+	int (*set_identity)(void *ctx, const u8 *sta_addr,
+			    const u8 *identity, size_t identity_len);
+	size_t (*get_identity)(void *ctx, const u8 *sta_addr, const u8 **buf);
+	int (*set_radius_cui)(void *ctx, const u8 *sta_addr,
+			      const u8 *radius_cui, size_t radius_cui_len);
+	size_t (*get_radius_cui)(void *ctx, const u8 *sta_addr, const u8 **buf);
+	void (*set_session_timeout)(void *ctx, const u8 *sta_addr,
+				    int session_timeout);
+	int (*get_session_timeout)(void *ctx, const u8 *sta_addr);
+
 	int (*send_ft_action)(void *ctx, const u8 *dst,
 			      const u8 *data, size_t data_len);
 	int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
@@ -331,6 +359,7 @@
 			       struct eapol_state_machine *eapol);
 int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
 			   const u8 *pmk, const u8 *pmkid);
+void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
 int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
 			int session_timeout, int akmp);
@@ -420,7 +449,8 @@
 int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
 				  size_t ies_len);
 
-int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, u8 *buf, size_t len);
+int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
+		       u8 *buf, size_t len);
 void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
 				   u8 *fils_anonce, u8 *fils_snonce,
 				   u8 *fils_kek, size_t *fils_kek_len);
@@ -437,5 +467,6 @@
 int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
 			     void (*cb)(void *ctx1, void *ctx2),
 			     void *ctx1, void *ctx2);
+int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
 
 #endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 153752d..e8d46ab 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -16,6 +16,7 @@
 #include "crypto/aes.h"
 #include "crypto/aes_siv.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/sha384.h"
 #include "crypto/random.h"
 #include "ap_config.h"
 #include "ieee802_11.h"
@@ -192,6 +193,98 @@
 }
 
 
+static int cmp_int(const void *a, const void *b)
+{
+	int x, y;
+
+	x = *((int *) a);
+	y = *((int *) b);
+	return x - y;
+}
+
+
+static int wpa_ft_rrb_get_tlv_vlan(const u8 *plain, const size_t plain_len,
+				   struct vlan_description *vlan)
+{
+	struct ft_rrb_tlv *f;
+	size_t left;
+	size_t len;
+	int taggedidx;
+	int vlan_id;
+	int type;
+
+	left = plain_len;
+	taggedidx = 0;
+	os_memset(vlan, 0, sizeof(*vlan));
+
+	while (left >= sizeof(*f)) {
+		f = (struct ft_rrb_tlv *) plain;
+
+		left -= sizeof(*f);
+		plain += sizeof(*f);
+
+		len = le_to_host16(f->len);
+		type = le_to_host16(f->type);
+
+		if (left < len) {
+			wpa_printf(MSG_DEBUG, "FT: RRB message truncated");
+			return -1;
+		}
+
+		if (type != FT_RRB_VLAN_UNTAGGED && type != FT_RRB_VLAN_TAGGED)
+			goto skip;
+
+		if (type == FT_RRB_VLAN_UNTAGGED && len != sizeof(le16)) {
+			wpa_printf(MSG_DEBUG,
+				   "FT: RRB VLAN_UNTAGGED invalid length");
+			return -1;
+		}
+
+		if (type == FT_RRB_VLAN_TAGGED && len % sizeof(le16) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "FT: RRB VLAN_TAGGED invalid length");
+			return -1;
+		}
+
+		while (len >= sizeof(le16)) {
+			vlan_id = WPA_GET_LE16(plain);
+			plain += sizeof(le16);
+			left -= sizeof(le16);
+			len -= sizeof(le16);
+
+			if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) {
+				wpa_printf(MSG_DEBUG,
+					   "FT: RRB VLAN ID invalid %d",
+					   vlan_id);
+				continue;
+			}
+
+			if (type == FT_RRB_VLAN_UNTAGGED)
+				vlan->untagged = vlan_id;
+
+			if (type == FT_RRB_VLAN_TAGGED &&
+			    taggedidx < MAX_NUM_TAGGED_VLAN) {
+				vlan->tagged[taggedidx] = vlan_id;
+				taggedidx++;
+			} else if (type == FT_RRB_VLAN_TAGGED) {
+				wpa_printf(MSG_DEBUG, "FT: RRB too many VLANs");
+			}
+		}
+
+	skip:
+		left -= len;
+		plain += len;
+	}
+
+	if (taggedidx)
+		qsort(vlan->tagged, taggedidx, sizeof(int), cmp_int);
+
+	vlan->notempty = vlan->untagged || vlan->tagged[0];
+
+	return 0;
+}
+
+
 static size_t wpa_ft_tlv_len(const struct tlv_list *tlvs)
 {
 	size_t tlv_len = 0;
@@ -233,6 +326,8 @@
 
 		if (tlv_len + tlvs[i].len > (size_t) (endpos - start))
 			return tlv_len;
+		if (tlvs[i].len == 0)
+			continue;
 		tlv_len += tlvs[i].len;
 		os_memcpy(pos, tlvs[i].data, tlvs[i].len);
 		pos = start + tlv_len;
@@ -242,8 +337,84 @@
 }
 
 
+static size_t wpa_ft_vlan_len(const struct vlan_description *vlan)
+{
+	size_t tlv_len = 0;
+	int i;
+
+	if (!vlan || !vlan->notempty)
+		return 0;
+
+	if (vlan->untagged) {
+		tlv_len += sizeof(struct ft_rrb_tlv);
+		tlv_len += sizeof(le16);
+	}
+	if (vlan->tagged[0])
+		tlv_len += sizeof(struct ft_rrb_tlv);
+	for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++)
+		tlv_len += sizeof(le16);
+
+	return tlv_len;
+}
+
+
+static size_t wpa_ft_vlan_lin(const struct vlan_description *vlan,
+			      u8 *start, u8 *endpos)
+{
+	size_t tlv_len;
+	int i, len;
+	struct ft_rrb_tlv *hdr;
+	u8 *pos = start;
+
+	if (!vlan || !vlan->notempty)
+		return 0;
+
+	tlv_len = 0;
+	if (vlan->untagged) {
+		tlv_len += sizeof(*hdr);
+		if (start + tlv_len > endpos)
+			return tlv_len;
+		hdr = (struct ft_rrb_tlv *) pos;
+		hdr->type = host_to_le16(FT_RRB_VLAN_UNTAGGED);
+		hdr->len = host_to_le16(sizeof(le16));
+		pos = start + tlv_len;
+
+		tlv_len += sizeof(le16);
+		if (start + tlv_len > endpos)
+			return tlv_len;
+		WPA_PUT_LE16(pos, vlan->untagged);
+		pos = start + tlv_len;
+	}
+
+	if (!vlan->tagged[0])
+		return tlv_len;
+
+	tlv_len += sizeof(*hdr);
+	if (start + tlv_len > endpos)
+		return tlv_len;
+	hdr = (struct ft_rrb_tlv *) pos;
+	hdr->type = host_to_le16(FT_RRB_VLAN_TAGGED);
+	len = 0; /* len is computed below */
+	pos = start + tlv_len;
+
+	for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++) {
+		tlv_len += sizeof(le16);
+		if (start + tlv_len > endpos)
+			break;
+		len += sizeof(le16);
+		WPA_PUT_LE16(pos, vlan->tagged[i]);
+		pos = start + tlv_len;
+	}
+
+	hdr->len = host_to_le16(len);
+
+	return tlv_len;
+}
+
+
 static int wpa_ft_rrb_lin(const struct tlv_list *tlvs1,
 			  const struct tlv_list *tlvs2,
+			  const struct vlan_description *vlan,
 			  u8 **plain, size_t *plain_len)
 {
 	u8 *pos, *endpos;
@@ -251,6 +422,7 @@
 
 	tlv_len = wpa_ft_tlv_len(tlvs1);
 	tlv_len += wpa_ft_tlv_len(tlvs2);
+	tlv_len += wpa_ft_vlan_len(vlan);
 
 	*plain_len = tlv_len;
 	*plain = os_zalloc(tlv_len);
@@ -263,6 +435,7 @@
 	endpos = *plain + tlv_len;
 	pos += wpa_ft_tlv_lin(tlvs1, pos, endpos);
 	pos += wpa_ft_tlv_lin(tlvs2, pos, endpos);
+	pos += wpa_ft_vlan_lin(vlan, pos, endpos);
 
 	/* sanity check */
 	if (pos != endpos) {
@@ -324,6 +497,7 @@
 			    const struct tlv_list *tlvs_enc0,
 			    const struct tlv_list *tlvs_enc1,
 			    const struct tlv_list *tlvs_auth,
+			    const struct vlan_description *vlan,
 			    const u8 *src_addr, u8 type,
 			    u8 **packet, size_t *packet_len)
 {
@@ -331,10 +505,11 @@
 	size_t plain_len = 0, auth_len = 0;
 	int ret = -1;
 
-	if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, &plain, &plain_len) < 0)
+	*packet = NULL;
+	if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0)
 		goto out;
 
-	if (wpa_ft_rrb_lin(tlvs_auth, NULL, &auth, &auth_len) < 0)
+	if (wpa_ft_rrb_lin(tlvs_auth, NULL, NULL, &auth, &auth_len) < 0)
 		goto out;
 
 	*packet_len = sizeof(u16) + auth_len + plain_len;
@@ -456,6 +631,89 @@
 }
 
 
+static int wpa_ft_set_vlan(struct wpa_authenticator *wpa_auth,
+			   const u8 *sta_addr, struct vlan_description *vlan)
+{
+	if (!wpa_auth->cb->set_vlan)
+		return -1;
+	return wpa_auth->cb->set_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
+}
+
+
+static int wpa_ft_get_vlan(struct wpa_authenticator *wpa_auth,
+			   const u8 *sta_addr, struct vlan_description *vlan)
+{
+	if (!wpa_auth->cb->get_vlan)
+		return -1;
+	return wpa_auth->cb->get_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
+}
+
+
+static int
+wpa_ft_set_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+		    const u8 *identity, size_t identity_len)
+{
+	if (!wpa_auth->cb->set_identity)
+		return -1;
+	return wpa_auth->cb->set_identity(wpa_auth->cb_ctx, sta_addr, identity,
+					  identity_len);
+}
+
+
+static size_t
+wpa_ft_get_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+		    const u8 **buf)
+{
+	*buf = NULL;
+	if (!wpa_auth->cb->get_identity)
+		return 0;
+	return wpa_auth->cb->get_identity(wpa_auth->cb_ctx, sta_addr, buf);
+}
+
+
+static int
+wpa_ft_set_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+		      const u8 *radius_cui, size_t radius_cui_len)
+{
+	if (!wpa_auth->cb->set_radius_cui)
+		return -1;
+	return wpa_auth->cb->set_radius_cui(wpa_auth->cb_ctx, sta_addr,
+					    radius_cui, radius_cui_len);
+}
+
+
+static size_t
+wpa_ft_get_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+		      const u8 **buf)
+{
+	*buf = NULL;
+	if (!wpa_auth->cb->get_radius_cui)
+		return 0;
+	return wpa_auth->cb->get_radius_cui(wpa_auth->cb_ctx, sta_addr, buf);
+}
+
+
+static void
+wpa_ft_set_session_timeout(struct wpa_authenticator *wpa_auth,
+			    const u8 *sta_addr, int session_timeout)
+{
+	if (!wpa_auth->cb->set_session_timeout)
+		return;
+	wpa_auth->cb->set_session_timeout(wpa_auth->cb_ctx, sta_addr,
+					  session_timeout);
+}
+
+
+static int
+wpa_ft_get_session_timeout(struct wpa_authenticator *wpa_auth,
+			    const u8 *sta_addr)
+{
+	if (!wpa_auth->cb->get_session_timeout)
+		return 0;
+	return wpa_auth->cb->get_session_timeout(wpa_auth->cb_ctx, sta_addr);
+}
+
+
 static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
 			    const u8 *sta_addr,
 			    u8 *tspec_ie, size_t tspec_ielen)
@@ -489,30 +747,44 @@
 }
 
 
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
-		   size_t r0kh_id_len,
+int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
+		   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)
 {
 	u8 *pos = buf, *ielen;
-	struct rsn_ftie *hdr;
+	size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
+		sizeof(struct rsn_ftie);
 
-	if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
+	if (len < 2 + hdrlen + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
 	    subelem_len)
 		return -1;
 
 	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
 	ielen = pos++;
 
-	hdr = (struct rsn_ftie *) pos;
-	os_memset(hdr, 0, sizeof(*hdr));
-	pos += sizeof(*hdr);
-	WPA_PUT_LE16(hdr->mic_control, 0);
-	if (anonce)
-		os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
-	if (snonce)
-		os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+	if (use_sha384) {
+		struct rsn_ftie_sha384 *hdr = (struct rsn_ftie_sha384 *) pos;
+
+		os_memset(hdr, 0, sizeof(*hdr));
+		pos += sizeof(*hdr);
+		WPA_PUT_LE16(hdr->mic_control, 0);
+		if (anonce)
+			os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+		if (snonce)
+			os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+	} else {
+		struct rsn_ftie *hdr = (struct rsn_ftie *) pos;
+
+		os_memset(hdr, 0, sizeof(*hdr));
+		pos += sizeof(*hdr);
+		WPA_PUT_LE16(hdr->mic_control, 0);
+		if (anonce)
+			os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+		if (snonce)
+			os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+	}
 
 	/* Optional Parameters */
 	*pos++ = FTIE_SUBELEM_R1KH_ID;
@@ -656,7 +928,7 @@
 
 	seq_req_auth[0].data = item->nonce;
 
-	if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_req_auth,
+	if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_req_auth, NULL,
 			     wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
 			     &packet, &packet_len) < 0) {
 		item = NULL; /* some other seq resp might still accept this */
@@ -834,34 +1106,136 @@
 
 
 struct wpa_ft_pmk_r0_sa {
-	struct wpa_ft_pmk_r0_sa *next;
-	u8 pmk_r0[PMK_LEN];
+	struct dl_list list;
+	u8 pmk_r0[PMK_LEN_MAX];
+	size_t pmk_r0_len;
 	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
 	u8 spa[ETH_ALEN];
 	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
-	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+	struct vlan_description *vlan;
+	os_time_t expiration; /* 0 for no expiration */
+	u8 *identity;
+	size_t identity_len;
+	u8 *radius_cui;
+	size_t radius_cui_len;
+	os_time_t session_timeout; /* 0 for no expiration */
+	/* TODO: radius_class, EAP type */
 	int pmk_r1_pushed;
 };
 
 struct wpa_ft_pmk_r1_sa {
-	struct wpa_ft_pmk_r1_sa *next;
-	u8 pmk_r1[PMK_LEN];
+	struct dl_list list;
+	u8 pmk_r1[PMK_LEN_MAX];
+	size_t pmk_r1_len;
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	u8 spa[ETH_ALEN];
 	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
-	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+	struct vlan_description *vlan;
+	u8 *identity;
+	size_t identity_len;
+	u8 *radius_cui;
+	size_t radius_cui_len;
+	os_time_t session_timeout; /* 0 for no expiration */
+	/* TODO: radius_class, EAP type */
 };
 
 struct wpa_ft_pmk_cache {
-	struct wpa_ft_pmk_r0_sa *pmk_r0;
-	struct wpa_ft_pmk_r1_sa *pmk_r1;
+	struct dl_list pmk_r0; /* struct wpa_ft_pmk_r0_sa */
+	struct dl_list pmk_r1; /* struct wpa_ft_pmk_r1_sa */
 };
 
+
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx);
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx);
+
+
+static void wpa_ft_free_pmk_r0(struct wpa_ft_pmk_r0_sa *r0)
+{
+	if (!r0)
+		return;
+
+	dl_list_del(&r0->list);
+	eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+
+	os_memset(r0->pmk_r0, 0, PMK_LEN_MAX);
+	os_free(r0->vlan);
+	os_free(r0->identity);
+	os_free(r0->radius_cui);
+	os_free(r0);
+}
+
+
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_ft_pmk_r0_sa *r0 = eloop_ctx;
+	struct os_reltime now;
+	int expires_in;
+	int session_timeout;
+
+	os_get_reltime(&now);
+
+	if (!r0)
+		return;
+
+	expires_in = r0->expiration - now.sec;
+	session_timeout = r0->session_timeout - now.sec;
+	/* conditions to remove from cache:
+	 * a) r0->expiration is set and hit
+	 * -or-
+	 * b) r0->session_timeout is set and hit
+	 */
+	if ((!r0->expiration || expires_in > 0) &&
+	    (!r0->session_timeout || session_timeout > 0)) {
+		wpa_printf(MSG_ERROR,
+			   "FT: %s() called for non-expired entry %p",
+			   __func__, r0);
+		eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+		if (r0->expiration && expires_in > 0)
+			eloop_register_timeout(expires_in + 1, 0,
+					       wpa_ft_expire_pmk_r0, r0, NULL);
+		if (r0->session_timeout && session_timeout > 0)
+			eloop_register_timeout(session_timeout + 1, 0,
+					       wpa_ft_expire_pmk_r0, r0, NULL);
+		return;
+	}
+
+	wpa_ft_free_pmk_r0(r0);
+}
+
+
+static void wpa_ft_free_pmk_r1(struct wpa_ft_pmk_r1_sa *r1)
+{
+	if (!r1)
+		return;
+
+	dl_list_del(&r1->list);
+	eloop_cancel_timeout(wpa_ft_expire_pmk_r1, r1, NULL);
+
+	os_memset(r1->pmk_r1, 0, PMK_LEN_MAX);
+	os_free(r1->vlan);
+	os_free(r1->identity);
+	os_free(r1->radius_cui);
+	os_free(r1);
+}
+
+
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_ft_pmk_r1_sa *r1 = eloop_ctx;
+
+	wpa_ft_free_pmk_r1(r1);
+}
+
+
 struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
 {
 	struct wpa_ft_pmk_cache *cache;
 
 	cache = os_zalloc(sizeof(*cache));
+	if (cache) {
+		dl_list_init(&cache->pmk_r0);
+		dl_list_init(&cache->pmk_r1);
+	}
 
 	return cache;
 }
@@ -872,46 +1246,77 @@
 	struct wpa_ft_pmk_r0_sa *r0, *r0prev;
 	struct wpa_ft_pmk_r1_sa *r1, *r1prev;
 
-	r0 = cache->pmk_r0;
-	while (r0) {
-		r0prev = r0;
-		r0 = r0->next;
-		os_memset(r0prev->pmk_r0, 0, PMK_LEN);
-		os_free(r0prev);
-	}
+	dl_list_for_each_safe(r0, r0prev, &cache->pmk_r0,
+			      struct wpa_ft_pmk_r0_sa, list)
+		wpa_ft_free_pmk_r0(r0);
 
-	r1 = cache->pmk_r1;
-	while (r1) {
-		r1prev = r1;
-		r1 = r1->next;
-		os_memset(r1prev->pmk_r1, 0, PMK_LEN);
-		os_free(r1prev);
-	}
+	dl_list_for_each_safe(r1, r1prev, &cache->pmk_r1,
+			      struct wpa_ft_pmk_r1_sa, list)
+		wpa_ft_free_pmk_r1(r1);
 
 	os_free(cache);
 }
 
 
-int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
-			const u8 *spa, const u8 *pmk_r0,
-			const u8 *pmk_r0_name, int pairwise)
+static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r0,
+			       size_t pmk_r0_len,
+			       const u8 *pmk_r0_name, int pairwise,
+			       const struct vlan_description *vlan,
+			       int expires_in, int session_timeout,
+			       const u8 *identity, size_t identity_len,
+			       const u8 *radius_cui, size_t radius_cui_len)
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r0_sa *r0;
+	struct os_reltime now;
 
-	/* TODO: add expiration and limit on number of entries in cache */
+	/* TODO: add limit on number of entries in cache */
+	os_get_reltime(&now);
 
 	r0 = os_zalloc(sizeof(*r0));
 	if (r0 == NULL)
 		return -1;
 
-	os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
+	os_memcpy(r0->pmk_r0, pmk_r0, pmk_r0_len);
+	r0->pmk_r0_len = pmk_r0_len;
 	os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
 	os_memcpy(r0->spa, spa, ETH_ALEN);
 	r0->pairwise = pairwise;
+	if (expires_in > 0)
+		r0->expiration = now.sec + expires_in;
+	if (vlan && vlan->notempty) {
+		r0->vlan = os_zalloc(sizeof(*vlan));
+		if (!r0->vlan) {
+			bin_clear_free(r0, sizeof(*r0));
+			return -1;
+		}
+		*r0->vlan = *vlan;
+	}
+	if (identity) {
+		r0->identity = os_malloc(identity_len);
+		if (r0->identity) {
+			os_memcpy(r0->identity, identity, identity_len);
+			r0->identity_len = identity_len;
+		}
+	}
+	if (radius_cui) {
+		r0->radius_cui = os_malloc(radius_cui_len);
+		if (r0->radius_cui) {
+			os_memcpy(r0->radius_cui, radius_cui, radius_cui_len);
+			r0->radius_cui_len = radius_cui_len;
+		}
+	}
+	if (session_timeout > 0)
+		r0->session_timeout = now.sec + session_timeout;
 
-	r0->next = cache->pmk_r0;
-	cache->pmk_r0 = r0;
+	dl_list_add(&cache->pmk_r0, &r0->list);
+	if (expires_in > 0)
+		eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r0,
+				       r0, NULL);
+	if (session_timeout > 0)
+		eloop_register_timeout(session_timeout + 1, 0,
+				       wpa_ft_expire_pmk_r0, r0, NULL);
 
 	return 0;
 }
@@ -923,17 +1328,16 @@
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r0_sa *r0;
+	struct os_reltime now;
 
-	r0 = cache->pmk_r0;
-	while (r0) {
+	os_get_reltime(&now);
+	dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
 		if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
 		    os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
 				    WPA_PMK_NAME_LEN) == 0) {
 			*r0_out = r0;
 			return 0;
 		}
-
-		r0 = r0->next;
 	}
 
 	*r0_out = NULL;
@@ -943,24 +1347,66 @@
 
 static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
 			       const u8 *spa, const u8 *pmk_r1,
-			       const u8 *pmk_r1_name, int pairwise)
+			       size_t pmk_r1_len,
+			       const u8 *pmk_r1_name, int pairwise,
+			       const struct vlan_description *vlan,
+			       int expires_in, int session_timeout,
+			       const u8 *identity, size_t identity_len,
+			       const u8 *radius_cui, size_t radius_cui_len)
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	int max_expires_in = wpa_auth->conf.r1_max_key_lifetime;
 	struct wpa_ft_pmk_r1_sa *r1;
+	struct os_reltime now;
 
-	/* TODO: add expiration and limit on number of entries in cache */
+	/* TODO: limit on number of entries in cache */
+	os_get_reltime(&now);
+
+	if (max_expires_in && (max_expires_in < expires_in || expires_in == 0))
+		expires_in = max_expires_in;
 
 	r1 = os_zalloc(sizeof(*r1));
 	if (r1 == NULL)
 		return -1;
 
-	os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
+	os_memcpy(r1->pmk_r1, pmk_r1, pmk_r1_len);
+	r1->pmk_r1_len = pmk_r1_len;
 	os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
 	os_memcpy(r1->spa, spa, ETH_ALEN);
 	r1->pairwise = pairwise;
+	if (vlan && vlan->notempty) {
+		r1->vlan = os_zalloc(sizeof(*vlan));
+		if (!r1->vlan) {
+			bin_clear_free(r1, sizeof(*r1));
+			return -1;
+		}
+		*r1->vlan = *vlan;
+	}
+	if (identity) {
+		r1->identity = os_malloc(identity_len);
+		if (r1->identity) {
+			os_memcpy(r1->identity, identity, identity_len);
+			r1->identity_len = identity_len;
+		}
+	}
+	if (radius_cui) {
+		r1->radius_cui = os_malloc(radius_cui_len);
+		if (r1->radius_cui) {
+			os_memcpy(r1->radius_cui, radius_cui, radius_cui_len);
+			r1->radius_cui_len = radius_cui_len;
+		}
+	}
+	if (session_timeout > 0)
+		r1->session_timeout = now.sec + session_timeout;
 
-	r1->next = cache->pmk_r1;
-	cache->pmk_r1 = r1;
+	dl_list_add(&cache->pmk_r1, &r1->list);
+
+	if (expires_in > 0)
+		eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r1,
+				       r1, NULL);
+	if (session_timeout > 0)
+		eloop_register_timeout(session_timeout + 1, 0,
+				       wpa_ft_expire_pmk_r1, r1, NULL);
 
 	return 0;
 }
@@ -968,23 +1414,47 @@
 
 static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
 			       const u8 *spa, const u8 *pmk_r1_name,
-			       u8 *pmk_r1, int *pairwise)
+			       u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+			       struct vlan_description *vlan,
+			       const u8 **identity, size_t *identity_len,
+			       const u8 **radius_cui, size_t *radius_cui_len,
+			       int *session_timeout)
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r1_sa *r1;
+	struct os_reltime now;
 
-	r1 = cache->pmk_r1;
-	while (r1) {
+	os_get_reltime(&now);
+
+	dl_list_for_each(r1, &cache->pmk_r1, struct wpa_ft_pmk_r1_sa, list) {
 		if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
 		    os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
 				    WPA_PMK_NAME_LEN) == 0) {
-			os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
+			os_memcpy(pmk_r1, r1->pmk_r1, r1->pmk_r1_len);
+			*pmk_r1_len = r1->pmk_r1_len;
 			if (pairwise)
 				*pairwise = r1->pairwise;
+			if (vlan && r1->vlan)
+				*vlan = *r1->vlan;
+			if (vlan && !r1->vlan)
+				os_memset(vlan, 0, sizeof(*vlan));
+			if (identity && identity_len) {
+				*identity = r1->identity;
+				*identity_len = r1->identity_len;
+			}
+			if (radius_cui && radius_cui_len) {
+				*radius_cui = r1->radius_cui;
+				*radius_cui_len = r1->radius_cui_len;
+			}
+			if (session_timeout && r1->session_timeout > now.sec)
+				*session_timeout = r1->session_timeout -
+					now.sec;
+			else if (session_timeout && r1->session_timeout)
+				*session_timeout = 1;
+			else
+				*session_timeout = 0;
 			return 0;
 		}
-
-		r1 = r1->next;
 	}
 
 	return -1;
@@ -1459,6 +1929,11 @@
 			    sm->r0kh_id, sm->r0kh_id_len);
 		return -1;
 	}
+	if (os_memcmp(r0kh->addr, sm->wpa_auth->addr, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: R0KH-ID points to self - no matching key available");
+		return -1;
+	}
 
 	key = r0kh->key;
 	key_len = sizeof(r0kh->key);
@@ -1486,7 +1961,7 @@
 		return -1;
 	}
 
-	if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth,
+	if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth, NULL,
 			     sm->wpa_auth->addr, FT_PACKET_R0KH_R1KH_PULL,
 			     &packet, &packet_len) < 0)
 		return -1;
@@ -1512,11 +1987,43 @@
 }
 
 
+int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm,
+			  const u8 *pmk_r0, const u8 *pmk_r0_name)
+{
+	int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+	struct vlan_description vlan;
+	const u8 *identity, *radius_cui;
+	size_t identity_len, radius_cui_len;
+	int session_timeout;
+	size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
+		SHA384_MAC_LEN : PMK_LEN;
+
+	if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
+			   MAC2STR(sm->addr));
+		return -1;
+	}
+
+	identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
+	radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
+					       &radius_cui);
+	session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
+
+	return wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
+				   pmk_r0_name, sm->pairwise, &vlan, expires_in,
+				   session_timeout, identity, identity_len,
+				   radius_cui, radius_cui_len);
+}
+
+
 int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
 			   struct wpa_ptk *ptk)
 {
-	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
-	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+	size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
+		SHA384_MAC_LEN : PMK_LEN;
+	size_t pmk_r1_len = pmk_r0_len;
+	u8 pmk_r1[PMK_LEN_MAX];
 	u8 ptk_name[WPA_PMK_NAME_LEN];
 	const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
 	const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
@@ -1525,6 +2032,11 @@
 	const u8 *ssid = sm->wpa_auth->conf.ssid;
 	size_t ssid_len = sm->wpa_auth->conf.ssid_len;
 	int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
+	int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+	struct vlan_description vlan;
+	const u8 *identity, *radius_cui;
+	size_t identity_len, radius_cui_len;
+	int session_timeout;
 
 	if (sm->xxkey_len == 0) {
 		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
@@ -1532,28 +2044,45 @@
 		return -1;
 	}
 
+	if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
+			   MAC2STR(sm->addr));
+		return -1;
+	}
+
+	identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
+	radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
+					       &radius_cui);
+	session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
+
 	if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
 			      r0kh, r0kh_len, sm->addr,
-			      pmk_r0, pmk_r0_name) < 0)
+			      pmk_r0, pmk_r0_name,
+			      wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
 		return -1;
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
 	if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
-		wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
-				    sm->pairwise);
+		wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
+				    pmk_r0_name,
+				    sm->pairwise, &vlan, expires_in,
+				    session_timeout, identity, identity_len,
+				    radius_cui, radius_cui_len);
 
-	if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+	if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
 			      pmk_r1, sm->pmk_r1_name) < 0)
 		return -1;
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
 		    WPA_PMK_NAME_LEN);
 	if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
-		wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1,
-				    sm->pmk_r1_name, sm->pairwise);
+		wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
+				    sm->pmk_r1_name, sm->pairwise, &vlan,
+				    expires_in, session_timeout, identity,
+				    identity_len, radius_cui, radius_cui_len);
 
-	return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
-				 sm->wpa_auth->addr, sm->pmk_r1_name,
+	return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
+				 sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
 				 ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
 }
 
@@ -1575,6 +2104,16 @@
 	const u8 *key;
 	size_t key_len;
 	u8 keybuf[32];
+	const u8 *kek;
+	size_t kek_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;
+	}
 
 	key_len = gsm->GTK_len;
 	if (key_len > sizeof(keybuf))
@@ -1613,8 +2152,10 @@
 	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
 	subelem[4] = gsm->GTK_len;
 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
-	if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
-		     subelem + 13)) {
+	if (aes_wrap(kek, kek_len, key_len / 8, key, subelem + 13)) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: GTK subelem encryption failed: kek_len=%d",
+			   (int) kek_len);
 		os_free(subelem);
 		return NULL;
 	}
@@ -1630,10 +2171,23 @@
 	u8 *subelem, *pos;
 	struct wpa_group *gsm = sm->group;
 	size_t subelem_len;
+	const u8 *kek;
+	size_t kek_len;
+	size_t igtk_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;
+	}
+
+	igtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
 
 	/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
 	 * Key[16+8] */
-	subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
+	subelem_len = 1 + 1 + 2 + 6 + 1 + igtk_len + 8;
 	subelem = os_zalloc(subelem_len);
 	if (subelem == NULL)
 		return NULL;
@@ -1645,9 +2199,12 @@
 	pos += 2;
 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
 	pos += 6;
-	*pos++ = WPA_IGTK_LEN;
-	if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
+	*pos++ = igtk_len;
+	if (aes_wrap(kek, kek_len, igtk_len / 8,
 		     gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: IGTK subelem encryption failed: kek_len=%d",
+			   (int) kek_len);
 		os_free(subelem);
 		return NULL;
 	}
@@ -1794,17 +2351,21 @@
 				 const u8 *req_ies, size_t req_ies_len)
 {
 	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;
 	int res;
 	struct wpa_auth_config *conf;
-	struct rsn_ftie *_ftie;
 	struct wpa_ft_ies parse;
 	u8 *ric_start;
 	u8 *anonce, *snonce;
+	const u8 *kck;
+	size_t kck_len;
+	int use_sha384;
 
 	if (sm == NULL)
 		return pos;
 
+	use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
 	conf = &sm->wpa_auth->conf;
 
 	if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
@@ -1819,7 +2380,7 @@
 		 */
 		res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
 		if (res < 0)
-			return pos;
+			return NULL;
 		rsnie = pos;
 		rsnie_len = res;
 		pos += res;
@@ -1828,7 +2389,7 @@
 	/* Mobility Domain Information */
 	res = wpa_write_mdie(conf, pos, end - pos);
 	if (res < 0)
-		return pos;
+		return NULL;
 	mdie = pos;
 	mdie_len = res;
 	pos += res;
@@ -1836,6 +2397,11 @@
 	/* Fast BSS Transition Information */
 	if (auth_alg == WLAN_AUTH_FT) {
 		subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+		if (!subelem) {
+			wpa_printf(MSG_DEBUG,
+				   "FT: Failed to add GTK subelement");
+			return NULL;
+		}
 		r0kh_id = sm->r0kh_id;
 		r0kh_id_len = sm->r0kh_id_len;
 		anonce = sm->ANonce;
@@ -1847,14 +2413,16 @@
 			u8 *nbuf;
 			igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
 			if (igtk == NULL) {
+				wpa_printf(MSG_DEBUG,
+					   "FT: Failed to add IGTK subelement");
 				os_free(subelem);
-				return pos;
+				return NULL;
 			}
 			nbuf = os_realloc(subelem, subelem_len + igtk_len);
 			if (nbuf == NULL) {
 				os_free(subelem);
 				os_free(igtk);
-				return pos;
+				return NULL;
 			}
 			subelem = nbuf;
 			os_memcpy(subelem + subelem_len, igtk, igtk_len);
@@ -1868,44 +2436,66 @@
 		anonce = NULL;
 		snonce = NULL;
 	}
-	res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
-			     end - pos, subelem, subelem_len);
+	res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
+			     anonce, snonce, pos, end - pos,
+			     subelem, subelem_len);
 	os_free(subelem);
 	if (res < 0)
-		return pos;
+		return NULL;
 	ftie = pos;
 	ftie_len = res;
 	pos += res;
 
-	_ftie = (struct rsn_ftie *) (ftie + 2);
+	if (use_sha384) {
+		struct rsn_ftie_sha384 *_ftie =
+			(struct rsn_ftie_sha384 *) (ftie + 2);
+
+		fte_mic = _ftie->mic;
+		elem_count = &_ftie->mic_control[1];
+	} else {
+		struct rsn_ftie *_ftie = (struct rsn_ftie *) (ftie + 2);
+
+		fte_mic = _ftie->mic;
+		elem_count = &_ftie->mic_control[1];
+	}
 	if (auth_alg == WLAN_AUTH_FT)
-		_ftie->mic_control[1] = 3; /* Information element count */
+		*elem_count = 3; /* Information element count */
 
 	ric_start = pos;
-	if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
+	if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, use_sha384) == 0
+	    && parse.ric) {
 		pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
 					 parse.ric_len);
 		if (auth_alg == WLAN_AUTH_FT)
-			_ftie->mic_control[1] +=
+			*elem_count +=
 				ieee802_11_ie_count(ric_start,
 						    pos - ric_start);
 	}
 	if (ric_start == pos)
 		ric_start = NULL;
 
+	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+		kck = sm->PTK.kck2;
+		kck_len = sm->PTK.kck2_len;
+	} else {
+		kck = sm->PTK.kck;
+		kck_len = sm->PTK.kck_len;
+	}
 	if (auth_alg == WLAN_AUTH_FT &&
-	    wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
-		       sm->wpa_auth->addr, 6,
+	    wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 6,
 		       mdie, mdie_len, ftie, ftie_len,
 		       rsnie, rsnie_len,
 		       ric_start, ric_start ? pos - ric_start : 0,
-		       _ftie->mic) < 0)
+		       fte_mic) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+		return NULL;
+	}
 
 	os_free(sm->assoc_resp_ftie);
 	sm->assoc_resp_ftie = os_malloc(ftie_len);
-	if (sm->assoc_resp_ftie)
-		os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+	if (!sm->assoc_resp_ftie)
+		return NULL;
+	os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
 
 	return pos;
 }
@@ -1964,7 +2554,12 @@
 /* Derive PMK-R1 from PSK, check all available PSK */
 static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm,
 			     const u8 *req_pmk_r1_name,
-			     u8 *out_pmk_r1, int *out_pairwise)
+			     u8 *out_pmk_r1, int *out_pairwise,
+			     struct vlan_description *out_vlan,
+			     const u8 **out_identity, size_t *out_identity_len,
+			     const u8 **out_radius_cui,
+			     size_t *out_radius_cui_len,
+			     int *out_session_timeout)
 {
 	const u8 *pmk = NULL;
 	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
@@ -1988,9 +2583,9 @@
 
 		if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
 				      r0kh_len, sm->addr,
-				      pmk_r0, pmk_r0_name) < 0 ||
-		    wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
-				      pmk_r1, pmk_r1_name) < 0 ||
+				      pmk_r0, pmk_r0_name, 0) < 0 ||
+		    wpa_derive_pmk_r1(pmk_r0, PMK_LEN, pmk_r0_name, r1kh,
+				      sm->addr, pmk_r1, pmk_r1_name) < 0 ||
 		    os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
 				    WPA_PMK_NAME_LEN) != 0)
 			continue;
@@ -2001,6 +2596,28 @@
 		os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN);
 		if (out_pairwise)
 			*out_pairwise = pairwise;
+		if (out_vlan &&
+		    wpa_ft_get_vlan(sm->wpa_auth, sm->addr, out_vlan) < 0) {
+			wpa_printf(MSG_DEBUG, "FT: vlan not available for STA "
+				   MACSTR, MAC2STR(sm->addr));
+			return -1;
+		}
+
+		if (out_identity && out_identity_len) {
+			*out_identity_len = wpa_ft_get_identity(
+				sm->wpa_auth, sm->addr, out_identity);
+		}
+
+		if (out_radius_cui && out_radius_cui_len) {
+			*out_radius_cui_len = wpa_ft_get_radius_cui(
+				sm->wpa_auth, sm->addr, out_radius_cui);
+		}
+
+		if (out_session_timeout) {
+			*out_session_timeout = wpa_ft_get_session_timeout(
+				sm->wpa_auth, sm->addr);
+		}
+
 		return 0;
 	}
 
@@ -2029,6 +2646,10 @@
 	}
 	if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
 	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
 #ifdef CONFIG_FILS
@@ -2050,20 +2671,99 @@
 }
 
 
+static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
+				      struct wpa_state_machine *sm,
+				      const u8 *r0kh_id, size_t r0kh_id_len,
+				      const u8 *req_pmk_r0_name,
+				      const u8 *req_pmk_r1_name,
+				      u8 *out_pmk_r1, int *out_pairwise,
+				      struct vlan_description *vlan,
+				      const u8 **identity, size_t *identity_len,
+				      const u8 **radius_cui,
+				      size_t *radius_cui_len,
+				      int *out_session_timeout)
+{
+	struct wpa_auth_config *conf = &wpa_auth->conf;
+	const struct wpa_ft_pmk_r0_sa *r0;
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+	int expires_in = 0;
+	int session_timeout = 0;
+	struct os_reltime now;
+
+	if (conf->r0_key_holder_len != r0kh_id_len ||
+	    os_memcmp(conf->r0_key_holder, r0kh_id, conf->r0_key_holder_len) !=
+	    0)
+		return -1; /* not our R0KH-ID */
+
+	wpa_printf(MSG_DEBUG, "FT: STA R0KH-ID matching local configuration");
+	if (wpa_ft_fetch_pmk_r0(sm->wpa_auth, sm->addr, req_pmk_r0_name, &r0) <
+	    0)
+		return -1; /* no matching PMKR0Name in local cache */
+
+	wpa_printf(MSG_DEBUG, "FT: Requested PMKR0Name found in local cache");
+
+	if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_len, r0->pmk_r0_name,
+			      conf->r1_key_holder,
+			      sm->addr, out_pmk_r1, pmk_r1_name) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	os_get_reltime(&now);
+	if (r0->expiration)
+		expires_in = r0->expiration - now.sec;
+
+	if (r0->session_timeout)
+		session_timeout = r0->session_timeout - now.sec;
+
+	wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, r0->pmk_r0_len,
+			    pmk_r1_name,
+			    sm->pairwise, r0->vlan, expires_in, session_timeout,
+			    r0->identity, r0->identity_len,
+			    r0->radius_cui, r0->radius_cui_len);
+
+	*out_pairwise = sm->pairwise;
+	if (vlan) {
+		if (r0->vlan)
+			*vlan = *r0->vlan;
+		else
+			os_memset(vlan, 0, sizeof(*vlan));
+	}
+
+	if (identity && identity_len) {
+		*identity = r0->identity;
+		*identity_len = r0->identity_len;
+	}
+
+	if (radius_cui && radius_cui_len) {
+		*radius_cui = r0->radius_cui;
+		*radius_cui_len = r0->radius_cui_len;
+	}
+
+	*out_session_timeout = session_timeout;
+
+	return 0;
+}
+
+
 static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
 				   const u8 *ies, size_t ies_len,
 				   u8 **resp_ies, size_t *resp_ies_len)
 {
 	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
-	u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+	u8 pmk_r1[PMK_LEN_MAX], pmk_r1_name[WPA_PMK_NAME_LEN];
 	u8 ptk_name[WPA_PMK_NAME_LEN];
 	struct wpa_auth_config *conf;
 	struct wpa_ft_ies parse;
 	size_t buflen;
 	int ret;
 	u8 *pos, *end;
-	int pairwise;
+	int pairwise, session_timeout = 0;
+	struct vlan_description vlan;
+	const u8 *identity, *radius_cui;
+	size_t identity_len = 0, radius_cui_len = 0;
+	int use_sha384;
+	size_t pmk_r1_len;
 
 	*resp_ies = NULL;
 	*resp_ies_len = 0;
@@ -2074,10 +2774,12 @@
 	wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
 		    ies, ies_len);
 
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+	if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
+	use_sha384 = wpa_key_mgmt_sha384(parse.key_mgmt);
+	pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
 
 	mdie = (struct rsn_mdie *) parse.mdie;
 	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
@@ -2088,13 +2790,27 @@
 		return WLAN_STATUS_INVALID_MDIE;
 	}
 
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return WLAN_STATUS_INVALID_FTIE;
-	}
+	if (use_sha384) {
+		struct rsn_ftie_sha384 *ftie;
 
-	os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+		ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return WLAN_STATUS_INVALID_FTIE;
+		}
+
+		os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+	} else {
+		struct rsn_ftie *ftie;
+
+		ftie = (struct rsn_ftie *) parse.ftie;
+		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return WLAN_STATUS_INVALID_FTIE;
+		}
+
+		os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+	}
 
 	if (parse.r0kh_id == NULL) {
 		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
@@ -2118,17 +2834,38 @@
 		    parse.rsn_pmkid, WPA_PMK_NAME_LEN);
 	if (wpa_derive_pmk_r1_name(parse.rsn_pmkid,
 				   sm->wpa_auth->conf.r1_key_holder, sm->addr,
-				   pmk_r1_name) < 0)
+				   pmk_r1_name, use_sha384) < 0)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
 		    pmk_r1_name, WPA_PMK_NAME_LEN);
 
 	if (conf->ft_psk_generate_local &&
 	    wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
-		if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise) < 0)
+		if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise,
+				      &vlan, &identity, &identity_len,
+				      &radius_cui, &radius_cui_len,
+				      &session_timeout) < 0)
 			return WLAN_STATUS_INVALID_PMKID;
+		wpa_printf(MSG_DEBUG,
+			   "FT: Generated PMK-R1 for FT-PSK locally");
 	} else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name,
-				       pmk_r1, &pairwise) < 0) {
+				       pmk_r1, &pmk_r1_len, &pairwise, &vlan,
+				       &identity, &identity_len, &radius_cui,
+				       &radius_cui_len, &session_timeout) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: No PMK-R1 available in local cache for the requested PMKR1Name");
+		if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm,
+					       parse.r0kh_id, parse.r0kh_id_len,
+					       parse.rsn_pmkid,
+					       pmk_r1_name, pmk_r1, &pairwise,
+					       &vlan, &identity, &identity_len,
+					       &radius_cui, &radius_cui_len,
+					       &session_timeout) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "FT: Generated PMK-R1 based on local PMK-R0");
+			goto pmk_r1_derived;
+		}
+
 		if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
 			wpa_printf(MSG_DEBUG,
 				   "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH");
@@ -2136,9 +2873,12 @@
 		}
 
 		return -1; /* Status pending */
+	} else {
+		wpa_printf(MSG_DEBUG, "FT: Found PMKR1Name from local cache");
 	}
 
-	wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
+pmk_r1_derived:
+	wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len);
 	sm->pmk_r1_name_valid = 1;
 	os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
 
@@ -2153,8 +2893,8 @@
 	wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
 		    sm->ANonce, WPA_NONCE_LEN);
 
-	if (wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
-			      sm->wpa_auth->addr, pmk_r1_name,
+	if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
+			      sm->addr, sm->wpa_auth->addr, pmk_r1_name,
 			      &sm->PTK, ptk_name, sm->wpa_key_mgmt,
 			      pairwise) < 0)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2164,6 +2904,19 @@
 	sm->tk_already_set = FALSE;
 	wpa_ft_install_ptk(sm);
 
+	if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	if (wpa_ft_set_identity(sm->wpa_auth, sm->addr,
+				identity, identity_len) < 0 ||
+	    wpa_ft_set_radius_cui(sm->wpa_auth, sm->addr,
+				  radius_cui, radius_cui_len) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to configure identity/CUI");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	wpa_ft_set_session_timeout(sm->wpa_auth, sm->addr, session_timeout);
+
 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
 		2 + FT_R1KH_ID_LEN + 200;
 	*resp_ies = os_zalloc(buflen);
@@ -2183,7 +2936,7 @@
 		goto fail;
 	pos += ret;
 
-	ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
+	ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
 			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
 	if (ret < 0)
 		goto fail;
@@ -2247,17 +3000,23 @@
 {
 	struct wpa_ft_ies parse;
 	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
 	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
 	size_t mic_len = 16;
 	unsigned int count;
+	const u8 *kck;
+	size_t kck_len;
+	int use_sha384;
+	const u8 *anonce, *snonce, *fte_mic;
+	u8 fte_elem_count;
 
 	if (sm == NULL)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
+	use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
 	wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
 
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+	if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
@@ -2288,25 +3047,47 @@
 		return WLAN_STATUS_INVALID_MDIE;
 	}
 
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return WLAN_STATUS_INVALID_FTIE;
+	if (use_sha384) {
+		struct rsn_ftie_sha384 *ftie;
+
+		ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+		if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return WLAN_STATUS_INVALID_FTIE;
+		}
+
+		anonce = ftie->anonce;
+		snonce = ftie->snonce;
+		fte_elem_count = ftie->mic_control[1];
+		fte_mic = ftie->mic;
+	} else {
+		struct rsn_ftie *ftie;
+
+		ftie = (struct rsn_ftie *) parse.ftie;
+		if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return WLAN_STATUS_INVALID_FTIE;
+		}
+
+		anonce = ftie->anonce;
+		snonce = ftie->snonce;
+		fte_elem_count = ftie->mic_control[1];
+		fte_mic = ftie->mic;
 	}
 
-	if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
+	if (os_memcmp(snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
 		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
-			    ftie->snonce, WPA_NONCE_LEN);
+			    snonce, WPA_NONCE_LEN);
 		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
 			    sm->SNonce, WPA_NONCE_LEN);
 		return WLAN_STATUS_INVALID_FTIE;
 	}
 
-	if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
+	if (os_memcmp(anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
 		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
-			    ftie->anonce, WPA_NONCE_LEN);
+			    anonce, WPA_NONCE_LEN);
 		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
 			    sm->ANonce, WPA_NONCE_LEN);
 		return WLAN_STATUS_INVALID_FTIE;
@@ -2357,15 +3138,21 @@
 	count = 3;
 	if (parse.ric)
 		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
-	if (ftie->mic_control[1] != count) {
+	if (fte_elem_count != count) {
 		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
 			   "Control: received %u expected %u",
-			   ftie->mic_control[1], count);
+			   fte_elem_count, count);
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
 
-	if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
-		       sm->wpa_auth->addr, 5,
+	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+		kck = sm->PTK.kck2;
+		kck_len = sm->PTK.kck2_len;
+	} else {
+		kck = sm->PTK.kck;
+		kck_len = sm->PTK.kck_len;
+	}
+	if (wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 5,
 		       parse.mdie - 2, parse.mdie_len + 2,
 		       parse.ftie - 2, parse.ftie_len + 2,
 		       parse.rsn - 2, parse.rsn_len + 2,
@@ -2375,12 +3162,12 @@
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
 
-	if (os_memcmp_const(mic, ftie->mic, mic_len) != 0) {
+	if (os_memcmp_const(mic, fte_mic, mic_len) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
 		wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
 			   MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
 		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
-			    ftie->mic, mic_len);
+			    fte_mic, mic_len);
 		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
 		wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
 			    parse.mdie - 2, parse.mdie_len + 2);
@@ -2579,33 +3366,65 @@
 			       const u8 *src_addr, u8 type,
 			       u8 **packet, size_t *packet_len)
 {
-	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1[PMK_LEN_MAX];
+	size_t pmk_r1_len = pmk_r0->pmk_r0_len;
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	u8 f_pairwise[sizeof(le16)];
+	u8 f_expires_in[sizeof(le16)];
+	u8 f_session_timeout[sizeof(le32)];
+	int expires_in;
+	int session_timeout;
+	struct os_reltime now;
 	int ret;
 	struct tlv_list sess_tlv[] = {
-		{ .type = FT_RRB_PMK_R1, .len = sizeof(pmk_r1),
+		{ .type = FT_RRB_PMK_R1, .len = pmk_r1_len,
 		  .data = pmk_r1 },
 		{ .type = FT_RRB_PMK_R1_NAME, .len = sizeof(pmk_r1_name),
 		  .data = pmk_r1_name },
 		{ .type = FT_RRB_PAIRWISE, .len = sizeof(f_pairwise),
 		  .data = f_pairwise },
+		{ .type = FT_RRB_EXPIRES_IN, .len = sizeof(f_expires_in),
+		  .data = f_expires_in },
+		{ .type = FT_RRB_IDENTITY, .len = pmk_r0->identity_len,
+		  .data = pmk_r0->identity },
+		{ .type = FT_RRB_RADIUS_CUI, .len = pmk_r0->radius_cui_len,
+		  .data = pmk_r0->radius_cui },
+		{ .type = FT_RRB_SESSION_TIMEOUT,
+		  .len = sizeof(f_session_timeout),
+		  .data = f_session_timeout },
 		{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
 	};
 
-	if (!pmk_r0)
-		return wpa_ft_rrb_build(key, key_len, tlvs, NULL, tlv_auth,
-					src_addr, type, packet, packet_len);
-
-	if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh_id,
+	if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
+			      pmk_r0->pmk_r0_name, r1kh_id,
 			      s1kh_id, pmk_r1, pmk_r1_name) < 0)
 		return -1;
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
+			pmk_r1, pmk_r1_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
+		    pmk_r1_name, WPA_PMK_NAME_LEN);
 	WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
 
+	os_get_reltime(&now);
+	if (pmk_r0->expiration > now.sec)
+		expires_in = pmk_r0->expiration - now.sec;
+	else if (pmk_r0->expiration)
+		expires_in = 1;
+	else
+		expires_in = 0;
+	WPA_PUT_LE16(f_expires_in, expires_in);
+
+	if (pmk_r0->session_timeout > now.sec)
+		session_timeout = pmk_r0->session_timeout - now.sec;
+	else if (pmk_r0->session_timeout)
+		session_timeout = 1;
+	else
+		session_timeout = 0;
+	WPA_PUT_LE32(f_session_timeout, session_timeout);
+
 	ret = wpa_ft_rrb_build(key, key_len, tlvs, sess_tlv, tlv_auth,
-			       src_addr, type, packet, packet_len);
+			       pmk_r0->vlan, src_addr, type,
+			       packet, packet_len);
 
 	os_memset(pmk_r1, 0, sizeof(pmk_r1));
 
@@ -2736,13 +3555,18 @@
 	resp_auth[4].len = 0;
 	resp_auth[4].data = NULL;
 
-	if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0)
+	if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: No matching PMK-R0-Name found");
-
-	ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id, f_s1kh_id,
-				  resp_auth, wpa_auth->addr,
-				  FT_PACKET_R0KH_R1KH_RESP,
-				  &packet, &packet_len);
+		ret = wpa_ft_rrb_build(key, key_len, resp, NULL, resp_auth,
+				       NULL, wpa_auth->addr,
+				       FT_PACKET_R0KH_R1KH_RESP,
+				       &packet, &packet_len);
+	} else {
+		ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id,
+					  f_s1kh_id, resp_auth, wpa_auth->addr,
+					  FT_PACKET_R0KH_R1KH_RESP,
+					  &packet, &packet_len);
+	}
 
 	if (!ret)
 		wpa_ft_rrb_oui_send(wpa_auth, src_addr,
@@ -2780,10 +3604,20 @@
 	int seq_ret;
 	const u8 *f_r1kh_id, *f_s1kh_id, *f_r0kh_id;
 	const u8 *f_pmk_r1_name, *f_pairwise, *f_pmk_r1;
+	const u8 *f_expires_in;
 	size_t f_r1kh_id_len, f_s1kh_id_len, f_r0kh_id_len;
+	const u8 *f_identity, *f_radius_cui;
+	const u8 *f_session_timeout;
 	size_t f_pmk_r1_name_len, f_pairwise_len, f_pmk_r1_len;
+	size_t f_expires_in_len;
+	size_t f_identity_len, f_radius_cui_len;
+	size_t f_session_timeout_len;
 	int pairwise;
 	int ret = -1;
+	int expires_in;
+	int session_timeout;
+	struct vlan_description vlan;
+	size_t pmk_r1_len;
 
 	RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
 	wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
@@ -2862,13 +3696,58 @@
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
 		    f_pmk_r1_name, WPA_PMK_NAME_LEN);
 
-	RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, PMK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, PMK_LEN);
+	pmk_r1_len = PMK_LEN;
+	if (wpa_ft_rrb_get_tlv(plain, plain_len, FT_RRB_PMK_R1, &f_pmk_r1_len,
+			       &f_pmk_r1) == 0 &&
+	    (f_pmk_r1_len == PMK_LEN || f_pmk_r1_len == SHA384_MAC_LEN))
+		pmk_r1_len = f_pmk_r1_len;
+	RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, pmk_r1_len);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, pmk_r1_len);
 
 	pairwise = WPA_GET_LE16(f_pairwise);
 
-	if (wpa_ft_store_pmk_r1(wpa_auth, f_s1kh_id, f_pmk_r1, f_pmk_r1_name,
-				pairwise) < 0)
+	RRB_GET_OPTIONAL(FT_RRB_EXPIRES_IN, expires_in, msgtype,
+			 sizeof(le16));
+	if (f_expires_in)
+		expires_in = WPA_GET_LE16(f_expires_in);
+	else
+		expires_in = 0;
+
+	wpa_printf(MSG_DEBUG, "FT: PMK-R1 %s - expires_in=%d", msgtype,
+		   expires_in);
+
+	if (wpa_ft_rrb_get_tlv_vlan(plain, plain_len, &vlan) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Cannot parse vlan");
+		wpa_ft_rrb_dump(plain, plain_len);
+		goto out;
+	}
+
+	wpa_printf(MSG_DEBUG, "FT: vlan %d%s",
+		   le_to_host16(vlan.untagged), vlan.tagged[0] ? "+" : "");
+
+	RRB_GET_OPTIONAL(FT_RRB_IDENTITY, identity, msgtype, -1);
+	if (f_identity)
+		wpa_hexdump_ascii(MSG_DEBUG, "FT: Identity", f_identity,
+				  f_identity_len);
+
+	RRB_GET_OPTIONAL(FT_RRB_RADIUS_CUI, radius_cui, msgtype, -1);
+	if (f_radius_cui)
+		wpa_hexdump_ascii(MSG_DEBUG, "FT: CUI", f_radius_cui,
+				  f_radius_cui_len);
+
+	RRB_GET_OPTIONAL(FT_RRB_SESSION_TIMEOUT, session_timeout, msgtype,
+			 sizeof(le32));
+	if (f_session_timeout)
+		session_timeout = WPA_GET_LE32(f_session_timeout);
+	else
+		session_timeout = 0;
+	wpa_printf(MSG_DEBUG, "FT: session_timeout %d", session_timeout);
+
+	if (wpa_ft_store_pmk_r1(wpa_auth, f_s1kh_id, f_pmk_r1, pmk_r1_len,
+				f_pmk_r1_name,
+				pairwise, &vlan, expires_in, session_timeout,
+				f_identity, f_identity_len, f_radius_cui,
+				f_radius_cui_len) < 0)
 		goto out;
 
 	ret = 0;
@@ -3178,7 +4057,7 @@
 	seq_resp_auth[4].len = 0;
 	seq_resp_auth[4].data = NULL;
 
-	if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_resp_auth,
+	if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_resp_auth, NULL,
 			     wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_RESP,
 			     &packet, &packet_len) < 0)
 		goto out;
@@ -3527,7 +4406,8 @@
 
 void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
 {
-	struct wpa_ft_pmk_r0_sa *r0;
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r0_sa *r0, *r0found = NULL;
 	struct ft_remote_r1kh *r1kh;
 
 	if (!wpa_auth->conf.pmk_r1_push)
@@ -3535,13 +4415,14 @@
 	if (!wpa_auth->conf.r1kh_list)
 		return;
 
-	r0 = wpa_auth->ft_pmk_cache->pmk_r0;
-	while (r0) {
-		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
+	dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
+		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) {
+			r0found = r0;
 			break;
-		r0 = r0->next;
+		}
 	}
 
+	r0 = r0found;
 	if (r0 == NULL || r0->pmk_r1_pushed)
 		return;
 	r0->pmk_r1_pushed = 1;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 98133a0..8127403 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -59,6 +59,7 @@
 #ifdef CONFIG_IEEE80211W
 	wconf->ieee80211w = conf->ieee80211w;
 	wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
+	wconf->sae_require_mfp = conf->sae_require_mfp;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R_AP
 	wconf->ssid_len = conf->ssid.ssid_len;
@@ -75,6 +76,7 @@
 	}
 	os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
 	wconf->r0_key_lifetime = conf->r0_key_lifetime;
+	wconf->r1_max_key_lifetime = conf->r1_max_key_lifetime;
 	wconf->reassociation_deadline = conf->reassociation_deadline;
 	wconf->rkh_pos_timeout = conf->rkh_pos_timeout;
 	wconf->rkh_neg_timeout = conf->rkh_neg_timeout;
@@ -364,10 +366,10 @@
 			sta->last_tk_len = key_len;
 		}
 #ifdef CONFIG_IEEE80211W
-	} else if (alg == WPA_CIPHER_AES_128_CMAC ||
-		   alg == WPA_CIPHER_BIP_GMAC_128 ||
-		   alg == WPA_CIPHER_BIP_GMAC_256 ||
-		   alg == WPA_CIPHER_BIP_CMAC_256) {
+	} else if (alg == WPA_ALG_IGTK ||
+		   alg == WPA_ALG_BIP_GMAC_128 ||
+		   alg == WPA_ALG_BIP_GMAC_256 ||
+		   alg == WPA_ALG_BIP_CMAC_256) {
 		hapd->last_igtk_alg = alg;
 		hapd->last_igtk_key_idx = idx;
 		if (key)
@@ -834,6 +836,244 @@
 }
 
 
+static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
+				     struct vlan_description *vlan)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta || !sta->wpa_sm)
+		return -1;
+
+	if (vlan->notempty &&
+	    !hostapd_vlan_valid(hapd->conf->vlan, vlan)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "Invalid VLAN %d%s received from FT",
+			       vlan->untagged, vlan->tagged[0] ? "+" : "");
+		return -1;
+	}
+
+	if (ap_sta_set_vlan(hapd, sta, vlan) < 0)
+		return -1;
+	/* Configure wpa_group for GTK but ignore error due to driver not
+	 * knowing this STA. */
+	ap_sta_bind_vlan(hapd, sta);
+
+	if (sta->vlan_id)
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+
+	return 0;
+}
+
+
+static int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr,
+				     struct vlan_description *vlan)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta)
+		return -1;
+
+	if (sta->vlan_desc)
+		*vlan = *sta->vlan_desc;
+	else
+		os_memset(vlan, 0, sizeof(*vlan));
+
+	return 0;
+}
+
+
+static int
+hostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr,
+			      const u8 *identity, size_t identity_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta)
+		return -1;
+
+	os_free(sta->identity);
+	sta->identity = NULL;
+
+	if (sta->eapol_sm) {
+		os_free(sta->eapol_sm->identity);
+		sta->eapol_sm->identity = NULL;
+		sta->eapol_sm->identity_len = 0;
+	}
+
+	if (!identity_len)
+		return 0;
+
+	/* sta->identity is NULL terminated */
+	sta->identity = os_zalloc(identity_len + 1);
+	if (!sta->identity)
+		return -1;
+	os_memcpy(sta->identity, identity, identity_len);
+
+	if (sta->eapol_sm) {
+		sta->eapol_sm->identity = os_zalloc(identity_len);
+		if (!sta->eapol_sm->identity)
+			return -1;
+		os_memcpy(sta->eapol_sm->identity, identity, identity_len);
+		sta->eapol_sm->identity_len = identity_len;
+	}
+
+	return 0;
+}
+
+
+static size_t
+hostapd_wpa_auth_get_identity(void *ctx, const u8 *sta_addr, const u8 **buf)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	size_t len;
+	char *identity;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta)
+		return 0;
+
+	*buf = ieee802_1x_get_identity(sta->eapol_sm, &len);
+	if (*buf && len)
+		return len;
+
+	if (!sta->identity) {
+		*buf = NULL;
+		return 0;
+	}
+
+	identity = sta->identity;
+	len = os_strlen(identity);
+	*buf = (u8 *) identity;
+
+	return len;
+}
+
+
+static int
+hostapd_wpa_auth_set_radius_cui(void *ctx, const u8 *sta_addr,
+				const u8 *radius_cui, size_t radius_cui_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta)
+		return -1;
+
+	os_free(sta->radius_cui);
+	sta->radius_cui = NULL;
+
+	if (sta->eapol_sm) {
+		wpabuf_free(sta->eapol_sm->radius_cui);
+		sta->eapol_sm->radius_cui = NULL;
+	}
+
+	if (!radius_cui)
+		return 0;
+
+	/* sta->radius_cui is NULL terminated */
+	sta->radius_cui = os_zalloc(radius_cui_len + 1);
+	if (!sta->radius_cui)
+		return -1;
+	os_memcpy(sta->radius_cui, radius_cui, radius_cui_len);
+
+	if (sta->eapol_sm) {
+		sta->eapol_sm->radius_cui = wpabuf_alloc_copy(radius_cui,
+							      radius_cui_len);
+		if (!sta->eapol_sm->radius_cui)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static size_t
+hostapd_wpa_auth_get_radius_cui(void *ctx, const u8 *sta_addr, const u8 **buf)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	struct wpabuf *b;
+	size_t len;
+	char *radius_cui;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta)
+		return 0;
+
+	b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+	if (b) {
+		len = wpabuf_len(b);
+		*buf = wpabuf_head(b);
+		return len;
+	}
+
+	if (!sta->radius_cui) {
+		*buf = NULL;
+		return 0;
+	}
+
+	radius_cui = sta->radius_cui;
+	len = os_strlen(radius_cui);
+	*buf = (u8 *) radius_cui;
+
+	return len;
+}
+
+
+static void hostapd_wpa_auth_set_session_timeout(void *ctx, const u8 *sta_addr,
+						 int session_timeout)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta)
+		return;
+
+	if (session_timeout) {
+		os_get_reltime(&sta->session_timeout);
+		sta->session_timeout.sec += session_timeout;
+		sta->session_timeout_set = 1;
+		ap_sta_session_timeout(hapd, sta, session_timeout);
+	} else {
+		sta->session_timeout_set = 0;
+		ap_sta_no_session_timeout(hapd, sta);
+	}
+}
+
+
+static int hostapd_wpa_auth_get_session_timeout(void *ctx, const u8 *sta_addr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	struct os_reltime now, remaining;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (!sta || !sta->session_timeout_set)
+		return 0;
+
+	os_get_reltime(&now);
+	if (os_reltime_before(&sta->session_timeout, &now)) {
+		/* already expired, return >0 as timeout was set */
+		return 1;
+	}
+
+	os_reltime_sub(&sta->session_timeout, &now, &remaining);
+
+	return (remaining.sec > 0) ? remaining.sec : 1;
+}
+
+
 static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 				size_t len)
 {
@@ -953,6 +1193,14 @@
 		.send_ft_action = hostapd_wpa_auth_send_ft_action,
 		.add_sta = hostapd_wpa_auth_add_sta,
 		.add_tspec = hostapd_wpa_auth_add_tspec,
+		.set_vlan = hostapd_wpa_auth_set_vlan,
+		.get_vlan = hostapd_wpa_auth_get_vlan,
+		.set_identity = hostapd_wpa_auth_set_identity,
+		.get_identity = hostapd_wpa_auth_get_identity,
+		.set_radius_cui = hostapd_wpa_auth_set_radius_cui,
+		.get_radius_cui = hostapd_wpa_auth_get_radius_cui,
+		.set_session_timeout = hostapd_wpa_auth_set_session_timeout,
+		.get_session_timeout = hostapd_wpa_auth_get_session_timeout,
 #endif /* CONFIG_IEEE80211R_AP */
 	};
 	const u8 *wpa_ie;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index befa800..b1cea1b 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -58,6 +58,7 @@
 	u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
 	u8 PMK[PMK_LEN_MAX];
 	unsigned int pmk_len;
+	u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
 	struct wpa_ptk PTK;
 	Boolean PTK_valid;
 	Boolean pairwise_set;
@@ -90,6 +91,7 @@
 	unsigned int pmk_r1_name_valid:1;
 #endif /* CONFIG_IEEE80211R_AP */
 	unsigned int is_wnmsleep:1;
+	unsigned int pmkid_set:1;
 
 	u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
 	int req_replay_counter_used;
@@ -110,7 +112,8 @@
 	u32 dot11RSNAStatsTKIPRemoteMICFailures;
 
 #ifdef CONFIG_IEEE80211R_AP
-	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+	u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
+				* first 384 bits of MSK */
 	size_t xxkey_len;
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
 					   * Request */
@@ -274,8 +277,8 @@
 
 #ifdef CONFIG_IEEE80211R_AP
 int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
-		   size_t r0kh_id_len,
+int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
+		   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);
@@ -284,9 +287,8 @@
 struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
 void wpa_ft_install_ptk(struct wpa_state_machine *sm);
-int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
-			const u8 *spa, const u8 *pmk_r0,
-			const u8 *pmk_r0_name, int pairwise);
+int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
+			  const u8 *pmk_r0_name);
 #endif /* CONFIG_IEEE80211R_AP */
 
 #endif /* WPA_AUTH_I_H */
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 0196d00..253fe6e 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -170,6 +170,13 @@
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
+#ifdef CONFIG_SHA384
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_SHA384 */
 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
 		pos += RSN_SELECTOR_LEN;
@@ -248,6 +255,13 @@
 		num_suites++;
 	}
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_HS20 */
 
 #ifdef CONFIG_RSN_TESTING
 	if (rsn_testing) {
@@ -559,6 +573,10 @@
 			selector = RSN_AUTH_KEY_MGMT_FILS_SHA256;
 #endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R_AP
+#ifdef CONFIG_SHA384
+		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+			selector = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+#endif /* CONFIG_SHA384 */
 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
 			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
@@ -588,6 +606,10 @@
 		else if (data.key_mgmt & WPA_KEY_MGMT_DPP)
 			selector = RSN_AUTH_KEY_MGMT_DPP;
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+		else if (data.key_mgmt & WPA_KEY_MGMT_OSEN)
+			selector = RSN_AUTH_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
 		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
 
 		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
@@ -661,6 +683,10 @@
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
 #endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R_AP
+#ifdef CONFIG_SHA384
+	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
 	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
 	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
@@ -688,6 +714,10 @@
 	else if (key_mgmt & WPA_KEY_MGMT_DPP)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP;
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+	else if (key_mgmt & WPA_KEY_MGMT_OSEN)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
 	else
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
 
@@ -711,12 +741,6 @@
 			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
 		}
 
-		if (ciphers & WPA_CIPHER_TKIP) {
-			wpa_printf(MSG_DEBUG, "Management frame protection "
-				   "cannot use TKIP");
-			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
-		}
-
 		if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
 		{
 			wpa_printf(MSG_DEBUG, "Unsupported management group "
@@ -725,11 +749,28 @@
 		}
 	}
 
+#ifdef CONFIG_SAE
+	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL &&
+	    wpa_auth->conf.sae_require_mfp &&
+	    wpa_key_mgmt_sae(sm->wpa_key_mgmt) &&
+	    !(data.capabilities & WPA_CAPABILITY_MFPC)) {
+		wpa_printf(MSG_DEBUG,
+			   "Management frame protection required with SAE, but client did not enable it");
+		return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+	}
+#endif /* CONFIG_SAE */
+
 	if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
 	    !(data.capabilities & WPA_CAPABILITY_MFPC))
 		sm->mgmt_frame_prot = 0;
 	else
 		sm->mgmt_frame_prot = 1;
+
+	if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) {
+		    wpa_printf(MSG_DEBUG,
+			       "Management frame protection cannot use TKIP");
+		    return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+	}
 #endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_IEEE80211R_AP
@@ -817,6 +858,15 @@
 		os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
 	}
 
+#ifdef CONFIG_SAE
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
+	    !sm->pmksa) {
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				 "No PMKSA cache entry found for SAE");
+		return WPA_INVALID_PMKID;
+	}
+#endif /* CONFIG_SAE */
+
 #ifdef CONFIG_DPP
 	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && !sm->pmksa) {
 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -1018,6 +1068,19 @@
 				   const u8 *req_ies, size_t req_ies_len)
 {
 	int res;
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (conf->own_ie_override_len) {
+		if (max_len < conf->own_ie_override_len)
+			return NULL;
+		wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
+			    conf->own_ie_override, conf->own_ie_override_len);
+		os_memcpy(pos, conf->own_ie_override,
+			  conf->own_ie_override_len);
+		return pos + conf->own_ie_override_len;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len,
 			       sm->pmksa ? sm->pmksa->pmkid : NULL);
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 95b40da..5ec0199 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1064,7 +1064,9 @@
 		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
 			wps->auth_types |= WPS_AUTH_WPA2;
 
-		if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) {
+		if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+					  WPA_CIPHER_CCMP_256 |
+					  WPA_CIPHER_GCMP_256)) {
 			wps->encr_types |= WPS_ENCR_AES;
 			wps->encr_types_rsn |= WPS_ENCR_AES;
 		}
diff --git a/src/common/ctrl_iface_common.c b/src/common/ctrl_iface_common.c
index ebbe6ff..e26407d 100644
--- a/src/common/ctrl_iface_common.c
+++ b/src/common/ctrl_iface_common.c
@@ -113,17 +113,53 @@
 }
 
 
+static int ctrl_set_events(struct wpa_ctrl_dst *dst, const char *input)
+{
+	const char *value;
+	int val;
+
+	if (!input)
+		return 0;
+
+	value = os_strchr(input, '=');
+	if (!value)
+		return -1;
+	value++;
+	val = atoi(value);
+	if (val < 0 || val > 1)
+		return -1;
+
+	if (str_starts(input, "probe_rx_events=")) {
+		if (val)
+			dst->events |= WPA_EVENT_RX_PROBE_REQUEST;
+		else
+			dst->events &= ~WPA_EVENT_RX_PROBE_REQUEST;
+	}
+
+	return 0;
+}
+
+
 int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
-		      socklen_t fromlen)
+		      socklen_t fromlen, const char *input)
 {
 	struct wpa_ctrl_dst *dst;
 
+	/* Update event registration if already attached */
+	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+		if (!sockaddr_compare(from, fromlen,
+				      &dst->addr, dst->addrlen))
+			return ctrl_set_events(dst, input);
+	}
+
+	/* New attachment */
 	dst = os_zalloc(sizeof(*dst));
 	if (dst == NULL)
 		return -1;
 	os_memcpy(&dst->addr, from, fromlen);
 	dst->addrlen = fromlen;
 	dst->debug_level = MSG_INFO;
+	ctrl_set_events(dst, input);
 	dl_list_add(ctrl_dst, &dst->list);
 
 	sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
diff --git a/src/common/ctrl_iface_common.h b/src/common/ctrl_iface_common.h
index 0b6e3e7..85e258e 100644
--- a/src/common/ctrl_iface_common.h
+++ b/src/common/ctrl_iface_common.h
@@ -11,6 +11,9 @@
 
 #include "utils/list.h"
 
+/* Events enable bits (wpa_ctrl_dst::events) */
+#define WPA_EVENT_RX_PROBE_REQUEST BIT(0)
+
 /**
  * struct wpa_ctrl_dst - Data structure of control interface monitors
  *
@@ -23,13 +26,14 @@
 	socklen_t addrlen;
 	int debug_level;
 	int errors;
+	u32 events; /* WPA_EVENT_* bitmap */
 };
 
 void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
 		    socklen_t socklen);
 
 int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
-		       socklen_t fromlen);
+		       socklen_t fromlen, const char *input);
 int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
 		      socklen_t fromlen);
 int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
diff --git a/src/common/defs.h b/src/common/defs.h
index 1de099f..c968cd6 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Common definitions
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -57,11 +57,13 @@
 #define WPA_KEY_MGMT_FT_FILS_SHA384 BIT(21)
 #define WPA_KEY_MGMT_OWE BIT(22)
 #define WPA_KEY_MGMT_DPP BIT(23)
+#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
 	return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
 			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
 			 WPA_KEY_MGMT_CCKM |
 			 WPA_KEY_MGMT_OSEN |
 			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
@@ -86,6 +88,7 @@
 {
 	return !!(akm & (WPA_KEY_MGMT_FT_PSK |
 			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
 			 WPA_KEY_MGMT_FT_SAE |
 			 WPA_KEY_MGMT_FT_FILS_SHA256 |
 			 WPA_KEY_MGMT_FT_FILS_SHA384));
@@ -114,6 +117,8 @@
 {
 	return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
 			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			 WPA_KEY_MGMT_SAE |
+			 WPA_KEY_MGMT_FT_SAE |
 			 WPA_KEY_MGMT_OSEN |
 			 WPA_KEY_MGMT_IEEE8021X_SUITE_B |
 			 WPA_KEY_MGMT_FILS_SHA256 |
@@ -123,6 +128,7 @@
 static inline int wpa_key_mgmt_sha384(int akm)
 {
 	return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
+			 WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
 			 WPA_KEY_MGMT_FILS_SHA384 |
 			 WPA_KEY_MGMT_FT_FILS_SHA384));
 }
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 5107950..677f586 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -9,6 +9,8 @@
 #include "utils/includes.h"
 #include <openssl/opensslv.h>
 #include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
 
 #include "utils/common.h"
 #include "utils/base64.h"
@@ -22,10 +24,28 @@
 #include "crypto/aes_siv.h"
 #include "crypto/sha384.h"
 #include "crypto/sha512.h"
+#include "drivers/driver.h"
 #include "dpp.h"
 
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#ifdef CONFIG_TESTING_OPTIONS
+enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
+u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_ephemeral_key_override[600];
+size_t dpp_pkex_ephemeral_key_override_len = 0;
+u8 dpp_protocol_key_override[600];
+size_t dpp_protocol_key_override_len = 0;
+u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
+size_t dpp_nonce_override_len = 0;
+
+static int dpp_test_gen_invalid_key(struct wpabuf *msg,
+				    const struct dpp_curve_params *curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 /* Compatibility wrappers for older versions. */
 
 static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
@@ -83,10 +103,10 @@
 	0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
 };
 static const u8 pkex_resp_y_p256[32] = {
-	0x26, 0x04, 0x09, 0x45, 0x0a, 0x05, 0x20, 0xe7,
-	0xa7, 0x27, 0xc1, 0x36, 0x76, 0x85, 0xca, 0x3e,
-	0x42, 0x16, 0xf4, 0x89, 0x85, 0x34, 0x6e, 0xd5,
-	0x17, 0xde, 0xc0, 0xb8, 0xad, 0xfd, 0xb2, 0x98
+	0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
+	0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
+	0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
+	0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
 };
 
 /* NIST P-384 */
@@ -99,12 +119,12 @@
 	0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
 };
 static const u8 pkex_init_y_p384[48] = {
-	0x89, 0xd0, 0x97, 0x7b, 0x59, 0x4f, 0xa6, 0xd6,
-	0x7c, 0x5d, 0x93, 0x5b, 0x93, 0xc4, 0x07, 0xa9,
-	0x89, 0xee, 0xd5, 0xcd, 0x6f, 0x42, 0xf8, 0x38,
-	0xc8, 0xc6, 0x62, 0x24, 0x69, 0x0c, 0xd4, 0x48,
-	0xd8, 0x44, 0xd6, 0xc2, 0xe8, 0xcc, 0x62, 0x6b,
-	0x3c, 0x25, 0x53, 0xba, 0x4f, 0x71, 0xf8, 0xe7
+	0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
+	0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
+	0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
+	0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
+	0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
+	0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
 };
 static const u8 pkex_resp_x_p384[48] = {
 	0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
@@ -115,12 +135,12 @@
 	0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
 };
 static const u8 pkex_resp_y_p384[48] = {
-	0x54, 0x58, 0x20, 0xad, 0x55, 0x1d, 0xca, 0xf3,
-	0x1c, 0x8a, 0xcd, 0x19, 0x40, 0xf9, 0x37, 0x83,
-	0xc7, 0xd6, 0xb3, 0x13, 0x7d, 0x53, 0x28, 0x5c,
-	0xf6, 0x2d, 0xf1, 0xdd, 0xa5, 0x8b, 0xad, 0x5d,
-	0x81, 0xab, 0xb1, 0x00, 0x39, 0xd6, 0xcc, 0x9c,
-	0xea, 0x1e, 0x84, 0x1d, 0xbf, 0xe3, 0x35, 0xf9
+	0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
+	0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
+	0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
+	0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
+	0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
+	0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
 };
 
 /* NIST P-521 */
@@ -136,15 +156,15 @@
 	0x97, 0x76
 };
 static const u8 pkex_init_y_p521[66] = {
-	0x01, 0x4c, 0x71, 0xfd, 0x1b, 0xd5, 0x9c, 0xa6,
-	0xed, 0x39, 0xef, 0x45, 0xc5, 0x06, 0xfd, 0x66,
-	0xc0, 0xeb, 0x0f, 0xbf, 0x21, 0xa3, 0x36, 0x74,
-	0xfd, 0xaa, 0x05, 0x6e, 0x4e, 0x33, 0x95, 0x42,
-	0x1a, 0x9d, 0x3f, 0x3a, 0x1c, 0x5e, 0xa8, 0x60,
-	0xf7, 0xe5, 0x59, 0x1d, 0x07, 0xaa, 0x6f, 0x40,
-	0x0a, 0x59, 0x3c, 0x27, 0xad, 0xe0, 0x48, 0xfd,
-	0xd1, 0x83, 0x37, 0x4c, 0xdf, 0xe1, 0x86, 0x72,
-	0xfc, 0x57
+	0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
+	0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
+	0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
+	0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
+	0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
+	0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
+	0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
+	0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
+	0x03, 0xa8
 };
 static const u8 pkex_resp_x_p521[66] = {
 	0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
@@ -158,15 +178,15 @@
 	0x84, 0xb4
 };
 static const u8 pkex_resp_y_p521[66] = {
-	0x01, 0xb9, 0x9c, 0xc6, 0x41, 0x32, 0x5b, 0xd2,
-	0x35, 0xd8, 0x8b, 0x2b, 0xe4, 0x6e, 0xcc, 0xdf,
-	0x7c, 0x38, 0xc4, 0x5b, 0xf6, 0x74, 0x71, 0x5c,
-	0x77, 0x16, 0x8a, 0x80, 0xa9, 0x84, 0xc7, 0x7b,
-	0x9d, 0xfd, 0x83, 0x6f, 0xae, 0xf8, 0x24, 0x16,
-	0x2f, 0x21, 0x25, 0x65, 0xa2, 0x1a, 0x6b, 0x2d,
-	0x30, 0x62, 0xb3, 0xcc, 0x6e, 0x59, 0x3c, 0x7f,
-	0x58, 0x91, 0x81, 0x72, 0x07, 0x8c, 0x91, 0xac,
-	0x31, 0x1e
+	0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
+	0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
+	0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
+	0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
+	0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
+	0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
+	0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
+	0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
+	0xce, 0xe1
 };
 
 /* Brainpool P-256r1 */
@@ -177,10 +197,10 @@
 	0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
 };
 static const u8 pkex_init_y_bp_p256r1[32] = {
-	0x16, 0x30, 0x68, 0x32, 0x3b, 0xb0, 0x21, 0xee,
-	0xeb, 0xf7, 0xb6, 0x7c, 0xae, 0x52, 0x26, 0x42,
-	0x59, 0x28, 0x58, 0xb6, 0x14, 0x90, 0xed, 0x69,
-	0xd0, 0x67, 0xea, 0x25, 0x60, 0x0f, 0xa9, 0x6c
+	0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
+	0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
+	0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
+	0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
 };
 static const u8 pkex_resp_x_bp_p256r1[32] = {
 	0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
@@ -241,14 +261,14 @@
 	0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
 };
 static const u8 pkex_init_y_bp_p512r1[64] = {
-	0x5a, 0x28, 0x01, 0xbe, 0x96, 0x82, 0x4e, 0xf6,
-	0xfa, 0xed, 0x7d, 0xfd, 0x48, 0x8b, 0x48, 0x4e,
-	0xd1, 0x97, 0x87, 0xc4, 0x05, 0x5d, 0x15, 0x2a,
-	0xf4, 0x91, 0x4b, 0x75, 0x90, 0xd9, 0x34, 0x2c,
-	0x3c, 0x12, 0xf2, 0xf5, 0x25, 0x94, 0x24, 0x34,
-	0xa7, 0x6d, 0x66, 0xbc, 0x27, 0xa4, 0xa0, 0x8d,
-	0xd5, 0xe1, 0x54, 0xa3, 0x55, 0x26, 0xd4, 0x14,
-	0x17, 0x0f, 0xc1, 0xc7, 0x3d, 0x68, 0x7f, 0x5a
+	0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
+	0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
+	0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
+	0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
+	0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
+	0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
+	0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
+	0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
 };
 static const u8 pkex_resp_x_bp_p512r1[64] = {
 	0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
@@ -261,17 +281,50 @@
 	0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
 };
 static const u8 pkex_resp_y_bp_p512r1[64] = {
-	0x2a, 0xbe, 0x59, 0xe6, 0xc4, 0xb3, 0xd8, 0x09,
-	0x66, 0x89, 0x0a, 0x2d, 0x19, 0xf0, 0x9c, 0x9f,
-	0xb4, 0xab, 0x8f, 0x50, 0x68, 0x3c, 0x74, 0x64,
-	0x4e, 0x19, 0x55, 0x81, 0x9b, 0x48, 0x5c, 0xf4,
-	0x12, 0x8d, 0xb9, 0xd8, 0x02, 0x5b, 0xe1, 0x26,
-	0x7e, 0x19, 0x5c, 0xfd, 0x70, 0xf7, 0x4b, 0xdc,
-	0xb5, 0x5d, 0xc1, 0x7a, 0xe9, 0xd1, 0x05, 0x2e,
-	0xd1, 0xfd, 0x2f, 0xce, 0x63, 0x77, 0x48, 0x2c
+	0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
+	0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
+	0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
+	0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
+	0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
+	0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
+	0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
+	0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
 };
 
 
+static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
+				  const EC_POINT *point)
+{
+	BIGNUM *x, *y;
+	BN_CTX *ctx;
+	char *x_str = NULL, *y_str = NULL;
+
+	if (!wpa_debug_show_keys)
+		return;
+
+	ctx = BN_CTX_new();
+	x = BN_new();
+	y = BN_new();
+	if (!ctx || !x || !y ||
+	    EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
+		goto fail;
+
+	x_str = BN_bn2hex(x);
+	y_str = BN_bn2hex(y);
+	if (!x_str || !y_str)
+		goto fail;
+
+	wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
+
+fail:
+	OPENSSL_free(x_str);
+	OPENSSL_free(y_str);
+	BN_free(x);
+	BN_free(y);
+	BN_CTX_free(ctx);
+}
+
+
 static int dpp_hash_vector(const struct dpp_curve_params *curve,
 			   size_t num_elem, const u8 *addr[], const size_t *len,
 			   u8 *mac)
@@ -335,6 +388,20 @@
 }
 
 
+static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
+{
+	int num_bytes, offset;
+
+	num_bytes = BN_num_bytes(bn);
+	if ((size_t) num_bytes > len)
+		return -1;
+	offset = len - num_bytes;
+	os_memset(pos, 0, offset);
+	BN_bn2bin(bn, pos + offset);
+	return 0;
+}
+
+
 static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
 {
 	int len, res;
@@ -418,6 +485,7 @@
 		wpa_printf(MSG_ERROR, "DPP: Invalid point");
 		goto fail;
 	}
+	dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
 
 	eckey = EC_KEY_new();
 	if (!eckey ||
@@ -479,6 +547,12 @@
 }
 
 
+static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
+{
+	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
+}
+
+
 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
 			      size_t len)
 {
@@ -523,6 +597,7 @@
 int dpp_check_attrs(const u8 *buf, size_t len)
 {
 	const u8 *pos, *end;
+	int wrapped_data = 0;
 
 	pos = buf;
 	end = buf + len;
@@ -540,6 +615,13 @@
 				   "DPP: Truncated message - not enough room for the attribute - dropped");
 			return -1;
 		}
+		if (wrapped_data) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: An unexpected attribute included after the Wrapped Data attribute");
+			return -1;
+		}
+		if (id == DPP_ATTR_WRAPPED_DATA)
+			wrapped_data = 1;
 		pos += alen;
 	}
 
@@ -731,7 +813,7 @@
 	const unsigned char *pk;
 	int ppklen;
 	X509_ALGOR *pa;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 	ASN1_OBJECT *pa_oid;
 #else
 	const ASN1_OBJECT *pa_oid;
@@ -758,6 +840,7 @@
 	if (sha256_vector(1, (const u8 **) &data, &data_len,
 			  bi->pubkey_hash) < 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+		os_free(data);
 		return -1;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
@@ -939,6 +1022,8 @@
 	int res;
 	unsigned char *der = NULL;
 	int der_len;
+	const EC_GROUP *group;
+	const EC_POINT *point;
 
 	out = BIO_new(BIO_s_mem());
 	if (!out)
@@ -961,6 +1046,11 @@
 	if (!eckey)
 		return;
 
+	group = EC_KEY_get0_group(eckey);
+	point = EC_KEY_get0_public_key(eckey);
+	if (group && point)
+		dpp_debug_print_point(title, group, point);
+
 	der_len = i2d_ECPrivateKey(eckey, &der);
 	if (der_len > 0)
 		wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
@@ -979,13 +1069,8 @@
 
 static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
 {
-#ifdef OPENSSL_IS_BORINGSSL
 	EVP_PKEY_CTX *kctx = NULL;
-	const EC_GROUP *group;
 	EC_KEY *ec_params;
-#else
-	EVP_PKEY_CTX *pctx, *kctx = NULL;
-#endif
 	EVP_PKEY *params = NULL, *key = NULL;
 	int nid;
 
@@ -996,10 +1081,9 @@
 		wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
 		return NULL;
 	}
-#ifdef OPENSSL_IS_BORINGSSL
-	group = EC_GROUP_new_by_curve_name(nid);
-	ec_params = EC_KEY_new();
-	if (!ec_params || EC_KEY_set_group(ec_params, group) != 1) {
+
+	ec_params = EC_KEY_new_by_curve_name(nid);
+	if (!ec_params) {
 		wpa_printf(MSG_ERROR,
 			   "DPP: Failed to generate EC_KEY parameters");
 		goto fail;
@@ -1011,20 +1095,6 @@
 			   "DPP: Failed to generate EVP_PKEY parameters");
 		goto fail;
 	}
-#else
-	pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
-	if (!pctx ||
-	    EVP_PKEY_paramgen_init(pctx) != 1 ||
-	    EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1 ||
-	    EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE) != 1 ||
-	    EVP_PKEY_paramgen(pctx, &params) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to generate EVP_PKEY parameters");
-		EVP_PKEY_CTX_free(pctx);
-		goto fail;
-	}
-	EVP_PKEY_CTX_free(pctx);
-#endif
 
 	kctx = EVP_PKEY_CTX_new(params, NULL);
 	if (!kctx ||
@@ -1121,34 +1191,111 @@
 }
 
 
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+typedef struct {
+	/* AlgorithmIdentifier ecPublicKey with optional parameters present
+	 * as an OID identifying the curve */
+	X509_ALGOR *alg;
+	/* Compressed format public key per ANSI X9.63 */
+	ASN1_BIT_STRING *pub_key;
+} DPP_BOOTSTRAPPING_KEY;
+
+ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
+	ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
+	ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
+
+IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
+
+
+static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
 {
 	unsigned char *der = NULL;
 	int der_len;
 	EC_KEY *eckey;
-	int res;
+	struct wpabuf *ret = NULL;
 	size_t len;
+	const EC_GROUP *group;
+	const EC_POINT *point;
+	BN_CTX *ctx;
+	DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
+	int nid;
 
-	/* Need to get the compressed form of the public key through EC_KEY, so
-	 * cannot use the simpler i2d_PUBKEY() here. */
-	eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey);
-	if (!eckey)
-		return -1;
-	EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
-	der_len = i2d_EC_PUBKEY(eckey, &der);
-	EC_KEY_free(eckey);
+	ctx = BN_CTX_new();
+	eckey = EVP_PKEY_get1_EC_KEY(key);
+	if (!ctx || !eckey)
+		goto fail;
+
+	group = EC_KEY_get0_group(eckey);
+	point = EC_KEY_get0_public_key(eckey);
+	if (!group || !point)
+		goto fail;
+	dpp_debug_print_point("DPP: bootstrap public key", group, point);
+	nid = EC_GROUP_get_curve_name(group);
+
+	bootstrap = DPP_BOOTSTRAPPING_KEY_new();
+	if (!bootstrap ||
+	    X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
+			    V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
+		goto fail;
+
+	len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+				 NULL, 0, ctx);
+	if (len == 0)
+		goto fail;
+
+	der = OPENSSL_malloc(len);
+	if (!der)
+		goto fail;
+	len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+				 der, len, ctx);
+
+	OPENSSL_free(bootstrap->pub_key->data);
+	bootstrap->pub_key->data = der;
+	der = NULL;
+	bootstrap->pub_key->length = len;
+	/* No unused bits */
+	bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+	bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+	der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
 	if (der_len <= 0) {
 		wpa_printf(MSG_ERROR,
 			   "DDP: Failed to build DER encoded public key");
-		OPENSSL_free(der);
-		return -1;
+		goto fail;
 	}
 
-	len = der_len;
-	res = sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash);
+	ret = wpabuf_alloc_copy(der, der_len);
+fail:
+	DPP_BOOTSTRAPPING_KEY_free(bootstrap);
 	OPENSSL_free(der);
+	EC_KEY_free(eckey);
+	BN_CTX_free(ctx);
+	return ret;
+}
+
+
+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);
 	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;
 }
 
@@ -1159,9 +1306,9 @@
 	unsigned char *base64 = NULL;
 	char *pos, *end;
 	size_t len;
-	unsigned char *der = NULL;
-	int der_len;
-	EC_KEY *eckey;
+	struct wpabuf *der = NULL;
+	const u8 *addr[1];
+	int res;
 
 	if (!curve) {
 		bi->curve = &dpp_curves[0];
@@ -1181,28 +1328,24 @@
 		goto fail;
 	bi->own = 1;
 
-	/* Need to get the compressed form of the public key through EC_KEY, so
-	 * cannot use the simpler i2d_PUBKEY() here. */
-	eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey);
-	if (!eckey)
+	der = dpp_bootstrap_key_der(bi->pubkey);
+	if (!der)
 		goto fail;
-	EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
-	der_len = i2d_EC_PUBKEY(eckey, &der);
-	EC_KEY_free(eckey);
-	if (der_len <= 0) {
-		wpa_printf(MSG_ERROR,
-			   "DDP: Failed to build DER encoded public key");
-		goto fail;
-	}
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
+			der);
 
-	len = der_len;
-	if (sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash) < 0) {
+	addr[0] = wpabuf_head(der);
+	len = wpabuf_len(der);
+	res = sha256_vector(1, addr, &len, bi->pubkey_hash);
+	if (res < 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(der, der_len, &len);
-	OPENSSL_free(der);
+	base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
+	wpabuf_free(der);
 	der = NULL;
 	if (!base64)
 		goto fail;
@@ -1217,7 +1360,7 @@
 	return (char *) base64;
 fail:
 	os_free(base64);
-	OPENSSL_free(der);
+	wpabuf_free(der);
 	return NULL;
 }
 
@@ -1291,6 +1434,12 @@
 	size_t len[3];
 	size_t num_elem = 0;
 
+	if (!auth->Mx_len || !auth->Nx_len) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Mx/Nx not available - cannot derive ke");
+		return -1;
+	}
+
 	/* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
 
 	/* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
@@ -1298,12 +1447,17 @@
 	os_memcpy(nonces, auth->i_nonce, nonce_len);
 	os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
 	addr[num_elem] = auth->Mx;
-	len[num_elem] = auth->secret_len;
+	len[num_elem] = auth->Mx_len;
 	num_elem++;
 	addr[num_elem] = auth->Nx;
-	len[num_elem] = auth->secret_len;
+	len[num_elem] = auth->Nx_len;
 	num_elem++;
 	if (auth->peer_bi && auth->own_bi) {
+		if (!auth->Lx_len) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Lx not available - cannot derive ke");
+			return -1;
+		}
 		addr[num_elem] = auth->Lx;
 		len[num_elem] = auth->secret_len;
 		num_elem++;
@@ -1327,16 +1481,48 @@
 }
 
 
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
-					  struct dpp_bootstrap_info *peer_bi,
-					  struct dpp_bootstrap_info *own_bi,
-					  int configurator)
+static void dpp_build_attr_status(struct wpabuf *msg,
+				  enum dpp_status_error status)
 {
-	struct dpp_authentication *auth;
-	size_t nonce_len;
-	EVP_PKEY_CTX *ctx = NULL;
-	size_t secret_len;
-	struct wpabuf *msg, *pi = NULL;
+	wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
+	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
+	wpabuf_put_le16(msg, 1);
+	wpabuf_put_u8(msg, status);
+}
+
+
+static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
+						const u8 *hash)
+{
+	if (hash) {
+		wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
+		wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
+		wpabuf_put_le16(msg, SHA256_MAC_LEN);
+		wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+	}
+}
+
+
+static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
+						const u8 *hash)
+{
+	if (hash) {
+		wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
+		wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
+		wpabuf_put_le16(msg, SHA256_MAC_LEN);
+		wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+	}
+}
+
+
+static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
+					  const struct wpabuf *pi,
+					  size_t nonce_len,
+					  const u8 *r_pubkey_hash,
+					  const u8 *i_pubkey_hash,
+					  unsigned int neg_freq)
+{
+	struct wpabuf *msg;
 	u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
 	u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
 	u8 *pos;
@@ -1344,24 +1530,593 @@
 	size_t len[2], siv_len, attr_len;
 	u8 *attr_start, *attr_end;
 
+	/* Build DPP Authentication Request frame attributes */
+	attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
+		4 + sizeof(wrapped_data);
+	if (neg_freq > 0)
+		attr_len += 4 + 2;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
+		attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
+	if (!msg)
+		return NULL;
+
+	attr_start = wpabuf_put(msg, 0);
+
+	/* Responder Bootstrapping Key Hash */
+	dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+	/* Initiator Bootstrapping Key Hash */
+	dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+	/* Initiator Protocol Key */
+	if (pi) {
+		wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
+		wpabuf_put_le16(msg, wpabuf_len(pi));
+		wpabuf_put_buf(msg, pi);
+	}
+
+	/* Channel */
+	if (neg_freq > 0) {
+		u8 op_class, channel;
+
+		if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
+						  &channel) ==
+		    NUM_HOSTAPD_MODES) {
+			wpa_printf(MSG_INFO,
+				   "DPP: Unsupported negotiation frequency request: %d",
+				   neg_freq);
+			wpabuf_free(msg);
+			return NULL;
+		}
+		wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
+		wpabuf_put_le16(msg, 2);
+		wpabuf_put_u8(msg, op_class);
+		wpabuf_put_u8(msg, channel);
+	}
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+		goto skip_wrapped_data;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* Wrapped data ({I-nonce, I-capabilities}k1) */
+	pos = clear;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+		goto skip_i_nonce;
+	}
+	if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
+		WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+		pos += 2;
+		WPA_PUT_LE16(pos, nonce_len - 1);
+		pos += 2;
+		os_memcpy(pos, auth->i_nonce, nonce_len - 1);
+		pos += nonce_len - 1;
+		goto skip_i_nonce;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* I-nonce */
+	WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+	pos += 2;
+	WPA_PUT_LE16(pos, nonce_len);
+	pos += 2;
+	os_memcpy(pos, auth->i_nonce, nonce_len);
+	pos += nonce_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_nonce:
+	if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
+		goto skip_i_capab;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* I-capabilities */
+	WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
+	pos += 2;
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	auth->i_capab = auth->allowed_roles;
+	*pos++ = auth->i_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
+		pos[-1] = 0;
+	}
+skip_i_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	attr_end = wpabuf_put(msg, 0);
+
+	/* OUI, OUI type, Crypto Suite, DPP frame type */
+	addr[0] = wpabuf_head_u8(msg) + 2;
+	len[0] = 3 + 1 + 1 + 1;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+	/* Attributes before Wrapped Data */
+	addr[1] = attr_start;
+	len[1] = attr_end - attr_start;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+	siv_len = pos - clear;
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+	if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
+			    2, addr, len, wrapped_data) < 0) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+	siv_len += AES_BLOCK_SIZE;
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+		    wrapped_data, siv_len);
+
+	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+	wpabuf_put_le16(msg, siv_len);
+	wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+		dpp_build_attr_status(msg, DPP_STATUS_OK);
+	}
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	wpa_hexdump_buf(MSG_DEBUG,
+			"DPP: Authentication Request frame attributes", msg);
+
+	return msg;
+}
+
+
+static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
+					   enum dpp_status_error status,
+					   const struct wpabuf *pr,
+					   size_t nonce_len,
+					   const u8 *r_pubkey_hash,
+					   const u8 *i_pubkey_hash,
+					   const u8 *r_nonce, const u8 *i_nonce,
+					   const u8 *wrapped_r_auth,
+					   size_t wrapped_r_auth_len,
+					   const u8 *siv_key)
+{
+	struct wpabuf *msg;
+#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
+		4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
+	u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
+	u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
+	const u8 *addr[2];
+	size_t len[2], siv_len, attr_len;
+	u8 *attr_start, *attr_end, *pos;
+
+	auth->waiting_auth_conf = 1;
+	auth->auth_resp_tries = 0;
+
+	/* Build DPP Authentication Response frame attributes */
+	attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
+		4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
+		attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+	if (!msg)
+		return NULL;
+
+	attr_start = wpabuf_put(msg, 0);
+
+	/* DPP Status */
+	if (status != 255)
+		dpp_build_attr_status(msg, status);
+
+	/* Responder Bootstrapping Key Hash */
+	dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+	/* Initiator Bootstrapping Key Hash (mutual authentication) */
+	dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+	/* Responder Protocol Key */
+	if (pr) {
+		wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
+		wpabuf_put_le16(msg, wpabuf_len(pr));
+		wpabuf_put_buf(msg, pr);
+	}
+
+	attr_end = wpabuf_put(msg, 0);
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+		goto skip_wrapped_data;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
+	pos = clear;
+
+	if (r_nonce) {
+		/* R-nonce */
+		WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
+		pos += 2;
+		WPA_PUT_LE16(pos, nonce_len);
+		pos += 2;
+		os_memcpy(pos, r_nonce, nonce_len);
+		pos += nonce_len;
+	}
+
+	if (i_nonce) {
+		/* I-nonce */
+		WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+		pos += 2;
+		WPA_PUT_LE16(pos, nonce_len);
+		pos += 2;
+		os_memcpy(pos, i_nonce, nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+		if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
+			wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
+			pos[nonce_len / 2] ^= 0x01;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+		pos += nonce_len;
+	}
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
+		goto skip_r_capab;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* R-capabilities */
+	WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
+	pos += 2;
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
+		DPP_CAPAB_ENROLLEE;
+	*pos++ = auth->r_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
+		pos[-1] = 0;
+	} else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - incompatible R-capabilities");
+		if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
+		    (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
+			pos[-1] = 0;
+		else
+			pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
+				DPP_CAPAB_CONFIGURATOR;
+	}
+skip_r_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (wrapped_r_auth) {
+		/* {R-auth}ke */
+		WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
+		pos += 2;
+		WPA_PUT_LE16(pos, wrapped_r_auth_len);
+		pos += 2;
+		os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
+		pos += wrapped_r_auth_len;
+	}
+
+	/* OUI, OUI type, Crypto Suite, DPP frame type */
+	addr[0] = wpabuf_head_u8(msg) + 2;
+	len[0] = 3 + 1 + 1 + 1;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+	/* Attributes before Wrapped Data */
+	addr[1] = attr_start;
+	len[1] = attr_end - attr_start;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+	siv_len = pos - clear;
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+	if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
+			    2, addr, len, wrapped_data) < 0) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+	siv_len += AES_BLOCK_SIZE;
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+		    wrapped_data, siv_len);
+
+	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+	wpabuf_put_le16(msg, siv_len);
+	wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+		dpp_build_attr_status(msg, DPP_STATUS_OK);
+	}
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	wpa_hexdump_buf(MSG_DEBUG,
+			"DPP: Authentication Response frame attributes", msg);
+	return msg;
+}
+
+
+static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
+			       u16 num_modes, unsigned int freq)
+{
+	u16 m;
+	int c, flag;
+
+	if (!own_modes || !num_modes)
+		return 1;
+
+	for (m = 0; m < num_modes; m++) {
+		for (c = 0; c < own_modes[m].num_channels; c++) {
+			if ((unsigned int) own_modes[m].channels[c].freq !=
+			    freq)
+				continue;
+			flag = own_modes[m].channels[c].flag;
+			if (!(flag & (HOSTAPD_CHAN_DISABLED |
+				      HOSTAPD_CHAN_NO_IR |
+				      HOSTAPD_CHAN_RADAR)))
+				return 1;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
+	return 0;
+}
+
+
+static int freq_included(const unsigned int freqs[], unsigned int num,
+			 unsigned int freq)
+{
+	while (num > 0) {
+		if (freqs[--num] == freq)
+			return 1;
+	}
+	return 0;
+}
+
+
+static void freq_to_start(unsigned int freqs[], unsigned int num,
+			  unsigned int freq)
+{
+	unsigned int i;
+
+	for (i = 0; i < num; i++) {
+		if (freqs[i] == freq)
+			break;
+	}
+	if (i == 0 || i >= num)
+		return;
+	os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
+	freqs[0] = freq;
+}
+
+
+static int dpp_channel_intersect(struct dpp_authentication *auth,
+				 struct hostapd_hw_modes *own_modes,
+				 u16 num_modes)
+{
+	struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
+	unsigned int i, freq;
+
+	for (i = 0; i < peer_bi->num_freq; i++) {
+		freq = peer_bi->freq[i];
+		if (freq_included(auth->freq, auth->num_freq, freq))
+			continue;
+		if (dpp_channel_ok_init(own_modes, num_modes, freq))
+			auth->freq[auth->num_freq++] = freq;
+	}
+	if (!auth->num_freq) {
+		wpa_printf(MSG_INFO,
+			   "DPP: No available channels for initiating DPP Authentication");
+		return -1;
+	}
+	auth->curr_freq = auth->freq[0];
+	return 0;
+}
+
+
+static int dpp_channel_local_list(struct dpp_authentication *auth,
+				  struct hostapd_hw_modes *own_modes,
+				  u16 num_modes)
+{
+	u16 m;
+	int c, flag;
+	unsigned int freq;
+
+	auth->num_freq = 0;
+
+	if (!own_modes || !num_modes) {
+		auth->freq[0] = 2412;
+		auth->freq[1] = 2437;
+		auth->freq[2] = 2462;
+		auth->num_freq = 3;
+		return 0;
+	}
+
+	for (m = 0; m < num_modes; m++) {
+		for (c = 0; c < own_modes[m].num_channels; c++) {
+			freq = own_modes[m].channels[c].freq;
+			flag = own_modes[m].channels[c].flag;
+			if (flag & (HOSTAPD_CHAN_DISABLED |
+				    HOSTAPD_CHAN_NO_IR |
+				    HOSTAPD_CHAN_RADAR))
+				continue;
+			if (freq_included(auth->freq, auth->num_freq, freq))
+				continue;
+			auth->freq[auth->num_freq++] = freq;
+			if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
+				m = num_modes;
+				break;
+			}
+		}
+	}
+
+	return auth->num_freq == 0 ? -1 : 0;
+}
+
+
+static int dpp_prepare_channel_list(struct dpp_authentication *auth,
+				    struct hostapd_hw_modes *own_modes,
+				    u16 num_modes)
+{
+	int res;
+	char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
+	unsigned int i;
+
+	if (auth->peer_bi->num_freq > 0)
+		res = dpp_channel_intersect(auth, own_modes, num_modes);
+	else
+		res = dpp_channel_local_list(auth, own_modes, num_modes);
+	if (res < 0)
+		return res;
+
+	/* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
+	 * likely channels first. */
+	freq_to_start(auth->freq, auth->num_freq, 2462);
+	freq_to_start(auth->freq, auth->num_freq, 2412);
+	freq_to_start(auth->freq, auth->num_freq, 2437);
+
+	auth->freq_idx = 0;
+	auth->curr_freq = auth->freq[0];
+
+	pos = freqs;
+	end = pos + sizeof(freqs);
+	for (i = 0; i < auth->num_freq; i++) {
+		res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
+		if (os_snprintf_error(end - pos, res))
+			break;
+		pos += res;
+	}
+	*pos = '\0';
+	wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
+		   freqs);
+
+	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 */
+
+	bi = os_zalloc(sizeof(*bi));
+	if (!bi)
+		return -1;
+	bi->type = DPP_BOOTSTRAP_QR_CODE;
+	pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
+	if (!pk)
+		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_bootstrap_info *peer_bi,
+					  struct dpp_bootstrap_info *own_bi,
+					  u8 dpp_allowed_roles,
+					  unsigned int neg_freq,
+					  struct hostapd_hw_modes *own_modes,
+					  u16 num_modes)
+{
+	struct dpp_authentication *auth;
+	size_t nonce_len;
+	EVP_PKEY_CTX *ctx = NULL;
+	size_t secret_len;
+	struct wpabuf *pi = NULL;
+	const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+	u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	auth = os_zalloc(sizeof(*auth));
 	if (!auth)
 		return NULL;
 	auth->msg_ctx = msg_ctx;
 	auth->initiator = 1;
-	auth->configurator = configurator;
+	auth->waiting_auth_resp = 1;
+	auth->allowed_roles = dpp_allowed_roles;
+	auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
 	auth->peer_bi = peer_bi;
 	auth->own_bi = own_bi;
 	auth->curve = peer_bi->curve;
 
+	if (dpp_autogen_bootstrap_key(auth) < 0 ||
+	    dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
+		goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_nonce_override_len > 0) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
+		nonce_len = dpp_nonce_override_len;
+		os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
+	} else {
+		nonce_len = auth->curve->nonce_len;
+		if (random_get_bytes(auth->i_nonce, nonce_len)) {
+			wpa_printf(MSG_ERROR,
+				   "DPP: Failed to generate I-nonce");
+			goto fail;
+		}
+	}
+#else /* CONFIG_TESTING_OPTIONS */
 	nonce_len = auth->curve->nonce_len;
 	if (random_get_bytes(auth->i_nonce, nonce_len)) {
 		wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
 		goto fail;
 	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_protocol_key_override_len) {
+		const struct dpp_curve_params *tmp_curve;
+
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - override protocol key");
+		auth->own_protocol_key = dpp_set_keypair(
+			&tmp_curve, dpp_protocol_key_override,
+			dpp_protocol_key_override_len);
+	} else {
+		auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+	}
+#else /* CONFIG_TESTING_OPTIONS */
 	auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (!auth->own_protocol_key)
 		goto fail;
 
@@ -1388,93 +2143,60 @@
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
 			auth->Mx, auth->secret_len);
+	auth->Mx_len = auth->secret_len;
 
 	if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
 			  auth->curve->hash_len) < 0)
 		goto fail;
 
-	/* Build DPP Authentication Request frame attributes */
-	attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + wpabuf_len(pi) +
-		4 + sizeof(wrapped_data);
-	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
-	if (!msg)
+	r_pubkey_hash = auth->peer_bi->pubkey_hash;
+	i_pubkey_hash = auth->own_bi->pubkey_hash;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+		r_pubkey_hash = NULL;
+	} else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
+		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		r_pubkey_hash = test_hash;
+	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+		i_pubkey_hash = NULL;
+	} else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
+		os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		i_pubkey_hash = test_hash;
+	} else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
+		wpabuf_free(pi);
+		pi = NULL;
+	} else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
+		wpabuf_free(pi);
+		pi = wpabuf_alloc(2 * auth->curve->prime_len);
+		if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
+			goto fail;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
+					   i_pubkey_hash, neg_freq);
+	if (!auth->req_msg)
 		goto fail;
-	auth->req_msg = msg;
 
-	attr_start = wpabuf_put(msg, 0);
-
-	/* Responder Bootstrapping Key Hash */
-	wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
-	wpabuf_put_le16(msg, SHA256_MAC_LEN);
-	wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
-
-	/* Initiator Bootstrapping Key Hash */
-	wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
-	wpabuf_put_le16(msg, SHA256_MAC_LEN);
-	if (auth->own_bi)
-		wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
-	else
-		os_memset(wpabuf_put(msg, SHA256_MAC_LEN), 0, SHA256_MAC_LEN);
-
-	/* Initiator Protocol Key */
-	wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
-	wpabuf_put_le16(msg, wpabuf_len(pi));
-	wpabuf_put_buf(msg, pi);
-	wpabuf_free(pi);
-	pi = NULL;
-
-	/* Wrapped data ({I-nonce, I-capabilities}k1) */
-	pos = clear;
-	/* I-nonce */
-	WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
-	pos += 2;
-	WPA_PUT_LE16(pos, nonce_len);
-	pos += 2;
-	os_memcpy(pos, auth->i_nonce, nonce_len);
-	pos += nonce_len;
-	/* I-capabilities */
-	WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
-	pos += 2;
-	WPA_PUT_LE16(pos, 1);
-	pos += 2;
-	auth->i_capab = configurator ? DPP_CAPAB_CONFIGURATOR :
-		DPP_CAPAB_ENROLLEE;
-	*pos++ = auth->i_capab;
-
-	attr_end = wpabuf_put(msg, 0);
-
-	/* OUI, OUI type, Crypto Suite, DPP frame type */
-	addr[0] = wpabuf_head_u8(msg) + 2;
-	len[0] = 3 + 1 + 1 + 1;
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
-	/* Attributes before Wrapped Data */
-	addr[1] = attr_start;
-	len[1] = attr_end - attr_start;
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
-	siv_len = pos - clear;
-	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
-	if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
-			    2, addr, len, wrapped_data) < 0)
-		goto fail;
-	siv_len += AES_BLOCK_SIZE;
-	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
-		    wrapped_data, siv_len);
-
-	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
-	wpabuf_put_le16(msg, siv_len);
-	wpabuf_put_data(msg, wrapped_data, siv_len);
-
-	wpa_hexdump_buf(MSG_DEBUG,
-			"DPP: Authentication Request frame attributes", msg);
-
-	return auth;
-fail:
+out:
 	wpabuf_free(pi);
 	EVP_PKEY_CTX_free(ctx);
+	return auth;
+fail:
 	dpp_auth_deinit(auth);
-	return NULL;
+	auth = NULL;
+	goto out;
 }
 
 
@@ -1485,6 +2207,7 @@
 	size_t json_len, clear_len;
 	struct wpabuf *clear = NULL, *msg = NULL;
 	u8 *wrapped;
+	size_t attr_len;
 
 	wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
 
@@ -1500,20 +2223,55 @@
 	/* { E-nonce, configAttrib }ke */
 	clear_len = 4 + nonce_len + 4 + json_len;
 	clear = wpabuf_alloc(clear_len);
-	msg = wpabuf_alloc(4 + clear_len + AES_BLOCK_SIZE);
+	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
+		attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+	msg = wpabuf_alloc(attr_len);
 	if (!clear || !msg)
 		goto fail;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
+		goto skip_e_nonce;
+	}
+	if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
+		wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+		wpabuf_put_le16(clear, nonce_len - 1);
+		wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
+		goto skip_e_nonce;
+	}
+	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+		goto skip_wrapped_data;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* E-nonce */
 	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
 	wpabuf_put_le16(clear, nonce_len);
 	wpabuf_put_data(clear, auth->e_nonce, nonce_len);
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_e_nonce:
+	if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
+		goto skip_conf_attr_obj;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* configAttrib */
 	wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
 	wpabuf_put_le16(clear, json_len);
 	wpabuf_put_data(clear, json, json_len);
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_conf_attr_obj:
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
@@ -1527,6 +2285,14 @@
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+		dpp_build_attr_status(msg, DPP_STATUS_OK);
+	}
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	wpa_hexdump_buf(MSG_DEBUG,
 			"DPP: Configuration Request frame attributes", msg);
 	wpabuf_free(clear);
@@ -1544,8 +2310,11 @@
 	wpa_printf(MSG_DEBUG,
 		   "DPP: Authentication success - clear temporary keys");
 	os_memset(auth->Mx, 0, sizeof(auth->Mx));
+	auth->Mx_len = 0;
 	os_memset(auth->Nx, 0, sizeof(auth->Nx));
+	auth->Nx_len = 0;
 	os_memset(auth->Lx, 0, sizeof(auth->Lx));
+	auth->Lx_len = 0;
 	os_memset(auth->k1, 0, sizeof(auth->k1));
 	os_memset(auth->k2, 0, sizeof(auth->k2));
 
@@ -1725,7 +2494,6 @@
 	BIGNUM *lx, *sum, *q;
 	const BIGNUM *bR_bn, *pR_bn;
 	int ret = -1;
-	int num_bytes, offset;
 
 	/* L = ((bR + pR) modulo q) * BI */
 
@@ -1765,17 +2533,10 @@
 		goto fail;
 	}
 
-	num_bytes = BN_num_bytes(lx);
-	if ((size_t) num_bytes > auth->secret_len)
+	if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
 		goto fail;
-	if (auth->secret_len > (size_t) num_bytes)
-		offset = auth->secret_len - num_bytes;
-	else
-		offset = 0;
-
-	os_memset(auth->Lx, 0, offset);
-	BN_bn2bin(lx, auth->Lx + offset);
 	wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+	auth->Lx_len = auth->secret_len;
 	ret = 0;
 fail:
 	EC_POINT_clear_free(l);
@@ -1800,7 +2561,6 @@
 	BIGNUM *lx;
 	const BIGNUM *bI_bn;
 	int ret = -1;
-	int num_bytes, offset;
 
 	/* L = bI * (BR + PR) */
 
@@ -1835,20 +2595,14 @@
 		goto fail;
 	}
 
-	num_bytes = BN_num_bytes(lx);
-	if ((size_t) num_bytes > auth->secret_len)
+	if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
 		goto fail;
-	if (auth->secret_len > (size_t) num_bytes)
-		offset = auth->secret_len - num_bytes;
-	else
-		offset = 0;
-
-	os_memset(auth->Lx, 0, offset);
-	BN_bn2bin(lx, auth->Lx + offset);
 	wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+	auth->Lx_len = auth->secret_len;
 	ret = 0;
 fail:
 	EC_POINT_clear_free(l);
+	EC_POINT_clear_free(sum);
 	EC_KEY_free(bI);
 	EC_KEY_free(BR);
 	EC_KEY_free(PR);
@@ -1858,34 +2612,63 @@
 }
 
 
-static int dpp_auth_build_resp(struct dpp_authentication *auth)
+static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
 {
 	size_t nonce_len;
 	EVP_PKEY_CTX *ctx = NULL;
 	size_t secret_len;
 	struct wpabuf *msg, *pr = NULL;
 	u8 r_auth[4 + DPP_MAX_HASH_LEN];
-	u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE];
-#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
-		4 + sizeof(wrapped_r_auth)
+	u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
 	size_t wrapped_r_auth_len;
-	u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
-	u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
-	u8 *pos;
-	const u8 *addr[2];
-	size_t len[2], siv_len, attr_len;
-	u8 *attr_start, *attr_end;
+	int ret = -1;
+	const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
+	enum dpp_status_error status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+	u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
+	if (!auth->own_bi)
+		return -1;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_nonce_override_len > 0) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
+		nonce_len = dpp_nonce_override_len;
+		os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
+	} else {
+		nonce_len = auth->curve->nonce_len;
+		if (random_get_bytes(auth->r_nonce, nonce_len)) {
+			wpa_printf(MSG_ERROR,
+				   "DPP: Failed to generate R-nonce");
+			goto fail;
+		}
+	}
+#else /* CONFIG_TESTING_OPTIONS */
 	nonce_len = auth->curve->nonce_len;
 	if (random_get_bytes(auth->r_nonce, nonce_len)) {
 		wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
 		goto fail;
 	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_protocol_key_override_len) {
+		const struct dpp_curve_params *tmp_curve;
+
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - override protocol key");
+		auth->own_protocol_key = dpp_set_keypair(
+			&tmp_curve, dpp_protocol_key_override,
+			dpp_protocol_key_override_len);
+	} else {
+		auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+	}
+#else /* CONFIG_TESTING_OPTIONS */
 	auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (!auth->own_protocol_key)
 		goto fail;
 
@@ -1911,6 +2694,7 @@
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
 			auth->Nx, auth->secret_len);
+	auth->Nx_len = auth->secret_len;
 
 	if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
 			  auth->curve->hash_len) < 0)
@@ -1928,215 +2712,163 @@
 	/* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
 	WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
 	WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
-	if (dpp_gen_r_auth(auth, r_auth + 4) < 0 ||
-	    aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+	if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
+		goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
+		r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
 			    r_auth, 4 + auth->curve->hash_len,
 			    0, NULL, NULL, wrapped_r_auth) < 0)
 		goto fail;
 	wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
 	wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
 		    wrapped_r_auth, wrapped_r_auth_len);
+	w_r_auth = wrapped_r_auth;
 
-	/* Build DPP Authentication Response frame attributes */
-	attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
-		4 + wpabuf_len(pr) + 4 + sizeof(wrapped_data);
-	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+	r_pubkey_hash = auth->own_bi->pubkey_hash;
+	if (auth->peer_bi)
+		i_pubkey_hash = auth->peer_bi->pubkey_hash;
+	else
+		i_pubkey_hash = NULL;
+
+	i_nonce = auth->i_nonce;
+	r_nonce = auth->r_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+		r_pubkey_hash = NULL;
+	} else if (dpp_test ==
+		   DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
+		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		r_pubkey_hash = test_hash;
+	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+		i_pubkey_hash = NULL;
+	} else if (dpp_test ==
+		   DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
+		if (i_pubkey_hash)
+			os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+		else
+			os_memset(test_hash, 0, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		i_pubkey_hash = test_hash;
+	} else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
+		wpabuf_free(pr);
+		pr = NULL;
+	} else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
+		wpabuf_free(pr);
+		pr = wpabuf_alloc(2 * auth->curve->prime_len);
+		if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
+			goto fail;
+	} else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
+		w_r_auth = NULL;
+		wrapped_r_auth_len = 0;
+	} else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+		status = 255;
+	} else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+		status = 254;
+	} else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
+		r_nonce = NULL;
+	} else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+		i_nonce = NULL;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
+				  r_pubkey_hash, i_pubkey_hash,
+				  r_nonce, i_nonce,
+				  w_r_auth, wrapped_r_auth_len,
+				  auth->k2);
 	if (!msg)
 		goto fail;
 	wpabuf_free(auth->resp_msg);
 	auth->resp_msg = msg;
-
-	attr_start = wpabuf_put(msg, 0);
-
-	/* DPP Status */
-	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
-	wpabuf_put_le16(msg, 1);
-	wpabuf_put_u8(msg, DPP_STATUS_OK);
-
-	/* Responder Bootstrapping Key Hash */
-	wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
-	wpabuf_put_le16(msg, SHA256_MAC_LEN);
-	wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
-
-	if (auth->peer_bi) {
-		/* Mutual authentication */
-		/* Initiator Bootstrapping Key Hash */
-		wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
-		wpabuf_put_le16(msg, SHA256_MAC_LEN);
-		wpabuf_put_data(msg, auth->peer_bi->pubkey_hash,
-				SHA256_MAC_LEN);
-	}
-
-	/* Responder Protocol Key */
-	wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
-	wpabuf_put_le16(msg, wpabuf_len(pr));
-	wpabuf_put_buf(msg, pr);
-	wpabuf_free(pr);
-	pr = NULL;
-
-	attr_end = wpabuf_put(msg, 0);
-
-	/* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
-	pos = clear;
-	/* R-nonce */
-	WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
-	pos += 2;
-	WPA_PUT_LE16(pos, nonce_len);
-	pos += 2;
-	os_memcpy(pos, auth->r_nonce, nonce_len);
-	pos += nonce_len;
-	/* I-nonce */
-	WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
-	pos += 2;
-	WPA_PUT_LE16(pos, nonce_len);
-	pos += 2;
-	os_memcpy(pos, auth->i_nonce, nonce_len);
-	pos += nonce_len;
-	/* R-capabilities */
-	WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
-	pos += 2;
-	WPA_PUT_LE16(pos, 1);
-	pos += 2;
-	auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
-		DPP_CAPAB_ENROLLEE;
-	*pos++ = auth->r_capab;
-	/* {R-auth}ke */
-	WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
-	pos += 2;
-	WPA_PUT_LE16(pos, wrapped_r_auth_len);
-	pos += 2;
-	os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
-	pos += wrapped_r_auth_len;
-
-	/* OUI, OUI type, Crypto Suite, DPP frame type */
-	addr[0] = wpabuf_head_u8(msg) + 2;
-	len[0] = 3 + 1 + 1 + 1;
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
-	/* Attributes before Wrapped Data */
-	addr[1] = attr_start;
-	len[1] = attr_end - attr_start;
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
-	siv_len = pos - clear;
-	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
-	if (aes_siv_encrypt(auth->k2, auth->curve->hash_len, clear, siv_len,
-			    2, addr, len, wrapped_data) < 0)
-		goto fail;
-	siv_len += AES_BLOCK_SIZE;
-	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
-		    wrapped_data, siv_len);
-
-	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
-	wpabuf_put_le16(msg, siv_len);
-	wpabuf_put_data(msg, wrapped_data, siv_len);
-
-	wpa_hexdump_buf(MSG_DEBUG,
-			"DPP: Authentication Response frame attributes", msg);
-
-	return 0;
-
+	ret = 0;
 fail:
 	wpabuf_free(pr);
-	return -1;
+	return ret;
 }
 
 
 static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
 				      enum dpp_status_error status)
 {
-	size_t nonce_len;
 	struct wpabuf *msg;
-#define DPP_AUTH_RESP_CLEAR_LEN2 4 + DPP_MAX_NONCE_LEN + 4 + 1
-	u8 clear[DPP_AUTH_RESP_CLEAR_LEN2];
-	u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN2 + AES_BLOCK_SIZE];
-	u8 *pos;
-	const u8 *addr[2];
-	size_t len[2], siv_len, attr_len;
-	u8 *attr_start, *attr_end;
+	const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
+#ifdef CONFIG_TESTING_OPTIONS
+	u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
 
+	if (!auth->own_bi)
+		return -1;
 	wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
 
-	/* Build DPP Authentication Response frame attributes */
-	attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 4 + sizeof(wrapped_data);
-	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+	r_pubkey_hash = auth->own_bi->pubkey_hash;
+	if (auth->peer_bi)
+		i_pubkey_hash = auth->peer_bi->pubkey_hash;
+	else
+		i_pubkey_hash = NULL;
+
+	i_nonce = auth->i_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+		r_pubkey_hash = NULL;
+	} else if (dpp_test ==
+		   DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
+		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		r_pubkey_hash = test_hash;
+	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+		i_pubkey_hash = NULL;
+	} else if (dpp_test ==
+		   DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
+		if (i_pubkey_hash)
+			os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+		else
+			os_memset(test_hash, 0, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		i_pubkey_hash = test_hash;
+	} else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+		status = -1;
+	} else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+		i_nonce = NULL;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
+				  r_pubkey_hash, i_pubkey_hash,
+				  NULL, i_nonce, NULL, 0, auth->k1);
 	if (!msg)
-		goto fail;
+		return -1;
 	wpabuf_free(auth->resp_msg);
 	auth->resp_msg = msg;
-
-	attr_start = wpabuf_put(msg, 0);
-
-	/* DPP Status */
-	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
-	wpabuf_put_le16(msg, 1);
-	wpabuf_put_u8(msg, status);
-
-	/* Responder Bootstrapping Key Hash */
-	wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
-	wpabuf_put_le16(msg, SHA256_MAC_LEN);
-	wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
-
-	if (auth->peer_bi) {
-		/* Mutual authentication */
-		/* Initiator Bootstrapping Key Hash */
-		wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
-		wpabuf_put_le16(msg, SHA256_MAC_LEN);
-		wpabuf_put_data(msg, auth->peer_bi->pubkey_hash,
-				SHA256_MAC_LEN);
-	}
-
-	attr_end = wpabuf_put(msg, 0);
-
-	/* Wrapped data ({I-nonce, R-capabilities}k1) */
-	pos = clear;
-	/* I-nonce */
-	nonce_len = auth->curve->nonce_len;
-	WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
-	pos += 2;
-	WPA_PUT_LE16(pos, nonce_len);
-	pos += 2;
-	os_memcpy(pos, auth->i_nonce, nonce_len);
-	pos += nonce_len;
-	/* R-capabilities */
-	WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
-	pos += 2;
-	WPA_PUT_LE16(pos, 1);
-	pos += 2;
-	auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
-		DPP_CAPAB_ENROLLEE;
-	*pos++ = auth->r_capab;
-
-	/* OUI, OUI type, Crypto Suite, DPP frame type */
-	addr[0] = wpabuf_head_u8(msg) + 2;
-	len[0] = 3 + 1 + 1 + 1;
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
-	/* Attributes before Wrapped Data */
-	addr[1] = attr_start;
-	len[1] = attr_end - attr_start;
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
-	siv_len = pos - clear;
-	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
-	if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
-			    2, addr, len, wrapped_data) < 0)
-		goto fail;
-	siv_len += AES_BLOCK_SIZE;
-	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
-		    wrapped_data, siv_len);
-
-	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
-	wpabuf_put_le16(msg, siv_len);
-	wpabuf_put_data(msg, wrapped_data, siv_len);
-
-	wpa_hexdump_buf(MSG_DEBUG,
-			"DPP: Authentication Response frame attributes", msg);
-
 	return 0;
-
-fail:
-	return -1;
 }
 
 
@@ -2145,7 +2877,7 @@
 		struct dpp_bootstrap_info *peer_bi,
 		struct dpp_bootstrap_info *own_bi,
 		unsigned int freq, const u8 *hdr, const u8 *attr_start,
-		const u8 *wrapped_data,	u16 wrapped_data_len)
+		size_t attr_len)
 {
 	EVP_PKEY *pi = NULL;
 	EVP_PKEY_CTX *ctx = NULL;
@@ -2154,14 +2886,29 @@
 	size_t len[2];
 	u8 *unwrapped = NULL;
 	size_t unwrapped_len = 0;
-	const u8 *i_proto, *i_nonce, *i_capab, *i_bootstrap;
-	u16 i_proto_len, i_nonce_len, i_capab_len, i_bootstrap_len;
+	const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
+		*channel;
+	u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
+		i_bootstrap_len, channel_len;
 	struct dpp_authentication *auth = NULL;
-	size_t attr_len;
 
-	if (wrapped_data_len < AES_BLOCK_SIZE)
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at Authentication Request");
 		return NULL;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
+	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+				    &wrapped_data_len);
+	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Wrapped Data attribute");
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
+		    wrapped_data, wrapped_data_len);
 	attr_len = wrapped_data - 4 - attr_start;
 
 	auth = os_zalloc(sizeof(*auth));
@@ -2173,11 +2920,39 @@
 	auth->curve = own_bi->curve;
 	auth->curr_freq = freq;
 
+	channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
+			       &channel_len);
+	if (channel) {
+		int neg_freq;
+
+		if (channel_len < 2) {
+			dpp_auth_fail(auth, "Too short Channel attribute");
+			goto fail;
+		}
+
+		neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
+			   channel[0], channel[1], neg_freq);
+		if (neg_freq < 0) {
+			dpp_auth_fail(auth,
+				      "Unsupported Channel attribute value");
+			goto fail;
+		}
+
+		if (auth->curr_freq != (unsigned int) neg_freq) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Changing negotiation channel from %u MHz to %u MHz",
+				   freq, neg_freq);
+			auth->curr_freq = neg_freq;
+		}
+	}
+
 	i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
 			       &i_proto_len);
 	if (!i_proto) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing required Initiator Protocol Key attribute");
+		dpp_auth_fail(auth,
+			      "Missing required Initiator Protocol Key attribute");
 		goto fail;
 	}
 	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
@@ -2186,7 +2961,7 @@
 	/* M = bR * PI */
 	pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
 	if (!pi) {
-		wpa_printf(MSG_DEBUG, "DPP: Invalid Initiator Protocol Key");
+		dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
 		goto fail;
 	}
 	dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
@@ -2201,6 +2976,7 @@
 		wpa_printf(MSG_ERROR,
 			   "DPP: Failed to derive ECDH shared secret: %s",
 			   ERR_error_string(ERR_get_error(), NULL));
+		dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
 		goto fail;
 	}
 	auth->secret_len = secret_len;
@@ -2209,6 +2985,7 @@
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
 			auth->Mx, auth->secret_len);
+	auth->Mx_len = auth->secret_len;
 
 	if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
 			  auth->curve->hash_len) < 0)
@@ -2229,22 +3006,21 @@
 	if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    2, addr, len, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
 	i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
 			       &i_nonce_len);
 	if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
+		dpp_auth_fail(auth, "Missing or invalid I-nonce");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
@@ -2254,7 +3030,7 @@
 			       DPP_ATTR_I_CAPABILITIES,
 			       &i_capab_len);
 	if (!i_capab || i_capab_len < 1) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-capabilities");
+		dpp_auth_fail(auth, "Missing or invalid I-capabilities");
 		goto fail;
 	}
 	auth->i_capab = i_capab[0];
@@ -2282,9 +3058,25 @@
 		wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
 		auth->configurator = 0;
 		break;
+	case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
+		if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
+			wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
+			auth->configurator = 0;
+		} else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
+			wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
+			auth->configurator = 1;
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Local policy does not allow Configurator/Enrollee role");
+			goto not_compatible;
+		}
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
-		goto not_compatible;
+		wpa_msg(auth->msg_ctx, MSG_INFO,
+			DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
+			auth->i_capab & DPP_CAPAB_ROLE_MASK);
+		goto fail;
 	}
 
 	auth->peer_protocol_key = pi;
@@ -2314,7 +3106,7 @@
 			"%s", hex);
 		return auth;
 	}
-	if (dpp_auth_build_resp(auth) < 0)
+	if (dpp_auth_build_resp_ok(auth) < 0)
 		goto fail;
 
 	return auth;
@@ -2355,52 +3147,107 @@
 		   MACSTR, MAC2STR(auth->peer_mac_addr));
 	auth->peer_bi = peer_bi;
 
-	if (dpp_auth_build_resp(auth) < 0)
+	if (dpp_auth_build_resp_ok(auth) < 0)
 		return -1;
 
 	return 1;
 }
 
 
-static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth)
+static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
+					   enum dpp_status_error status)
 {
 	struct wpabuf *msg;
 	u8 i_auth[4 + DPP_MAX_HASH_LEN];
 	size_t i_auth_len;
+	u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
+	size_t r_nonce_len;
 	const u8 *addr[2];
 	size_t len[2], attr_len;
 	u8 *wrapped_i_auth;
+	u8 *wrapped_r_nonce;
 	u8 *attr_start, *attr_end;
+	const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+	u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
 
 	i_auth_len = 4 + auth->curve->hash_len;
+	r_nonce_len = 4 + auth->curve->nonce_len;
 	/* Build DPP Authentication Confirmation frame attributes */
 	attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
-		4 + i_auth_len + AES_BLOCK_SIZE;
+		4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
+		attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
 	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
 	if (!msg)
 		goto fail;
 
 	attr_start = wpabuf_put(msg, 0);
 
+	r_pubkey_hash = auth->peer_bi->pubkey_hash;
+	if (auth->own_bi)
+		i_pubkey_hash = auth->own_bi->pubkey_hash;
+	else
+		i_pubkey_hash = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+		goto skip_status;
+	} else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+		status = 254;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* DPP Status */
-	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
-	wpabuf_put_le16(msg, 1);
-	wpabuf_put_u8(msg, DPP_STATUS_OK);
+	dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+		r_pubkey_hash = NULL;
+	} else if (dpp_test ==
+		   DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
+		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		r_pubkey_hash = test_hash;
+	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+		i_pubkey_hash = NULL;
+	} else if (dpp_test ==
+		   DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
+		if (i_pubkey_hash)
+			os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+		else
+			os_memset(test_hash, 0, SHA256_MAC_LEN);
+		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+		i_pubkey_hash = test_hash;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	/* Responder Bootstrapping Key Hash */
-	wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
-	wpabuf_put_le16(msg, SHA256_MAC_LEN);
-	wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+	dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
 
-	if (auth->own_bi) {
-		/* Mutual authentication */
-		/* Initiator Bootstrapping Key Hash */
-		wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
-		wpabuf_put_le16(msg, SHA256_MAC_LEN);
-		wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
-	}
+	/* Initiator Bootstrapping Key Hash (mutual authentication) */
+	dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
+		goto skip_wrapped_data;
+	if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+		i_auth_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	attr_end = wpabuf_put(msg, 0);
 
@@ -2414,28 +3261,73 @@
 	len[1] = attr_end - attr_start;
 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
 
-	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
-	wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
-	wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
-	/* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
-	WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
-	WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
-	if (dpp_gen_i_auth(auth, i_auth + 4) < 0 ||
-	    aes_siv_encrypt(auth->ke, auth->curve->hash_len,
-			    i_auth, i_auth_len,
-			    2, addr, len, wrapped_i_auth) < 0)
-		goto fail;
-	wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
-		    wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
+	if (status == DPP_STATUS_OK) {
+		/* I-auth wrapped with ke */
+		wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+		wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
+		wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+		if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+			goto skip_i_auth;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+		/* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
+		 *	      1) */
+		WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
+		WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
+		if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
+			goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+		if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
+			wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
+			i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+		}
+skip_i_auth:
+#endif /* CONFIG_TESTING_OPTIONS */
+		if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+				    i_auth, i_auth_len,
+				    2, addr, len, wrapped_i_auth) < 0)
+			goto fail;
+		wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
+			    wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
+	} else {
+		/* R-nonce wrapped with k2 */
+		wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+		wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
+		wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
+
+		WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
+		WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
+		os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
+
+		if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
+				    r_nonce, r_nonce_len,
+				    2, addr, len, wrapped_r_nonce) < 0)
+			goto fail;
+		wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
+			    wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
+	}
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+		dpp_build_attr_status(msg, DPP_STATUS_OK);
+	}
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	wpa_hexdump_buf(MSG_DEBUG,
 			"DPP: Authentication Confirmation frame attributes",
 			msg);
-	dpp_auth_success(auth);
+	if (status == DPP_STATUS_OK)
+		dpp_auth_success(auth);
 
 	return msg;
 
 fail:
+	wpabuf_free(msg);
 	return NULL;
 }
 
@@ -2463,6 +3355,7 @@
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Responder reported failure (status %d)",
 			   status);
+		dpp_auth_fail(auth, "Responder reported failure");
 		return;
 	}
 
@@ -2481,27 +3374,26 @@
 	if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    2, addr, len, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
 	i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
 			       &i_nonce_len);
 	if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
+		dpp_auth_fail(auth, "Missing or invalid I-nonce");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
 	if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
-		wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch");
+		dpp_auth_fail(auth, "I-nonce mismatch");
 		goto fail;
 	}
 
@@ -2509,7 +3401,7 @@
 			       DPP_ATTR_R_CAPABILITIES,
 			       &r_capab_len);
 	if (!r_capab || r_capab_len < 1) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities");
+		dpp_auth_fail(auth, "Missing or invalid R-capabilities");
 		goto fail;
 	}
 	auth->r_capab = r_capab[0];
@@ -2518,9 +3410,20 @@
 		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
 			"r-capab=0x%02x", auth->r_capab);
 	} else if (status == DPP_STATUS_RESPONSE_PENDING) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Continue waiting for full DPP Authentication Response");
-		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_RESPONSE_PENDING);
+		u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+
+		if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+		    (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
+			wpa_msg(auth->msg_ctx, MSG_INFO,
+				DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
+				role);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Continue waiting for full DPP Authentication Response");
+			wpa_msg(auth->msg_ctx, MSG_INFO,
+				DPP_EVENT_RESPONSE_PENDING "%s",
+				auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
+		}
 	}
 fail:
 	bin_clear_free(unwrapped, unwrapped_len);
@@ -2544,34 +3447,49 @@
 		r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
 		wrapped2_len, r_auth_len;
 	u8 r_auth2[DPP_MAX_HASH_LEN];
+	u8 role;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at Authentication Response");
+		return NULL;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (!auth->initiator) {
+		dpp_auth_fail(auth, "Unexpected Authentication Response");
+		return NULL;
+	}
+
+	auth->waiting_auth_resp = 0;
 
 	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
 				    &wrapped_data_len);
-	if (!wrapped_data) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing required Wrapped data attribute");
+	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+		dpp_auth_fail(auth,
+			      "Missing or invalid required Wrapped Data attribute");
 		return NULL;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
 		    wrapped_data, wrapped_data_len);
 
-	if (wrapped_data_len < AES_BLOCK_SIZE)
-		return NULL;
-
 	attr_len = wrapped_data - 4 - attr_start;
 
 	r_bootstrap = dpp_get_attr(attr_start, attr_len,
 				   DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
 				   &r_bootstrap_len);
 	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid required Responder Bootstrapping Key Hash attribute");
 		return NULL;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
 		    r_bootstrap, r_bootstrap_len);
 	if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
 		      SHA256_MAC_LEN) != 0) {
+		dpp_auth_fail(auth,
+			      "Unexpected Responder Bootstrapping Key Hash value");
 		wpa_hexdump(MSG_DEBUG,
 			    "DPP: Expected Responder Bootstrapping Key Hash",
 			    auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
@@ -2583,8 +3501,8 @@
 				   &i_bootstrap_len);
 	if (i_bootstrap) {
 		if (i_bootstrap_len != SHA256_MAC_LEN) {
-			wpa_printf(MSG_DEBUG,
-				   "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
+			dpp_auth_fail(auth,
+				      "Invalid Initiator Bootstrapping Key Hash attribute");
 			return NULL;
 		}
 		wpa_hexdump(MSG_MSGDUMP,
@@ -2593,17 +3511,22 @@
 		if (!auth->own_bi ||
 		    os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
 			      SHA256_MAC_LEN) != 0) {
-			wpa_printf(MSG_DEBUG,
-				   "DPP: Initiator Bootstrapping Key Hash attribute did not match");
+			dpp_auth_fail(auth,
+				      "Initiator Bootstrapping Key Hash attribute did not match");
 			return NULL;
 		}
+	} else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
+		/* PKEX bootstrapping mandates use of mutual authentication */
+		dpp_auth_fail(auth,
+			      "Missing Initiator Bootstrapping Key Hash attribute");
+		return NULL;
 	}
 
 	status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
 			      &status_len);
 	if (!status || status_len < 1) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required DPP Status attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid required DPP Status attribute");
 		return NULL;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
@@ -2615,11 +3538,20 @@
 		return NULL;
 	}
 
+	if (!i_bootstrap && auth->own_bi) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Responder decided not to use mutual authentication");
+		auth->own_bi = NULL;
+	}
+
+	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
+		auth->own_bi != NULL);
+
 	r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
 			       &r_proto_len);
 	if (!r_proto) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing required Responder Protocol Key attribute");
+		dpp_auth_fail(auth,
+			      "Missing required Responder Protocol Key attribute");
 		return NULL;
 	}
 	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
@@ -2628,7 +3560,7 @@
 	/* N = pI * PR */
 	pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
 	if (!pr) {
-		wpa_printf(MSG_DEBUG, "DPP: Invalid Responder Protocol Key");
+		dpp_auth_fail(auth, "Invalid Responder Protocol Key");
 		return NULL;
 	}
 	dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
@@ -2643,6 +3575,7 @@
 		wpa_printf(MSG_ERROR,
 			   "DPP: Failed to derive ECDH shared secret: %s",
 			   ERR_error_string(ERR_get_error(), NULL));
+		dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
 		goto fail;
 	}
 	EVP_PKEY_CTX_free(ctx);
@@ -2652,6 +3585,7 @@
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
 			auth->Nx, auth->secret_len);
+	auth->Nx_len = auth->secret_len;
 
 	if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
 			  auth->curve->hash_len) < 0)
@@ -2672,22 +3606,21 @@
 	if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    2, addr, len, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
 	r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
 			       &r_nonce_len);
 	if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-nonce");
+		dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
@@ -2696,12 +3629,12 @@
 	i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
 			       &i_nonce_len);
 	if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
+		dpp_auth_fail(auth, "Missing or invalid I-nonce");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
 	if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
-		wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch");
+		dpp_auth_fail(auth, "I-nonce mismatch");
 		goto fail;
 	}
 
@@ -2711,34 +3644,52 @@
 			goto fail;
 	}
 
-	if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
-		goto fail;
-
 	r_capab = dpp_get_attr(unwrapped, unwrapped_len,
 			       DPP_ATTR_R_CAPABILITIES,
 			       &r_capab_len);
 	if (!r_capab || r_capab_len < 1) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities");
+		dpp_auth_fail(auth, "Missing or invalid R-capabilities");
 		goto fail;
 	}
 	auth->r_capab = r_capab[0];
 	wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
-	if ((auth->configurator && (auth->r_capab & DPP_CAPAB_CONFIGURATOR)) ||
-	    (!auth->configurator && (auth->r_capab & DPP_CAPAB_ENROLLEE))) {
+	role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+	if ((auth->allowed_roles ==
+	     (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
+	    (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
+		/* Peer selected its role, so move from "either role" to the
+		 * role that is compatible with peer's selection. */
+		auth->configurator = role == DPP_CAPAB_ENROLLEE;
+		wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
+			   auth->configurator ? "Configurator" : "Enrollee");
+	} else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+		   (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
 		wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
-		goto fail;
+		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Unexpected role in R-capabilities 0x%02x",
+			role);
+		if (role != DPP_CAPAB_ENROLLEE &&
+		    role != DPP_CAPAB_CONFIGURATOR)
+			goto fail;
+		bin_clear_free(unwrapped, unwrapped_len);
+		auth->remove_on_tx_status = 1;
+		return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
 	}
 
 	wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
 				DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
 	if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid Secondary Wrapped Data");
+		dpp_auth_fail(auth,
+			      "Missing or invalid Secondary Wrapped Data");
 		goto fail;
 	}
 
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
 		    wrapped2, wrapped2_len);
+
+	if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
+		goto fail;
+
 	unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
 	unwrapped2 = os_malloc(unwrapped2_len);
 	if (!unwrapped2)
@@ -2746,23 +3697,23 @@
 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
 			    wrapped2, wrapped2_len,
 			    0, NULL, NULL, unwrapped2) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped2, unwrapped2_len);
 
 	if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in secondary unwrapped data");
+		dpp_auth_fail(auth,
+			      "Invalid attribute in secondary unwrapped data");
 		goto fail;
 	}
 
 	r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
 			       &r_auth_len);
 	if (!r_auth || r_auth_len != auth->curve->hash_len) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid Responder Authenticating Tag");
+		dpp_auth_fail(auth,
+			      "Missing or invalid Responder Authenticating Tag");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
@@ -2773,15 +3724,27 @@
 	wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
 		    r_auth2, r_auth_len);
 	if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Mismatching Responder Authenticating Tag");
-		goto fail;
+		dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
+		bin_clear_free(unwrapped, unwrapped_len);
+		bin_clear_free(unwrapped2, unwrapped2_len);
+		auth->remove_on_tx_status = 1;
+		return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
 	}
 
 	bin_clear_free(unwrapped, unwrapped_len);
 	bin_clear_free(unwrapped2, unwrapped2_len);
 
-	return dpp_auth_build_conf(auth);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - Authentication Response in place of Confirm");
+		if (dpp_auth_build_resp_ok(auth) < 0)
+			return NULL;
+		return wpabuf_dup(auth->resp_msg);
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	return dpp_auth_build_conf(auth, DPP_STATUS_OK);
 
 fail:
 	bin_clear_free(unwrapped, unwrapped_len);
@@ -2792,6 +3755,77 @@
 }
 
 
+static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
+				    const u8 *hdr,
+				    const u8 *attr_start, size_t attr_len,
+				    const u8 *wrapped_data,
+				    u16 wrapped_data_len,
+				    enum dpp_status_error status)
+{
+	const u8 *addr[2];
+	size_t len[2];
+	u8 *unwrapped = NULL;
+	size_t unwrapped_len = 0;
+	const u8 *r_nonce;
+	u16 r_nonce_len;
+
+	/* Authentication Confirm failure cases are expected to include
+	 * {R-nonce}k2 in the Wrapped Data attribute. */
+
+	addr[0] = hdr;
+	len[0] = DPP_HDR_LEN;
+	addr[1] = attr_start;
+	len[1] = attr_len;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+		    wrapped_data, wrapped_data_len);
+	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+	unwrapped = os_malloc(unwrapped_len);
+	if (!unwrapped) {
+		dpp_auth_fail(auth, "Authentication failed");
+		goto fail;
+	}
+	if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
+			    wrapped_data, wrapped_data_len,
+			    2, addr, len, unwrapped) < 0) {
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
+		goto fail;
+	}
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+		    unwrapped, unwrapped_len);
+
+	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+		goto fail;
+	}
+
+	r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
+			       &r_nonce_len);
+	if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
+		dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
+		goto fail;
+	}
+	if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
+		wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
+			    r_nonce, r_nonce_len);
+		wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
+			    auth->r_nonce, r_nonce_len);
+		dpp_auth_fail(auth, "R-nonce mismatch");
+		goto fail;
+	}
+
+	if (status == DPP_STATUS_NOT_COMPATIBLE)
+		dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
+	else if (status == DPP_STATUS_AUTH_FAILURE)
+		dpp_auth_fail(auth, "Peer reported authentication failure)");
+
+fail:
+	bin_clear_free(unwrapped, unwrapped_len);
+	return -1;
+}
+
+
 int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
 		     const u8 *attr_start, size_t attr_len)
 {
@@ -2804,28 +3838,39 @@
 	size_t unwrapped_len = 0;
 	u8 i_auth2[DPP_MAX_HASH_LEN];
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at Authentication Confirm");
+		return -1;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (auth->initiator) {
+		dpp_auth_fail(auth, "Unexpected Authentication Confirm");
+		return -1;
+	}
+
+	auth->waiting_auth_conf = 0;
+
 	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
 				    &wrapped_data_len);
-	if (!wrapped_data) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing required Wrapped data attribute");
+	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+		dpp_auth_fail(auth,
+			      "Missing or invalid required Wrapped Data attribute");
 		return -1;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
 		    wrapped_data, wrapped_data_len);
 
-	if (wrapped_data_len < AES_BLOCK_SIZE)
-		return -1;
-
 	attr_len = wrapped_data - 4 - attr_start;
 
 	r_bootstrap = dpp_get_attr(attr_start, attr_len,
 				   DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
 				   &r_bootstrap_len);
-	if (!r_bootstrap || r_bootstrap > wrapped_data ||
-	    r_bootstrap_len != SHA256_MAC_LEN) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+		dpp_auth_fail(auth,
+			      "Missing or invalid required Responder Bootstrapping Key Hash attribute");
 		return -1;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
@@ -2835,6 +3880,8 @@
 		wpa_hexdump(MSG_DEBUG,
 			    "DPP: Expected Responder Bootstrapping Key Hash",
 			    auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+		dpp_auth_fail(auth,
+			      "Responder Bootstrapping Key Hash mismatch");
 		return -1;
 	}
 
@@ -2842,10 +3889,9 @@
 				   DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
 				   &i_bootstrap_len);
 	if (i_bootstrap) {
-		if (i_bootstrap > wrapped_data ||
-		    i_bootstrap_len != SHA256_MAC_LEN) {
-			wpa_printf(MSG_DEBUG,
-				   "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
+		if (i_bootstrap_len != SHA256_MAC_LEN) {
+			dpp_auth_fail(auth,
+				      "Invalid Initiator Bootstrapping Key Hash attribute");
 			return -1;
 		}
 		wpa_hexdump(MSG_MSGDUMP,
@@ -2854,22 +3900,34 @@
 		if (!auth->peer_bi ||
 		    os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
 			      SHA256_MAC_LEN) != 0) {
-			wpa_printf(MSG_DEBUG,
-				   "DPP: Initiator Bootstrapping Key Hash attribute did not match");
+			dpp_auth_fail(auth,
+				      "Initiator Bootstrapping Key Hash mismatch");
 			return -1;
 		}
+	} else if (auth->own_bi && auth->peer_bi) {
+		/* Mutual authentication and peer did not include its
+		 * Bootstrapping Key Hash attribute. */
+		dpp_auth_fail(auth,
+			      "Missing Initiator Bootstrapping Key Hash attribute");
+		return -1;
 	}
 
 	status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
 			      &status_len);
 	if (!status || status_len < 1) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required DPP Status attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid required DPP Status attribute");
 		return -1;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+	if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
+	    status[0] == DPP_STATUS_AUTH_FAILURE)
+		return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
+						attr_len, wrapped_data,
+						wrapped_data_len, status[0]);
+
 	if (status[0] != DPP_STATUS_OK) {
-		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+		dpp_auth_fail(auth, "Authentication failed");
 		return -1;
 	}
 
@@ -2888,23 +3946,22 @@
 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    2, addr, len, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
 	i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
 			      &i_auth_len);
 	if (!i_auth || i_auth_len != auth->curve->hash_len) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid Initiator Authenticating Tag");
+		dpp_auth_fail(auth,
+			      "Missing or invalid Initiator Authenticating Tag");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
@@ -2915,8 +3972,7 @@
 	wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
 		    i_auth2, i_auth_len);
 	if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Mismatching Initiator Authenticating Tag");
+		dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
 		goto fail;
 	}
 
@@ -2934,6 +3990,7 @@
 	if (!conf)
 		return;
 	str_clear_free(conf->passphrase);
+	os_free(conf->group_id);
 	bin_clear_free(conf, sizeof(*conf));
 }
 
@@ -2952,6 +4009,7 @@
 	os_free(auth->connector);
 	wpabuf_free(auth->net_access_key);
 	wpabuf_free(auth->c_sign_key);
+	dpp_bootstrap_info_free(auth->tmp_own_bi);
 #ifdef CONFIG_TESTING_OPTIONS
 	os_free(auth->config_obj_override);
 	os_free(auth->discovery_override);
@@ -2990,28 +4048,12 @@
 	json_escape_string(ssid, sizeof(ssid),
 			   (const char *) conf->ssid, conf->ssid_len);
 	wpabuf_put_str(buf, ssid);
-	wpabuf_put_str(buf, "\"");
-	/* TODO: optional channel information */
-	wpabuf_put_str(buf, "},");
+	wpabuf_put_str(buf, "\"},");
 
 	return buf;
 }
 
 
-static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
-{
-	int num_bytes, offset;
-
-	num_bytes = BN_num_bytes(bn);
-	if ((size_t) num_bytes > len)
-		return -1;
-	offset = len - num_bytes;
-	os_memset(pos, 0, offset);
-	BN_bn2bin(bn, pos + offset);
-	return 0;
-}
-
-
 static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
 			 const char *kid, const struct dpp_curve_params *curve)
 {
@@ -3095,6 +4137,9 @@
 		extra_len += os_strlen(auth->groups_override);
 #endif /* CONFIG_TESTING_OPTIONS */
 
+	if (conf->group_id)
+		extra_len += os_strlen(conf->group_id);
+
 	/* Connector (JSON dppCon object) */
 	dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
 	if (!dppcon)
@@ -3113,7 +4158,8 @@
 		goto skip_groups;
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
-	wpabuf_put_str(dppcon, "{\"groups\":[{\"groupId\":\"*\",");
+	wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
+		      conf->group_id ? conf->group_id : "*");
 	wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
 #ifdef CONFIG_TESTING_OPTIONS
 skip_groups:
@@ -3208,7 +4254,7 @@
 	tailroom += signed1_len + signed2_len + signed3_len;
 	buf = dpp_build_conf_start(auth, conf, tailroom);
 	if (!buf)
-		return NULL;
+		goto fail;
 
 	wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
 	wpabuf_put_str(buf, signed1);
@@ -3255,7 +4301,7 @@
 	if (!buf)
 		return NULL;
 
-	wpabuf_put_str(buf, "\"cred\":{\"akm\":\"psk\",");
+	wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
 	if (conf->passphrase) {
 		char pass[63 * 6 + 1];
 
@@ -3308,7 +4354,7 @@
 		return NULL;
 	}
 
-	if (conf->dpp)
+	if (conf->akm == DPP_AKM_DPP)
 		return dpp_build_conf_obj_dpp(auth, ap, conf);
 	return dpp_build_conf_obj_legacy(auth, ap, conf);
 }
@@ -3319,7 +4365,7 @@
 		    u16 e_nonce_len, int ap)
 {
 	struct wpabuf *conf;
-	size_t clear_len;
+	size_t clear_len, attr_len;
 	struct wpabuf *clear = NULL, *msg = NULL;
 	u8 *wrapped;
 	const u8 *addr[1];
@@ -3338,27 +4384,71 @@
 	if (conf)
 		clear_len += 4 + wpabuf_len(conf);
 	clear = wpabuf_alloc(clear_len);
-	msg = wpabuf_alloc(4 + 1 + 4 + clear_len + AES_BLOCK_SIZE);
+	attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
+		attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+	msg = wpabuf_alloc(attr_len);
 	if (!clear || !msg)
 		goto fail;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
+		goto skip_e_nonce;
+	}
+	if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
+		wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+		wpabuf_put_le16(clear, e_nonce_len);
+		wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
+		wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
+		goto skip_e_nonce;
+	}
+	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+		goto skip_wrapped_data;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* E-nonce */
 	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
 	wpabuf_put_le16(clear, e_nonce_len);
 	wpabuf_put_data(clear, e_nonce, e_nonce_len);
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_e_nonce:
+	if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
+		goto skip_config_obj;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (conf) {
 		wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
 		wpabuf_put_le16(clear, wpabuf_len(conf));
 		wpabuf_put_buf(clear, conf);
-		wpabuf_free(conf);
-		conf = NULL;
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_config_obj:
+	if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - Status");
+		goto skip_status;
+	}
+	if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+		status = 255;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* DPP Status */
-	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
-	wpabuf_put_le16(msg, 1);
-	wpabuf_put_u8(msg, status);
+	dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	addr[0] = wpabuf_head(msg);
 	len[0] = wpabuf_len(msg);
@@ -3375,17 +4465,26 @@
 		goto fail;
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
-	wpabuf_free(clear);
-	clear = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+		dpp_build_attr_status(msg, DPP_STATUS_OK);
+	}
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	wpa_hexdump_buf(MSG_DEBUG,
 			"DPP: Configuration Response attributes", msg);
-	return msg;
-fail:
+out:
 	wpabuf_free(conf);
 	wpabuf_free(clear);
+
+	return msg;
+fail:
 	wpabuf_free(msg);
-	return NULL;
+	msg = NULL;
+	goto out;
 }
 
 
@@ -3401,17 +4500,24 @@
 	struct json_token *root = NULL, *token;
 	int ap;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at Config Request");
+		return NULL;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (dpp_check_attrs(attr_start, attr_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in config request");
+		dpp_auth_fail(auth, "Invalid attribute in config request");
 		return NULL;
 	}
 
 	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
 				    &wrapped_data_len);
 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Wrapped data attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid required Wrapped Data attribute");
 		return NULL;
 	}
 
@@ -3424,15 +4530,14 @@
 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    0, NULL, NULL, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
@@ -3440,8 +4545,8 @@
 			       DPP_ATTR_ENROLLEE_NONCE,
 			       &e_nonce_len);
 	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid Enrollee Nonce attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid Enrollee Nonce attribute");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
@@ -3450,8 +4555,8 @@
 				   DPP_ATTR_CONFIG_ATTR_OBJ,
 				   &config_attr_len);
 	if (!config_attr) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid Config Attributes attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid Config Attributes attribute");
 		goto fail;
 	}
 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
@@ -3459,32 +4564,33 @@
 
 	root = json_parse((const char *) config_attr, config_attr_len);
 	if (!root) {
-		wpa_printf(MSG_DEBUG, "DPP: Could not parse Config Attributes");
+		dpp_auth_fail(auth, "Could not parse Config Attributes");
 		goto fail;
 	}
 
 	token = json_get_member(root, "name");
 	if (!token || token->type != JSON_STRING) {
-		wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - name");
+		dpp_auth_fail(auth, "No Config Attributes - name");
 		goto fail;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
 
 	token = json_get_member(root, "wi-fi_tech");
 	if (!token || token->type != JSON_STRING) {
-		wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - wi-fi_tech");
+		dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
 		goto fail;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
 	if (os_strcmp(token->string, "infra") != 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
 			   token->string);
+		dpp_auth_fail(auth, "Unsupported wi-fi_tech");
 		goto fail;
 	}
 
 	token = json_get_member(root, "netRole");
 	if (!token || token->type != JSON_STRING) {
-		wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - netRole");
+		dpp_auth_fail(auth, "No Config Attributes - netRole");
 		goto fail;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
@@ -3495,6 +4601,7 @@
 	} else {
 		wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
 			   token->string);
+		dpp_auth_fail(auth, "Unsupported netRole");
 		goto fail;
 	}
 
@@ -3607,6 +4714,11 @@
 		os_strlcpy(auth->passphrase, pass->string,
 			   sizeof(auth->passphrase));
 	} else if (psk_hex && psk_hex->type == JSON_STRING) {
+		if (auth->akm == DPP_AKM_SAE) {
+			wpa_printf(MSG_DEBUG,
+				   "DPP: Unexpected psk_hex with akm=sae");
+			return -1;
+		}
 		if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
 		    hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
 			wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
@@ -3620,6 +4732,12 @@
 		return -1;
 	}
 
+	if ((auth->akm == DPP_AKM_SAE || auth->akm == DPP_AKM_PSK_SAE) &&
+	    !auth->passphrase[0]) {
+		wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -3950,11 +5068,11 @@
 	size_t payload_len;
 };
 
-static int
+static enum dpp_status_error
 dpp_process_signed_connector(struct dpp_signed_connector_info *info,
 			     EVP_PKEY *csign_pub, const char *connector)
 {
-	int ret = -1;
+	enum dpp_status_error ret = 255;
 	const char *pos, *end, *signed_start, *signed_end;
 	struct wpabuf *kid = NULL;
 	unsigned char *prot_hdr = NULL, *signature = NULL;
@@ -3988,6 +5106,7 @@
 	end = os_strchr(pos, '.');
 	if (!end) {
 		wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 	prot_hdr = base64_url_decode((const unsigned char *) pos,
@@ -3995,18 +5114,22 @@
 	if (!prot_hdr) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Failed to base64url decode signedConnector JWS Protected Header");
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 	wpa_hexdump_ascii(MSG_DEBUG,
 			  "DPP: signedConnector - JWS Protected Header",
 			  prot_hdr, prot_hdr_len);
 	kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
-	if (!kid)
+	if (!kid) {
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
+	}
 	if (wpabuf_len(kid) != SHA256_MAC_LEN) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
 			   (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 
@@ -4015,6 +5138,7 @@
 	if (!end) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Missing dot(2) in signedConnector");
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 	signed_end = end - 1;
@@ -4023,6 +5147,7 @@
 	if (!info->payload) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Failed to base64url decode signedConnector JWS Payload");
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 	wpa_hexdump_ascii(MSG_DEBUG,
@@ -4034,18 +5159,22 @@
 	if (!signature) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Failed to base64url decode signedConnector signature");
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 		}
 	wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
 		    signature, signature_len);
 
-	if (dpp_check_pubkey_match(csign_pub, kid) < 0)
+	if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
+		ret = DPP_STATUS_NO_MATCH;
 		goto fail;
+	}
 
 	if (signature_len & 0x01) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Unexpected signedConnector signature length (%d)",
 			   (int) signature_len);
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 
@@ -4086,10 +5215,11 @@
 		wpa_printf(MSG_DEBUG,
 			   "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
 			   res, ERR_error_string(ERR_get_error(), NULL));
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 
-	ret = 0;
+	ret = DPP_STATUS_OK;
 fail:
 	EC_KEY_free(eckey);
 	EVP_MD_CTX_destroy(md_ctx);
@@ -4148,7 +5278,7 @@
 	}
 
 	if (dpp_process_signed_connector(&info, csign_pub,
-					 signed_connector) < 0)
+					 signed_connector) != DPP_STATUS_OK)
 		goto fail;
 
 	if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
@@ -4170,6 +5300,37 @@
 }
 
 
+const char * dpp_akm_str(enum dpp_akm akm)
+{
+	switch (akm) {
+	case DPP_AKM_DPP:
+		return "dpp";
+	case DPP_AKM_PSK:
+		return "psk";
+	case DPP_AKM_SAE:
+		return "sae";
+	case DPP_AKM_PSK_SAE:
+		return "psk+sae";
+	default:
+		return "??";
+	}
+}
+
+
+static enum dpp_akm dpp_akm_from_str(const char *akm)
+{
+	if (os_strcmp(akm, "psk") == 0)
+		return DPP_AKM_PSK;
+	if (os_strcmp(akm, "sae") == 0)
+		return DPP_AKM_SAE;
+	if (os_strcmp(akm, "psk+sae") == 0)
+		return DPP_AKM_PSK_SAE;
+	if (os_strcmp(akm, "dpp") == 0)
+		return DPP_AKM_DPP;
+	return DPP_AKM_UNKNOWN;
+}
+
+
 static int dpp_parse_conf_obj(struct dpp_authentication *auth,
 			      const u8 *conf_obj, u16 conf_obj_len)
 {
@@ -4180,38 +5341,37 @@
 	if (!root)
 		return -1;
 	if (root->type != JSON_OBJECT) {
-		wpa_printf(MSG_DEBUG, "DPP: JSON root is not an object");
+		dpp_auth_fail(auth, "JSON root is not an object");
 		goto fail;
 	}
 
 	token = json_get_member(root, "wi-fi_tech");
 	if (!token || token->type != JSON_STRING) {
-		wpa_printf(MSG_DEBUG, "DPP: No wi-fi_tech string value found");
+		dpp_auth_fail(auth, "No wi-fi_tech string value found");
 		goto fail;
 	}
 	if (os_strcmp(token->string, "infra") != 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
 			   token->string);
+		dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
 		goto fail;
 	}
 
 	discovery = json_get_member(root, "discovery");
 	if (!discovery || discovery->type != JSON_OBJECT) {
-		wpa_printf(MSG_DEBUG, "DPP: No discovery object in JSON");
+		dpp_auth_fail(auth, "No discovery object in JSON");
 		goto fail;
 	}
 
 	token = json_get_member(discovery, "ssid");
 	if (!token || token->type != JSON_STRING) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No discovery::ssid string value found");
+		dpp_auth_fail(auth, "No discovery::ssid string value found");
 		goto fail;
 	}
 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
 			  token->string, os_strlen(token->string));
 	if (os_strlen(token->string) > SSID_MAX_LEN) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Too long discovery::ssid string value");
+		dpp_auth_fail(auth, "Too long discovery::ssid string value");
 		goto fail;
 	}
 	auth->ssid_len = os_strlen(token->string);
@@ -4219,25 +5379,28 @@
 
 	cred = json_get_member(root, "cred");
 	if (!cred || cred->type != JSON_OBJECT) {
-		wpa_printf(MSG_DEBUG, "DPP: No cred object in JSON");
+		dpp_auth_fail(auth, "No cred object in JSON");
 		goto fail;
 	}
 
 	token = json_get_member(cred, "akm");
 	if (!token || token->type != JSON_STRING) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No cred::akm string value found");
+		dpp_auth_fail(auth, "No cred::akm string value found");
 		goto fail;
 	}
-	if (os_strcmp(token->string, "psk") == 0) {
+	auth->akm = dpp_akm_from_str(token->string);
+
+	if (auth->akm == DPP_AKM_PSK || auth->akm == DPP_AKM_SAE ||
+	    auth->akm == DPP_AKM_PSK_SAE) {
 		if (dpp_parse_cred_legacy(auth, cred) < 0)
 			goto fail;
-	} else if (os_strcmp(token->string, "dpp") == 0) {
+	} else if (auth->akm == DPP_AKM_DPP) {
 		if (dpp_parse_cred_dpp(auth, cred) < 0)
 			goto fail;
 	} else {
 		wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
 			   token->string);
+		dpp_auth_fail(auth, "Unsupported akm");
 		goto fail;
 	}
 
@@ -4261,8 +5424,7 @@
 	int ret = -1;
 
 	if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in config response");
+		dpp_auth_fail(auth, "Invalid attribute in config response");
 		return -1;
 	}
 
@@ -4270,8 +5432,8 @@
 				    DPP_ATTR_WRAPPED_DATA,
 				    &wrapped_data_len);
 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Wrapped data attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid required Wrapped Data attribute");
 		return -1;
 	}
 
@@ -4289,15 +5451,14 @@
 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    1, addr, len, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
@@ -4305,34 +5466,34 @@
 			       DPP_ATTR_ENROLLEE_NONCE,
 			       &e_nonce_len);
 	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid Enrollee Nonce attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid Enrollee Nonce attribute");
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
 	if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
-		wpa_printf(MSG_DEBUG, "Enrollee Nonce mismatch");
+		dpp_auth_fail(auth, "Enrollee Nonce mismatch");
 		goto fail;
 	}
 
 	status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
 			      DPP_ATTR_STATUS, &status_len);
 	if (!status || status_len < 1) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required DPP Status attribute");
+		dpp_auth_fail(auth,
+			      "Missing or invalid required DPP Status attribute");
 		goto fail;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
 	if (status[0] != DPP_STATUS_OK) {
-		wpa_printf(MSG_DEBUG, "DPP: Configuration failed");
+		dpp_auth_fail(auth, "Configurator rejected configuration");
 		goto fail;
 	}
 
 	conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
 				DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
 	if (!conf_obj) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing required Configuration Object attribute");
+		dpp_auth_fail(auth,
+			      "Missing required Configuration Object attribute");
 		goto fail;
 	}
 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
@@ -4358,6 +5519,30 @@
 }
 
 
+int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
+			     size_t buflen)
+{
+	EC_KEY *eckey;
+	int key_len, ret = -1;
+	unsigned char *key = NULL;
+
+	if (!conf->csign)
+		return -1;
+
+	eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
+	if (!eckey)
+		return -1;
+
+	key_len = i2d_ECPrivateKey(eckey, &key);
+	if (key_len > 0)
+		ret = wpa_snprintf_hex(buf, buflen, key, key_len);
+
+	EC_KEY_free(eckey);
+	OPENSSL_free(key);
+	return ret;
+}
+
+
 struct dpp_configurator *
 dpp_keygen_configurator(const char *curve, const u8 *privkey,
 			size_t privkey_len)
@@ -4379,6 +5564,7 @@
 		if (!conf->curve) {
 			wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
 				   curve);
+			os_free(conf);
 			return NULL;
 		}
 	}
@@ -4421,7 +5607,7 @@
 
 
 int dpp_configurator_own_config(struct dpp_authentication *auth,
-				const char *curve)
+				const char *curve, int ap)
 {
 	struct wpabuf *conf_obj;
 	int ret = -1;
@@ -4452,7 +5638,7 @@
 	auth->peer_protocol_key = auth->own_protocol_key;
 	dpp_copy_csign(auth, auth->conf->csign);
 
-	conf_obj = dpp_build_conf_obj(auth, 0);
+	conf_obj = dpp_build_conf_obj(auth, ap);
 	if (!conf_obj)
 		goto fail;
 	ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
@@ -4615,15 +5801,16 @@
 }
 
 
-int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
-		   const u8 *net_access_key, size_t net_access_key_len,
-		   const u8 *csign_key, size_t csign_key_len,
-		   const u8 *peer_connector, size_t peer_connector_len,
-		   os_time_t *expiry)
+enum dpp_status_error
+dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
+	       const u8 *net_access_key, size_t net_access_key_len,
+	       const u8 *csign_key, size_t csign_key_len,
+	       const u8 *peer_connector, size_t peer_connector_len,
+	       os_time_t *expiry)
 {
 	struct json_token *root = NULL, *netkey, *token;
 	struct json_token *own_root = NULL;
-	int ret = -1;
+	enum dpp_status_error ret = 255, res;
 	EVP_PKEY *own_key = NULL, *peer_key = NULL;
 	struct wpabuf *own_key_pub = NULL;
 	const struct dpp_curve_params *curve, *own_curve;
@@ -4691,18 +5878,23 @@
 	os_memcpy(signed_connector, peer_connector, peer_connector_len);
 	signed_connector[peer_connector_len] = '\0';
 
-	if (dpp_process_signed_connector(&info, csign, signed_connector) < 0)
+	res = dpp_process_signed_connector(&info, csign, signed_connector);
+	if (res != DPP_STATUS_OK) {
+		ret = res;
 		goto fail;
+	}
 
 	root = json_parse((const char *) info.payload, info.payload_len);
 	if (!root) {
 		wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 
 	if (!dpp_connector_match_groups(own_root, root)) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Peer connector does not include compatible group netrole with own connector");
+		ret = DPP_STATUS_NO_MATCH;
 		goto fail;
 	}
 
@@ -4715,6 +5907,7 @@
 		if (dpp_key_expired(token->string, expiry)) {
 			wpa_printf(MSG_DEBUG,
 				   "DPP: Connector (netAccessKey) has expired");
+			ret = DPP_STATUS_INVALID_CONNECTOR;
 			goto fail;
 		}
 	}
@@ -4722,18 +5915,22 @@
 	netkey = json_get_member(root, "netAccessKey");
 	if (!netkey || netkey->type != JSON_OBJECT) {
 		wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 
 	peer_key = dpp_parse_jwk(netkey, &curve);
-	if (!peer_key)
+	if (!peer_key) {
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
+	}
 	dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
 
 	if (own_curve != curve) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Mismatching netAccessKey curves (%s != %s)",
 			   own_curve->name, curve->name);
+		ret = DPP_STATUS_INVALID_CONNECTOR;
 		goto fail;
 	}
 
@@ -4767,9 +5964,9 @@
 		goto fail;
 	}
 
-	ret = 0;
+	ret = DPP_STATUS_OK;
 fail:
-	if (ret < 0)
+	if (ret != DPP_STATUS_OK)
 		os_memset(intro, 0, sizeof(*intro));
 	os_memset(Nx, 0, sizeof(Nx));
 	EVP_PKEY_CTX_free(ctx);
@@ -4893,9 +6090,10 @@
 	    EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
 		goto fail;
 	if (EC_POINT_is_at_infinity(group, Qi)) {
-		wpa_printf(MSG_INFO, "PDP: Qi is the point-at-infinity");
+		wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
 		goto fail;
 	}
+	dpp_debug_print_point("DPP: Qi", group, Qi);
 out:
 	EC_KEY_free(Pi_ec);
 	EVP_PKEY_free(Pi);
@@ -4973,6 +6171,11 @@
 	if (!hash_bn ||
 	    EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
 		goto fail;
+	if (EC_POINT_is_at_infinity(group, Qr)) {
+		wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
+		goto fail;
+	}
+	dpp_debug_print_point("DPP: Qr", group, Qr);
 out:
 	EC_KEY_free(Pr_ec);
 	EVP_PKEY_free(Pr);
@@ -4987,6 +6190,72 @@
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static int dpp_test_gen_invalid_key(struct wpabuf *msg,
+				    const struct dpp_curve_params *curve)
+{
+	BN_CTX *ctx;
+	BIGNUM *x, *y;
+	int ret = -1;
+	EC_GROUP *group;
+	EC_POINT *point;
+
+	group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
+	if (!group)
+		return -1;
+
+	ctx = BN_CTX_new();
+	point = EC_POINT_new(group);
+	x = BN_new();
+	y = BN_new();
+	if (!ctx || !point || !x || !y)
+		goto fail;
+
+	if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
+		goto fail;
+
+	/* Generate a random y coordinate that results in a point that is not
+	 * on the curve. */
+	for (;;) {
+		if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
+			goto fail;
+
+		if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
+							ctx) != 1) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
+		/* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
+		 * return an error from EC_POINT_set_affine_coordinates_GFp()
+		 * when the point is not on the curve. */
+			break;
+#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
+			goto fail;
+#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
+		}
+
+		if (!EC_POINT_is_on_curve(group, point, ctx))
+			break;
+	}
+
+	if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
+			   curve->prime_len) < 0 ||
+	    dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
+			   curve->prime_len) < 0)
+		goto fail;
+
+	ret = 0;
+fail:
+	if (ret < 0)
+		wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
+	BN_free(x);
+	BN_free(y);
+	EC_POINT_free(point);
+	BN_CTX_free(ctx);
+
+	return ret;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
 {
 	EC_KEY *X_ec = NULL;
@@ -4999,7 +6268,6 @@
 	struct wpabuf *msg = NULL;
 	size_t attr_len;
 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
-	int num_bytes, offset;
 
 	wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
 
@@ -5013,7 +6281,21 @@
 		goto fail;
 
 	/* Generate a random ephemeral keypair x/X */
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_pkex_ephemeral_key_override_len) {
+		const struct dpp_curve_params *tmp_curve;
+
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - override ephemeral key x/X");
+		pkex->x = dpp_set_keypair(&tmp_curve,
+					  dpp_pkex_ephemeral_key_override,
+					  dpp_pkex_ephemeral_key_override_len);
+	} else {
+		pkex->x = dpp_gen_keypair(curve);
+	}
+#else /* CONFIG_TESTING_OPTIONS */
 	pkex->x = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (!pkex->x)
 		goto fail;
 
@@ -5024,6 +6306,7 @@
 	X_point = EC_KEY_get0_public_key(X_ec);
 	if (!X_point)
 		goto fail;
+	dpp_debug_print_point("DPP: X", group, X_point);
 	M = EC_POINT_new(group);
 	Mx = BN_new();
 	My = BN_new();
@@ -5031,6 +6314,7 @@
 	    EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
 	    EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
 		goto fail;
+	dpp_debug_print_point("DPP: M", group, M);
 
 	/* Initiator -> Responder: group, [identifier,] M */
 	attr_len = 4 + 2;
@@ -5041,11 +6325,22 @@
 	if (!msg)
 		goto fail;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
+		goto skip_finite_cyclic_group;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* Finite Cyclic Group attribute */
 	wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
 	wpabuf_put_le16(msg, 2);
 	wpabuf_put_le16(msg, curve->ike_group);
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_finite_cyclic_group:
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* Code Identifier attribute */
 	if (pkex->identifier) {
 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
@@ -5053,31 +6348,32 @@
 		wpabuf_put_str(msg, pkex->identifier);
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+		goto out;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* M in Encrypted Key attribute */
 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
 	wpabuf_put_le16(msg, 2 * curve->prime_len);
 
-	num_bytes = BN_num_bytes(Mx);
-	if ((size_t) num_bytes > curve->prime_len)
-		goto fail;
-	if (curve->prime_len > (size_t) num_bytes)
-		offset = curve->prime_len - num_bytes;
-	else
-		offset = 0;
-	os_memset(wpabuf_put(msg, offset), 0, offset);
-	BN_bn2bin(Mx, wpabuf_put(msg, num_bytes));
-	os_memset(pkex->Mx, 0, offset);
-	BN_bn2bin(Mx, pkex->Mx + offset);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+		if (dpp_test_gen_invalid_key(msg, curve) < 0)
+			goto fail;
+		goto out;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
-	num_bytes = BN_num_bytes(My);
-	if ((size_t) num_bytes > curve->prime_len)
+	if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
+			   curve->prime_len) < 0 ||
+	    dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
+	    dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
+			   curve->prime_len) < 0)
 		goto fail;
-	if (curve->prime_len > (size_t) num_bytes)
-		offset = curve->prime_len - num_bytes;
-	else
-		offset = 0;
-	os_memset(wpabuf_put(msg, offset), 0, offset);
-	BN_bn2bin(My, wpabuf_put(msg, num_bytes));
 
 out:
 	wpabuf_free(M_buf);
@@ -5096,16 +6392,31 @@
 }
 
 
-struct dpp_pkex * dpp_pkex_init(struct dpp_bootstrap_info *bi,
+static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
+{
+	wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
+}
+
+
+struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 				const u8 *own_mac,
 				const char *identifier,
 				const char *code)
 {
 	struct dpp_pkex *pkex;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+			   MAC2STR(dpp_pkex_own_mac_override));
+		own_mac = dpp_pkex_own_mac_override;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	pkex = os_zalloc(sizeof(*pkex));
 	if (!pkex)
 		return NULL;
+	pkex->msg_ctx = msg_ctx;
 	pkex->initiator = 1;
 	pkex->own_bi = bi;
 	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
@@ -5127,158 +6438,42 @@
 }
 
 
-struct dpp_pkex * dpp_pkex_rx_exchange_req(struct dpp_bootstrap_info *bi,
-					   const u8 *own_mac,
-					   const u8 *peer_mac,
-					   const char *identifier,
-					   const char *code,
-					   const u8 *buf, size_t len)
+static struct wpabuf *
+dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
+			     enum dpp_status_error status,
+			     const BIGNUM *Nx, const BIGNUM *Ny)
 {
-	const u8 *attr_group, *attr_id, *attr_key;
-	u16 attr_group_len, attr_id_len, attr_key_len;
-	const struct dpp_curve_params *curve = bi->curve;
-	u16 ike_group;
-	struct dpp_pkex *pkex = NULL;
-	EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
-	BN_CTX *bnctx = NULL;
-	const EC_GROUP *group;
-	BIGNUM *Mx = NULL, *My = NULL;
-	EC_KEY *Y_ec = NULL, *X_ec = NULL;;
-	const EC_POINT *Y_point;
-	BIGNUM *Nx = NULL, *Ny = NULL;
 	struct wpabuf *msg = NULL;
 	size_t attr_len;
-	int num_bytes, offset;
-
-	attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
-			       &attr_id_len);
-	if (!attr_id && identifier) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No PKEX code identifier received, but expected one");
-		return NULL;
-	}
-	if (attr_id && identifier &&
-	    (os_strlen(identifier) != attr_id_len ||
-	     os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
-		wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
-		return NULL;
-	}
-
-	attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
-				  &attr_group_len);
-	if (!attr_group || attr_group_len != 2) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid Finite Cyclic Group attribute");
-		return NULL;
-	}
-	ike_group = WPA_GET_LE16(attr_group);
-	if (ike_group != curve->ike_group) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Mismatching PKEX curve: peer=%u own=%u",
-			   ike_group, curve->ike_group);
-		/* TODO: error response with suggested curve:
-		 * DPP Status, group */
-		return NULL;
-	}
-
-	/* M in Encrypted Key attribute */
-	attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
-				&attr_key_len);
-	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
-	    attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing Encrypted Key attribute");
-		return NULL;
-	}
-
-	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
-	bnctx = BN_CTX_new();
-	if (!bnctx)
-		goto fail;
-	Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
-				&group);
-	if (!Qi)
-		goto fail;
-
-	/* X' = M - Qi */
-	X = EC_POINT_new(group);
-	M = EC_POINT_new(group);
-	Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
-	My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
-	if (!X || !M || !Mx || !My ||
-	    EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
-	    EC_POINT_is_at_infinity(group, M) ||
-	    !EC_POINT_is_on_curve(group, M, bnctx) ||
-	    EC_POINT_invert(group, Qi, bnctx) != 1 ||
-	    EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
-	    EC_POINT_is_at_infinity(group, X) ||
-	    !EC_POINT_is_on_curve(group, X, bnctx))
-		goto fail;
-
-	pkex = os_zalloc(sizeof(*pkex));
-	if (!pkex)
-		goto fail;
-	pkex->own_bi = bi;
-	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
-	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
-	if (identifier) {
-		pkex->identifier = os_strdup(identifier);
-		if (!pkex->identifier)
-			goto fail;
-	}
-	pkex->code = os_strdup(code);
-	if (!pkex->code)
-		goto fail;
-
-	os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
-
-	X_ec = EC_KEY_new();
-	if (!X_ec ||
-	    EC_KEY_set_group(X_ec, group) != 1 ||
-	    EC_KEY_set_public_key(X_ec, X) != 1)
-		goto fail;
-	pkex->x = EVP_PKEY_new();
-	if (!pkex->x ||
-	    EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
-		goto fail;
-
-	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
-	Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
-	if (!Qr)
-		goto fail;
-
-	/* Generate a random ephemeral keypair y/Y */
-	pkex->y = dpp_gen_keypair(curve);
-	if (!pkex->y)
-		goto fail;
-
-	/* N = Y + Qr */
-	Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
-	if (!Y_ec)
-		goto fail;
-	Y_point = EC_KEY_get0_public_key(Y_ec);
-	if (!Y_point)
-		goto fail;
-	N = EC_POINT_new(group);
-	Nx = BN_new();
-	Ny = BN_new();
-	if (!N || !Nx || !Ny ||
-	    EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
-	    EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
-		goto fail;
+	const struct dpp_curve_params *curve = pkex->own_bi->curve;
 
 	/* Initiator -> Responder: DPP Status, [identifier,] N */
 	attr_len = 4 + 1;
-	if (identifier)
-		attr_len += 4 + os_strlen(identifier);
+	if (pkex->identifier)
+		attr_len += 4 + os_strlen(pkex->identifier);
 	attr_len += 4 + 2 * curve->prime_len;
 	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
 	if (!msg)
 		goto fail;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+		goto skip_status;
+	}
+
+	if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+		status = 255;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* DPP Status */
-	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
-	wpabuf_put_le16(msg, 1);
-	wpabuf_put_u8(msg, DPP_STATUS_OK);
+	dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	/* Code Identifier attribute */
 	if (pkex->identifier) {
@@ -5287,56 +6482,48 @@
 		wpabuf_put_str(msg, pkex->identifier);
 	}
 
+	if (status != DPP_STATUS_OK)
+		goto skip_encrypted_key;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+		goto skip_encrypted_key;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* N in Encrypted Key attribute */
 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
 	wpabuf_put_le16(msg, 2 * curve->prime_len);
 
-	num_bytes = BN_num_bytes(Nx);
-	if ((size_t) num_bytes > curve->prime_len)
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+		if (dpp_test_gen_invalid_key(msg, curve) < 0)
+			goto fail;
+		goto skip_encrypted_key;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
+			   curve->prime_len) < 0 ||
+	    dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
+	    dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
+			   curve->prime_len) < 0)
 		goto fail;
-	if (curve->prime_len > (size_t) num_bytes)
-		offset = curve->prime_len - num_bytes;
-	else
-		offset = 0;
-	os_memset(wpabuf_put(msg, offset), 0, offset);
-	BN_bn2bin(Nx, wpabuf_put(msg, num_bytes));
-	os_memset(pkex->Nx, 0, offset);
-	BN_bn2bin(Nx, pkex->Nx + offset);
 
-	num_bytes = BN_num_bytes(Ny);
-	if ((size_t) num_bytes > curve->prime_len)
-		goto fail;
-	if (curve->prime_len > (size_t) num_bytes)
-		offset = curve->prime_len - num_bytes;
-	else
-		offset = 0;
-	os_memset(wpabuf_put(msg, offset), 0, offset);
-	BN_bn2bin(Ny, wpabuf_put(msg, num_bytes));
+skip_encrypted_key:
+	if (status == DPP_STATUS_BAD_GROUP) {
+		/* Finite Cyclic Group attribute */
+		wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+		wpabuf_put_le16(msg, 2);
+		wpabuf_put_le16(msg, curve->ike_group);
+	}
 
-	pkex->exchange_resp = msg;
-	msg = NULL;
-	pkex->exchange_done = 1;
-
-out:
-	wpabuf_free(msg);
-	BN_CTX_free(bnctx);
-	EC_POINT_free(Qi);
-	EC_POINT_free(Qr);
-	BN_free(Mx);
-	BN_free(My);
-	BN_free(Nx);
-	BN_free(Ny);
-	EC_POINT_free(M);
-	EC_POINT_free(N);
-	EC_POINT_free(X);
-	EC_KEY_free(X_ec);
-	EC_KEY_free(Y_ec);
-	return pkex;
+	return msg;
 fail:
-	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing faileed");
-	dpp_pkex_free(pkex);
-	pkex = NULL;
-	goto out;
+	wpabuf_free(msg);
+	return NULL;
 }
 
 
@@ -5399,16 +6586,376 @@
 }
 
 
-struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
-					  const u8 *buf, size_t buflen)
+struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+					   struct dpp_bootstrap_info *bi,
+					   const u8 *own_mac,
+					   const u8 *peer_mac,
+					   const char *identifier,
+					   const char *code,
+					   const u8 *buf, size_t len)
 {
-	const u8 *attr_status, *attr_id, *attr_key;
-	u16 attr_status_len, attr_id_len, attr_key_len;
-	const EC_GROUP *group;
+	const u8 *attr_group, *attr_id, *attr_key;
+	u16 attr_group_len, attr_id_len, attr_key_len;
+	const struct dpp_curve_params *curve = bi->curve;
+	u16 ike_group;
+	struct dpp_pkex *pkex = NULL;
+	EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
 	BN_CTX *bnctx = NULL;
-	size_t clear_len;
+	const EC_GROUP *group;
+	BIGNUM *Mx = NULL, *My = NULL;
+	EC_KEY *Y_ec = NULL, *X_ec = NULL;;
+	const EC_POINT *Y_point;
+	BIGNUM *Nx = NULL, *Ny = NULL;
+	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
+	size_t Kx_len;
+	int res;
+	EVP_PKEY_CTX *ctx = NULL;
+
+	if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
+		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"PKEX counter t limit reached - ignore message");
+		return NULL;
+	}
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+			   MAC2STR(dpp_pkex_peer_mac_override));
+		peer_mac = dpp_pkex_peer_mac_override;
+	}
+	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+			   MAC2STR(dpp_pkex_own_mac_override));
+		own_mac = dpp_pkex_own_mac_override;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
+			       &attr_id_len);
+	if (!attr_id && identifier) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No PKEX code identifier received, but expected one");
+		return NULL;
+	}
+	if (attr_id && identifier &&
+	    (os_strlen(identifier) != attr_id_len ||
+	     os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
+		wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
+		return NULL;
+	}
+
+	attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+				  &attr_group_len);
+	if (!attr_group || attr_group_len != 2) {
+		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid Finite Cyclic Group attribute");
+		return NULL;
+	}
+	ike_group = WPA_GET_LE16(attr_group);
+	if (ike_group != curve->ike_group) {
+		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Mismatching PKEX curve: peer=%u own=%u",
+			ike_group, curve->ike_group);
+		pkex = os_zalloc(sizeof(*pkex));
+		if (!pkex)
+			goto fail;
+		pkex->own_bi = bi;
+		pkex->failed = 1;
+		pkex->exchange_resp = dpp_pkex_build_exchange_resp(
+			pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
+		if (!pkex->exchange_resp)
+			goto fail;
+		return pkex;
+	}
+
+	/* M in Encrypted Key attribute */
+	attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
+				&attr_key_len);
+	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
+	    attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
+		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Missing Encrypted Key attribute");
+		return NULL;
+	}
+
+	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+	bnctx = BN_CTX_new();
+	if (!bnctx)
+		goto fail;
+	Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
+				&group);
+	if (!Qi)
+		goto fail;
+
+	/* X' = M - Qi */
+	X = EC_POINT_new(group);
+	M = EC_POINT_new(group);
+	Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
+	My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
+	if (!X || !M || !Mx || !My ||
+	    EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
+	    EC_POINT_is_at_infinity(group, M) ||
+	    !EC_POINT_is_on_curve(group, M, bnctx) ||
+	    EC_POINT_invert(group, Qi, bnctx) != 1 ||
+	    EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
+	    EC_POINT_is_at_infinity(group, X) ||
+	    !EC_POINT_is_on_curve(group, X, bnctx)) {
+		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+			"Invalid Encrypted Key value");
+		bi->pkex_t++;
+		goto fail;
+	}
+	dpp_debug_print_point("DPP: M", group, M);
+	dpp_debug_print_point("DPP: X'", group, X);
+
+	pkex = os_zalloc(sizeof(*pkex));
+	if (!pkex)
+		goto fail;
+	pkex->t = bi->pkex_t;
+	pkex->msg_ctx = msg_ctx;
+	pkex->own_bi = bi;
+	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+	if (identifier) {
+		pkex->identifier = os_strdup(identifier);
+		if (!pkex->identifier)
+			goto fail;
+	}
+	pkex->code = os_strdup(code);
+	if (!pkex->code)
+		goto fail;
+
+	os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
+
+	X_ec = EC_KEY_new();
+	if (!X_ec ||
+	    EC_KEY_set_group(X_ec, group) != 1 ||
+	    EC_KEY_set_public_key(X_ec, X) != 1)
+		goto fail;
+	pkex->x = EVP_PKEY_new();
+	if (!pkex->x ||
+	    EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
+		goto fail;
+
+	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+	Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
+	if (!Qr)
+		goto fail;
+
+	/* Generate a random ephemeral keypair y/Y */
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_pkex_ephemeral_key_override_len) {
+		const struct dpp_curve_params *tmp_curve;
+
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - override ephemeral key y/Y");
+		pkex->y = dpp_set_keypair(&tmp_curve,
+					  dpp_pkex_ephemeral_key_override,
+					  dpp_pkex_ephemeral_key_override_len);
+	} else {
+		pkex->y = dpp_gen_keypair(curve);
+	}
+#else /* CONFIG_TESTING_OPTIONS */
+	pkex->y = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+	if (!pkex->y)
+		goto fail;
+
+	/* N = Y + Qr */
+	Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
+	if (!Y_ec)
+		goto fail;
+	Y_point = EC_KEY_get0_public_key(Y_ec);
+	if (!Y_point)
+		goto fail;
+	dpp_debug_print_point("DPP: Y", group, Y_point);
+	N = EC_POINT_new(group);
+	Nx = BN_new();
+	Ny = BN_new();
+	if (!N || !Nx || !Ny ||
+	    EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
+	    EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
+		goto fail;
+	dpp_debug_print_point("DPP: N", group, N);
+
+	pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
+							   Nx, Ny);
+	if (!pkex->exchange_resp)
+		goto fail;
+
+	/* K = y * X' */
+	ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
+	if (!ctx ||
+	    EVP_PKEY_derive_init(ctx) != 1 ||
+	    EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
+	    EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
+	    Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
+	    EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
+		wpa_printf(MSG_ERROR,
+			   "DPP: Failed to derive ECDH shared secret: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto fail;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
+			Kx, Kx_len);
+
+	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+	 */
+	res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
+				pkex->Mx, curve->prime_len,
+				pkex->Nx, curve->prime_len, pkex->code,
+				Kx, Kx_len, pkex->z, curve->hash_len);
+	os_memset(Kx, 0, Kx_len);
+	if (res < 0)
+		goto fail;
+
+	pkex->exchange_done = 1;
+
+out:
+	EVP_PKEY_CTX_free(ctx);
+	BN_CTX_free(bnctx);
+	EC_POINT_free(Qi);
+	EC_POINT_free(Qr);
+	BN_free(Mx);
+	BN_free(My);
+	BN_free(Nx);
+	BN_free(Ny);
+	EC_POINT_free(M);
+	EC_POINT_free(N);
+	EC_POINT_free(X);
+	EC_KEY_free(X_ec);
+	EC_KEY_free(Y_ec);
+	return pkex;
+fail:
+	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
+	dpp_pkex_free(pkex);
+	pkex = NULL;
+	goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
+				 const struct wpabuf *A_pub, const u8 *u)
+{
+	const struct dpp_curve_params *curve = pkex->own_bi->curve;
+	struct wpabuf *msg = NULL;
+	size_t clear_len, attr_len;
 	struct wpabuf *clear = NULL;
 	u8 *wrapped;
+	u8 octet;
+	const u8 *addr[2];
+	size_t len[2];
+
+	/* {A, u, [bootstrapping info]}z */
+	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
+	clear = wpabuf_alloc(clear_len);
+	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
+		attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
+	if (!clear || !msg)
+		goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+		goto skip_bootstrap_key;
+	}
+	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+		wpabuf_put_le16(clear, 2 * curve->prime_len);
+		if (dpp_test_gen_invalid_key(clear, curve) < 0)
+			goto fail;
+		goto skip_bootstrap_key;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* A in Bootstrap Key attribute */
+	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+	wpabuf_put_le16(clear, wpabuf_len(A_pub));
+	wpabuf_put_buf(clear, A_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+	if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
+		goto skip_i_auth_tag;
+	}
+	if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
+		wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+		wpabuf_put_le16(clear, curve->hash_len);
+		wpabuf_put_data(clear, u, curve->hash_len - 1);
+		wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
+		goto skip_i_auth_tag;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* u in I-Auth tag attribute */
+	wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+	wpabuf_put_le16(clear, curve->hash_len);
+	wpabuf_put_data(clear, u, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_auth_tag:
+	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+		goto skip_wrapped_data;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	addr[0] = wpabuf_head_u8(msg) + 2;
+	len[0] = DPP_HDR_LEN;
+	octet = 0;
+	addr[1] = &octet;
+	len[1] = sizeof(octet);
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+	if (aes_siv_encrypt(pkex->z, curve->hash_len,
+			    wpabuf_head(clear), wpabuf_len(clear),
+			    2, addr, len, wrapped) < 0)
+		goto fail;
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+		dpp_build_attr_status(msg, DPP_STATUS_OK);
+	}
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+out:
+	wpabuf_free(clear);
+	return msg;
+
+fail:
+	wpabuf_free(msg);
+	msg = NULL;
+	goto out;
+}
+
+
+struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+					  const u8 *peer_mac,
+					  const u8 *buf, size_t buflen)
+{
+	const u8 *attr_status, *attr_id, *attr_key, *attr_group;
+	u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
+	const EC_GROUP *group;
+	BN_CTX *bnctx = NULL;
 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
 	EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
@@ -5420,18 +6967,50 @@
 	const u8 *addr[4];
 	size_t len[4];
 	u8 u[DPP_MAX_HASH_LEN];
-	u8 octet;
 	int res;
 
+	if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+		return NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at PKEX Exchange Response");
+		pkex->failed = 1;
+		return NULL;
+	}
+
+	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+			   MAC2STR(dpp_pkex_peer_mac_override));
+		peer_mac = dpp_pkex_peer_mac_override;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+
 	attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
 				   &attr_status_len);
 	if (!attr_status || attr_status_len != 1) {
-		wpa_printf(MSG_DEBUG, "DPP: No DPP Status attribute");
+		dpp_pkex_fail(pkex, "No DPP Status attribute");
 		return NULL;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
+
+	if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
+		attr_group = dpp_get_attr(buf, buflen,
+					  DPP_ATTR_FINITE_CYCLIC_GROUP,
+					  &attr_group_len);
+		if (attr_group && attr_group_len == 2) {
+			wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+				"Peer indicated mismatching PKEX group - proposed %u",
+				WPA_GET_LE16(attr_group));
+			return NULL;
+		}
+	}
+
 	if (attr_status[0] != DPP_STATUS_OK) {
-		wpa_printf(MSG_DEBUG, "DPP: PKEX failed");
+		dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
 		return NULL;
 	}
 
@@ -5445,7 +7024,7 @@
 	if (attr_id && pkex->identifier &&
 	    (os_strlen(pkex->identifier) != attr_id_len ||
 	     os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) {
-		wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
+		dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
 		return NULL;
 	}
 
@@ -5453,7 +7032,7 @@
 	attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
 				&attr_key_len);
 	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
-		wpa_printf(MSG_DEBUG, "DPP: Missing Encrypted Key attribute");
+		dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
 		return NULL;
 	}
 
@@ -5478,8 +7057,13 @@
 	    EC_POINT_invert(group, Qr, bnctx) != 1 ||
 	    EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
 	    EC_POINT_is_at_infinity(group, Y) ||
-	    !EC_POINT_is_on_curve(group, Y, bnctx))
+	    !EC_POINT_is_on_curve(group, Y, bnctx)) {
+		dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
+		pkex->t++;
 		goto fail;
+	}
+	dpp_debug_print_point("DPP: N", group, N);
+	dpp_debug_print_point("DPP: Y'", group, Y);
 
 	pkex->exchange_done = 1;
 
@@ -5556,27 +7140,106 @@
 	if (res < 0)
 		goto fail;
 
-	/* {A, u, [bootstrapping info]}z */
+	msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
+	if (!msg)
+		goto fail;
+
+out:
+	wpabuf_free(A_pub);
+	wpabuf_free(X_pub);
+	wpabuf_free(Y_pub);
+	EC_POINT_free(Qr);
+	EC_POINT_free(Y);
+	EC_POINT_free(N);
+	BN_free(Nx);
+	BN_free(Ny);
+	EC_KEY_free(Y_ec);
+	EVP_PKEY_CTX_free(ctx);
+	BN_CTX_free(bnctx);
+	return msg;
+fail:
+	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
+	goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
+				  const struct wpabuf *B_pub, const u8 *v)
+{
+	const struct dpp_curve_params *curve = pkex->own_bi->curve;
+	struct wpabuf *msg = NULL;
+	const u8 *addr[2];
+	size_t len[2];
+	u8 octet;
+	u8 *wrapped;
+	struct wpabuf *clear = NULL;
+	size_t clear_len, attr_len;
+
+	/* {B, v [bootstrapping info]}z */
 	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
 	clear = wpabuf_alloc(clear_len);
-	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ,
-			    4 + clear_len + AES_BLOCK_SIZE);
+	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
+		attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
 	if (!clear || !msg)
 		goto fail;
 
-	/* A in Bootstrap Key attribute */
-	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
-	wpabuf_put_le16(clear, wpabuf_len(A_pub));
-	wpabuf_put_buf(clear, A_pub);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+		goto skip_bootstrap_key;
+	}
+	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+		wpabuf_put_le16(clear, 2 * curve->prime_len);
+		if (dpp_test_gen_invalid_key(clear, curve) < 0)
+			goto fail;
+		goto skip_bootstrap_key;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
-	/* u in I-Auth tag attribute */
-	wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+	/* B in Bootstrap Key attribute */
+	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+	wpabuf_put_le16(clear, wpabuf_len(B_pub));
+	wpabuf_put_buf(clear, B_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+	if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
+		goto skip_r_auth_tag;
+	}
+	if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
+		wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
+		wpabuf_put_le16(clear, curve->hash_len);
+		wpabuf_put_data(clear, v, curve->hash_len - 1);
+		wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
+		goto skip_r_auth_tag;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	/* v in R-Auth tag attribute */
+	wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
 	wpabuf_put_le16(clear, curve->hash_len);
-	wpabuf_put_data(clear, u, curve->hash_len);
+	wpabuf_put_data(clear, v, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_r_auth_tag:
+	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+		goto skip_wrapped_data;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	addr[0] = wpabuf_head_u8(msg) + 2;
 	len[0] = DPP_HDR_LEN;
-	octet = 0;
+	octet = 1;
 	addr[1] = &octet;
 	len[1] = sizeof(octet);
 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
@@ -5594,22 +7257,19 @@
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+		dpp_build_attr_status(msg, DPP_STATUS_OK);
+	}
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
 out:
 	wpabuf_free(clear);
-	wpabuf_free(A_pub);
-	wpabuf_free(X_pub);
-	wpabuf_free(Y_pub);
-	EC_POINT_free(Qr);
-	EC_POINT_free(Y);
-	EC_POINT_free(N);
-	BN_free(Nx);
-	BN_free(Ny);
-	EC_KEY_free(Y_ec);
-	EVP_PKEY_CTX_free(ctx);
-	BN_CTX_free(bnctx);
 	return msg;
+
 fail:
-	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing faileed");
 	wpabuf_free(msg);
 	msg = NULL;
 	goto out;
@@ -5621,9 +7281,9 @@
 					      const u8 *buf, size_t buflen)
 {
 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
-	EVP_PKEY_CTX *ctx;
-	size_t Jx_len, Kx_len, Lx_len;
-	u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
+	EVP_PKEY_CTX *ctx = NULL;
+	size_t Jx_len, Lx_len;
+	u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
 	const u8 *wrapped_data, *b_key, *peer_u;
 	u16 wrapped_data_len, b_key_len, peer_u_len = 0;
@@ -5635,43 +7295,25 @@
 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
 	struct wpabuf *B_pub = NULL;
 	u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
-	size_t clear_len;
-	struct wpabuf *clear = NULL;
-	u8 *wrapped;
-	int res;
 
-	/* K = y * X' */
-	ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
-	    Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
-		goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at PKEX CR Request");
+		pkex->failed = 1;
+		return NULL;
 	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
-	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
-			Kx, Kx_len);
-
-	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
-	 */
-	res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
-				pkex->Mx, curve->prime_len,
-				pkex->Nx, curve->prime_len, pkex->code,
-				Kx, Kx_len, pkex->z, curve->hash_len);
-	os_memset(Kx, 0, Kx_len);
-	if (res < 0)
+	if (!pkex->exchange_done || pkex->failed ||
+	    pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
 		goto fail;
 
 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
 				    &wrapped_data_len);
 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Wrapped data attribute");
+		dpp_pkex_fail(pkex,
+			      "Missing or invalid required Wrapped Data attribute");
 		goto fail;
 	}
 
@@ -5693,34 +7335,36 @@
 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    2, addr, len, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_pkex_fail(pkex,
+			      "AES-SIV decryption failed - possible PKEX code mismatch");
+		pkex->failed = 1;
+		pkex->t++;
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
 			     &b_key_len);
 	if (!b_key || b_key_len != 2 * curve->prime_len) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No valid peer bootstrapping key found");
+		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
 		goto fail;
 	}
 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
 							b_key_len);
-	if (!pkex->peer_bootstrap_key)
+	if (!pkex->peer_bootstrap_key) {
+		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
 		goto fail;
+	}
 	dpp_debug_print_key("DPP: Peer bootstrap public key",
 			    pkex->peer_bootstrap_key);
 
 	/* ECDH: J' = y * A' */
-	EVP_PKEY_CTX_free(ctx);
 	ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
 	if (!ctx ||
 	    EVP_PKEY_derive_init(ctx) != 1 ||
@@ -5758,10 +7402,11 @@
 			      &peer_u_len);
 	if (!peer_u || peer_u_len != curve->hash_len ||
 	    os_memcmp(peer_u, u, curve->hash_len) != 0) {
-		wpa_printf(MSG_DEBUG, "DPP: No valid u (I-Auth tag) found");
+		dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
 			    u, curve->hash_len);
 		wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
+		pkex->t++;
 		goto fail;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
@@ -5800,43 +7445,10 @@
 		goto fail;
 	wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
 
-	/* {B, v [bootstrapping info]}z */
-	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
-	clear = wpabuf_alloc(clear_len);
-	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP,
-			    4 + clear_len + AES_BLOCK_SIZE);
-	if (!clear || !msg)
+	msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
+	if (!msg)
 		goto fail;
 
-	/* A in Bootstrap Key attribute */
-	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
-	wpabuf_put_le16(clear, wpabuf_len(B_pub));
-	wpabuf_put_buf(clear, B_pub);
-
-	/* v in R-Auth tag attribute */
-	wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
-	wpabuf_put_le16(clear, curve->hash_len);
-	wpabuf_put_data(clear, v, curve->hash_len);
-
-	addr[0] = wpabuf_head_u8(msg) + 2;
-	len[0] = DPP_HDR_LEN;
-	octet = 1;
-	addr[1] = &octet;
-	len[1] = sizeof(octet);
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
-	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
-	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
-	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
-
-	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
-	if (aes_siv_encrypt(pkex->z, curve->hash_len,
-			    wpabuf_head(clear), wpabuf_len(clear),
-			    2, addr, len, wrapped) < 0)
-		goto fail;
-	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
-		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
 out:
 	EVP_PKEY_CTX_free(ctx);
 	os_free(unwrapped);
@@ -5844,11 +7456,10 @@
 	wpabuf_free(B_pub);
 	wpabuf_free(X_pub);
 	wpabuf_free(Y_pub);
-	wpabuf_free(clear);
 	return msg;
 fail:
-	wpabuf_free(msg);
-	msg = NULL;
+	wpa_printf(MSG_DEBUG,
+		   "DPP: PKEX Commit-Reveal Request processing failed");
 	goto out;
 }
 
@@ -5871,11 +7482,24 @@
 	EVP_PKEY_CTX *ctx = NULL;
 	struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at PKEX CR Response");
+		pkex->failed = 1;
+		goto fail;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (!pkex->exchange_done || pkex->failed ||
+	    pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+		goto fail;
+
 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
 				    &wrapped_data_len);
 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Wrapped data attribute");
+		dpp_pkex_fail(pkex,
+			      "Missing or invalid required Wrapped Data attribute");
 		goto fail;
 	}
 
@@ -5897,29 +7521,31 @@
 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
 			    wrapped_data, wrapped_data_len,
 			    2, addr, len, unwrapped) < 0) {
-		wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+		dpp_pkex_fail(pkex,
+			      "AES-SIV decryption failed - possible PKEX code mismatch");
+		pkex->t++;
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
 		    unwrapped, unwrapped_len);
 
 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Invalid attribute in unwrapped data");
+		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
 		goto fail;
 	}
 
 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
 			     &b_key_len);
 	if (!b_key || b_key_len != 2 * curve->prime_len) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No valid peer bootstrapping key found");
+		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
 		goto fail;
 	}
 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
 							b_key_len);
-	if (!pkex->peer_bootstrap_key)
+	if (!pkex->peer_bootstrap_key) {
+		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
 		goto fail;
+	}
 	dpp_debug_print_key("DPP: Peer bootstrap public key",
 			    pkex->peer_bootstrap_key);
 
@@ -5961,10 +7587,11 @@
 			      &peer_v_len);
 	if (!peer_v || peer_v_len != curve->hash_len ||
 	    os_memcmp(peer_v, v, curve->hash_len) != 0) {
-		wpa_printf(MSG_DEBUG, "DPP: No valid v (R-Auth tag) found");
+		dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
 			    v, curve->hash_len);
 		wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
+		pkex->t++;
 		goto fail;
 	}
 	wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
@@ -5996,3 +7623,56 @@
 	wpabuf_free(pkex->exchange_resp);
 	os_free(pkex);
 }
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+char * dpp_corrupt_connector_signature(const char *connector)
+{
+	char *tmp, *pos, *signed3 = NULL;
+	unsigned char *signature = NULL;
+	size_t signature_len = 0, signed3_len;
+
+	tmp = os_zalloc(os_strlen(connector) + 5);
+	if (!tmp)
+		goto fail;
+	os_memcpy(tmp, connector, os_strlen(connector));
+
+	pos = os_strchr(tmp, '.');
+	if (!pos)
+		goto fail;
+
+	pos = os_strchr(pos + 1, '.');
+	if (!pos)
+		goto fail;
+	pos++;
+
+	wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
+		   pos);
+	signature = base64_url_decode((const unsigned char *) pos,
+				      os_strlen(pos), &signature_len);
+	if (!signature || signature_len == 0)
+		goto fail;
+	wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
+		    signature, signature_len);
+	signature[signature_len - 1] ^= 0x01;
+	wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
+		    signature, signature_len);
+	signed3 = (char *) base64_url_encode(signature, signature_len,
+					     &signed3_len, 0);
+	if (!signed3)
+		goto fail;
+	os_memcpy(pos, signed3, signed3_len);
+	pos[signed3_len] = '\0';
+	wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
+		   pos);
+
+out:
+	os_free(signature);
+	os_free(signed3);
+	return tmp;
+fail:
+	os_free(tmp);
+	tmp = NULL;
+	goto out;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index dfee499..2575908 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -52,6 +52,8 @@
 	DPP_ATTR_ENROLLEE_NONCE = 0x1014,
 	DPP_ATTR_CODE_IDENTIFIER = 0x1015,
 	DPP_ATTR_TRANSACTION_ID = 0x1016,
+	DPP_ATTR_BOOTSTRAP_INFO = 0x1017,
+	DPP_ATTR_CHANNEL = 0x1018,
 };
 
 enum dpp_status_error {
@@ -62,6 +64,8 @@
 	DPP_STATUS_BAD_GROUP = 4,
 	DPP_STATUS_CONFIGURE_FAILURE = 5,
 	DPP_STATUS_RESPONSE_PENDING = 6,
+	DPP_STATUS_INVALID_CONNECTOR = 7,
+	DPP_STATUS_NO_MATCH = 8,
 };
 
 #define DPP_CAPAB_ENROLLEE BIT(0)
@@ -102,11 +106,17 @@
 	EVP_PKEY *pubkey;
 	u8 pubkey_hash[SHA256_MAC_LEN];
 	const struct dpp_curve_params *curve;
+	unsigned int pkex_t; /* number of failures before dpp_pkex
+			      * instantiation */
 };
 
+#define PKEX_COUNTER_T_LIMIT 5
+
 struct dpp_pkex {
+	void *msg_ctx;
 	unsigned int initiator:1;
 	unsigned int exchange_done:1;
+	unsigned int failed:1;
 	struct dpp_bootstrap_info *own_bi;
 	u8 own_mac[ETH_ALEN];
 	u8 peer_mac[ETH_ALEN];
@@ -120,17 +130,30 @@
 	EVP_PKEY *peer_bootstrap_key;
 	struct wpabuf *exchange_req;
 	struct wpabuf *exchange_resp;
+	unsigned int t; /* number of failures on code use */
+	unsigned int exch_req_wait_time;
+	unsigned int exch_req_tries;
+	unsigned int freq;
+};
+
+enum dpp_akm {
+	DPP_AKM_UNKNOWN,
+	DPP_AKM_DPP,
+	DPP_AKM_PSK,
+	DPP_AKM_SAE,
+	DPP_AKM_PSK_SAE
 };
 
 struct dpp_configuration {
 	u8 ssid[32];
 	size_t ssid_len;
-	int dpp; /* whether to use DPP or legacy configuration */
+	enum dpp_akm akm;
 
 	/* For DPP configuration (connector) */
 	os_time_t netaccesskey_expiry;
 
 	/* TODO: groups */
+	char *group_id;
 
 	/* For legacy configuration */
 	char *passphrase;
@@ -142,6 +165,7 @@
 	const struct dpp_curve_params *curve;
 	struct dpp_bootstrap_info *peer_bi;
 	struct dpp_bootstrap_info *own_bi;
+	struct dpp_bootstrap_info *tmp_own_bi;
 	u8 waiting_pubkey_hash[SHA256_MAC_LEN];
 	int response_pending;
 	enum dpp_status_error auth_resp_status;
@@ -155,19 +179,34 @@
 	EVP_PKEY *peer_protocol_key;
 	struct wpabuf *req_msg;
 	struct wpabuf *resp_msg;
+	/* Intersection of possible frequencies for initiating DPP
+	 * Authentication exchange */
+	unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
+	unsigned int num_freq, freq_idx;
 	unsigned int curr_freq;
+	unsigned int neg_freq;
+	unsigned int num_freq_iters;
 	size_t secret_len;
 	u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
+	size_t Mx_len;
 	u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
+	size_t Nx_len;
 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
+	size_t Lx_len;
 	u8 k1[DPP_MAX_HASH_LEN];
 	u8 k2[DPP_MAX_HASH_LEN];
 	u8 ke[DPP_MAX_HASH_LEN];
 	int initiator;
+	int waiting_auth_resp;
+	int waiting_auth_conf;
+	int auth_req_ack;
+	unsigned int auth_resp_tries;
+	u8 allowed_roles;
 	int configurator;
 	int remove_on_tx_status;
 	int auth_success;
 	struct wpabuf *conf_req;
+	const struct wpabuf *conf_resp; /* owned by GAS server */
 	struct dpp_configuration *conf_ap;
 	struct dpp_configuration *conf_sta;
 	struct dpp_configurator *conf;
@@ -177,6 +216,7 @@
 	char passphrase[64];
 	u8 psk[PMK_LEN];
 	int psk_set;
+	enum dpp_akm akm;
 	struct wpabuf *net_access_key;
 	os_time_t net_access_key_expiry;
 	struct wpabuf *c_sign_key;
@@ -203,6 +243,112 @@
 	size_t pmk_len;
 };
 
+#ifdef CONFIG_TESTING_OPTIONS
+enum dpp_test_behavior {
+	DPP_TEST_DISABLED = 0,
+	DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ = 1,
+	DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP = 2,
+	DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF = 3,
+	DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ = 4,
+	DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP = 5,
+	DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ = 6,
+	DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP = 7,
+	DPP_TEST_ZERO_I_CAPAB = 8,
+	DPP_TEST_ZERO_R_CAPAB = 9,
+	DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 10,
+	DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 11,
+	DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ = 12,
+	DPP_TEST_NO_I_NONCE_AUTH_REQ = 13,
+	DPP_TEST_NO_I_CAPAB_AUTH_REQ = 14,
+	DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ = 15,
+	DPP_TEST_NO_STATUS_AUTH_RESP = 16,
+	DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 17,
+	DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 18,
+	DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP = 19,
+	DPP_TEST_NO_R_NONCE_AUTH_RESP = 20,
+	DPP_TEST_NO_I_NONCE_AUTH_RESP = 21,
+	DPP_TEST_NO_R_CAPAB_AUTH_RESP = 22,
+	DPP_TEST_NO_R_AUTH_AUTH_RESP = 23,
+	DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP = 24,
+	DPP_TEST_NO_STATUS_AUTH_CONF = 25,
+	DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 26,
+	DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 27,
+	DPP_TEST_NO_I_AUTH_AUTH_CONF = 28,
+	DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF = 29,
+	DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP = 30,
+	DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP = 31,
+	DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP = 32,
+	DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF = 33,
+	DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ = 34,
+	DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 35,
+	DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP = 36,
+	DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 37,
+	DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ = 38,
+	DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ = 39,
+	DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ = 40,
+	DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP = 41,
+	DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP = 42,
+	DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP = 43,
+	DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 44,
+	DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 45,
+	DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP = 46,
+	DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ = 47,
+	DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP = 48,
+	DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ = 49,
+	DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP = 50,
+	DPP_TEST_NO_E_NONCE_CONF_REQ = 51,
+	DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ = 52,
+	DPP_TEST_NO_WRAPPED_DATA_CONF_REQ = 53,
+	DPP_TEST_NO_E_NONCE_CONF_RESP = 54,
+	DPP_TEST_NO_CONFIG_OBJ_CONF_RESP = 55,
+	DPP_TEST_NO_STATUS_CONF_RESP = 56,
+	DPP_TEST_NO_WRAPPED_DATA_CONF_RESP = 57,
+	DPP_TEST_INVALID_STATUS_CONF_RESP = 58,
+	DPP_TEST_E_NONCE_MISMATCH_CONF_RESP = 59,
+	DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ = 60,
+	DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ = 61,
+	DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP = 62,
+	DPP_TEST_NO_STATUS_PEER_DISC_RESP = 63,
+	DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP = 64,
+	DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF = 65,
+	DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ = 66,
+	DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP = 67,
+	DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 68,
+	DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 69,
+	DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 70,
+	DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 71,
+	DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 72,
+	DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 73,
+	DPP_TEST_INVALID_STATUS_AUTH_RESP = 74,
+	DPP_TEST_INVALID_STATUS_AUTH_CONF = 75,
+	DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ = 76,
+	DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP = 77,
+	DPP_TEST_INVALID_STATUS_PEER_DISC_RESP = 78,
+	DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP = 79,
+	DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ = 80,
+	DPP_TEST_INVALID_I_NONCE_AUTH_REQ = 81,
+	DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ = 82,
+	DPP_TEST_INVALID_E_NONCE_CONF_REQ = 83,
+	DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP = 84,
+	DPP_TEST_STOP_AT_PKEX_CR_REQ = 85,
+	DPP_TEST_STOP_AT_PKEX_CR_RESP = 86,
+	DPP_TEST_STOP_AT_AUTH_REQ = 87,
+	DPP_TEST_STOP_AT_AUTH_RESP = 88,
+	DPP_TEST_STOP_AT_AUTH_CONF = 89,
+	DPP_TEST_STOP_AT_CONF_REQ = 90,
+};
+
+extern enum dpp_test_behavior dpp_test;
+extern u8 dpp_pkex_own_mac_override[ETH_ALEN];
+extern u8 dpp_pkex_peer_mac_override[ETH_ALEN];
+extern u8 dpp_pkex_ephemeral_key_override[600];
+extern size_t dpp_pkex_ephemeral_key_override_len;
+extern u8 dpp_protocol_key_override[600];
+extern size_t dpp_protocol_key_override_len;
+extern u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
+extern size_t dpp_nonce_override_len;
+#endif /* CONFIG_TESTING_OPTIONS */
+
 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);
@@ -213,16 +359,20 @@
 struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri);
 char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
 		  const u8 *privkey, size_t privkey_len);
+struct hostapd_hw_modes;
 struct dpp_authentication * dpp_auth_init(void *msg_ctx,
 					  struct dpp_bootstrap_info *peer_bi,
 					  struct dpp_bootstrap_info *own_bi,
-					  int configurator);
+					  u8 dpp_allowed_roles,
+					  unsigned int neg_freq,
+					  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,
 		struct dpp_bootstrap_info *own_bi,
 		unsigned int freq, const u8 *hdr, const u8 *attr_start,
-		const u8 *wrapped_data, u16 wrapped_data_len);
+		size_t attr_len);
 struct wpabuf *
 dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
 		 const u8 *attr_start, size_t attr_len);
@@ -244,28 +394,34 @@
 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
 int dpp_check_attrs(const u8 *buf, size_t len);
 int dpp_key_expired(const char *timestamp, os_time_t *expiry);
+const char * dpp_akm_str(enum dpp_akm akm);
+int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
+			     size_t buflen);
 void dpp_configurator_free(struct dpp_configurator *conf);
 struct dpp_configurator *
 dpp_keygen_configurator(const char *curve, const u8 *privkey,
 			size_t privkey_len);
 int dpp_configurator_own_config(struct dpp_authentication *auth,
-				const char *curve);
-int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
-		   const u8 *net_access_key, size_t net_access_key_len,
-		   const u8 *csign_key, size_t csign_key_len,
-		   const u8 *peer_connector, size_t peer_connector_len,
-		   os_time_t *expiry);
-struct dpp_pkex * dpp_pkex_init(struct dpp_bootstrap_info *bi,
+				const char *curve, int ap);
+enum dpp_status_error
+dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
+	       const u8 *net_access_key, size_t net_access_key_len,
+	       const u8 *csign_key, size_t csign_key_len,
+	       const u8 *peer_connector, size_t peer_connector_len,
+	       os_time_t *expiry);
+struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 				const u8 *own_mac,
 				const char *identifier,
 				const char *code);
-struct dpp_pkex * dpp_pkex_rx_exchange_req(struct dpp_bootstrap_info *bi,
+struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+					   struct dpp_bootstrap_info *bi,
 					   const u8 *own_mac,
 					   const u8 *peer_mac,
 					   const char *identifier,
 					   const char *code,
 					   const u8 *buf, size_t len);
 struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+					  const u8 *peer_mac,
 					  const u8 *buf, size_t len);
 struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
 					      const u8 *hdr,
@@ -274,4 +430,6 @@
 				   const u8 *buf, size_t len);
 void dpp_pkex_free(struct dpp_pkex *pkex);
 
+char * dpp_corrupt_connector_signature(const char *connector);
+
 #endif /* DPP_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index fdd5e73..db40379 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -89,7 +89,7 @@
 {
 	int ok, j, first;
 	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
-			  149, 157, 184, 192 };
+			  149, 157, 165, 184, 192 };
 	size_t k;
 
 	if (pri_chan == sec_chan || !sec_chan)
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 120d4e8..4fd3357 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -11,6 +11,7 @@
 #include "common.h"
 #include "defs.h"
 #include "wpa_common.h"
+#include "drivers/driver.h"
 #include "qca-vendor.h"
 #include "ieee802_11_defs.h"
 #include "ieee802_11_common.h"
@@ -120,6 +121,11 @@
 			elems->mbo = pos;
 			elems->mbo_len = elen;
 			break;
+		case HS20_ROAMING_CONS_SEL_OUI_TYPE:
+			/* Hotspot 2.0 Roaming Consortium Selection */
+			elems->roaming_cons_sel = pos;
+			elems->roaming_cons_sel_len = elen;
+			break;
 		default:
 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
 				   "information element ignored "
@@ -256,6 +262,10 @@
 		elems->owe_dh = pos;
 		elems->owe_dh_len = elen;
 		break;
+	case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
+		elems->password_id = pos;
+		elems->password_id_len = elen;
+		break;
 	default:
 		if (show_errors) {
 			wpa_printf(MSG_MSGDUMP,
@@ -352,6 +362,10 @@
 			elems->rsn_ie_len = elen;
 			break;
 		case WLAN_EID_PWR_CAPABILITY:
+			if (elen < 2)
+				break;
+			elems->power_capab = pos;
+			elems->power_capab_len = elen;
 			break;
 		case WLAN_EID_SUPPORTED_CHANNELS:
 			elems->supp_channels = pos;
@@ -619,6 +633,8 @@
 			return NULL;
 		return hdr->addr1;
 	case WLAN_FC_TYPE_MGMT:
+		if (len < 24)
+			return NULL;
 		return hdr->addr3;
 	default:
 		return NULL;
@@ -1169,10 +1185,24 @@
 }
 
 
-int ieee80211_is_dfs(int freq)
+int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
+		     u16 num_modes)
 {
-	/* TODO: this could be more accurate to better cover all domains */
-	return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
+	int i, j;
+
+	if (!modes || !num_modes)
+		return (freq >= 5260 && freq <= 5320) ||
+			(freq >= 5500 && freq <= 5700);
+
+	for (i = 0; i < num_modes; i++) {
+		for (j = 0; j < modes[i].num_channels; j++) {
+			if (modes[i].channels[j].freq == freq &&
+			    (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR))
+				return 1;
+		}
+	}
+
+	return 0;
 }
 
 
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9276158..ff7e51d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -11,6 +11,8 @@
 
 #include "defs.h"
 
+struct hostapd_hw_modes;
+
 #define MAX_NOF_MB_IES_SUPPORTED 5
 
 struct mb_ies_info {
@@ -79,6 +81,9 @@
 	const u8 *fils_pk;
 	const u8 *fils_nonce;
 	const u8 *owe_dh;
+	const u8 *power_capab;
+	const u8 *roaming_cons_sel;
+	const u8 *password_id;
 
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -122,6 +127,9 @@
 	u8 fils_wrapped_data_len;
 	u8 fils_pk_len;
 	u8 owe_dh_len;
+	u8 power_capab_len;
+	u8 roaming_cons_sel_len;
+	u8 password_id_len;
 
 	struct mb_ies_info mb_ies;
 };
@@ -152,7 +160,8 @@
 enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
 						   int sec_channel, int vht,
 						   u8 *op_class, u8 *channel);
-int ieee80211_is_dfs(int freq);
+int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
+		     u16 num_modes);
 enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
 
 int supp_rates_11b_only(struct ieee802_11_elems *elems);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b7fa563..762e731 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -203,6 +203,7 @@
 #define WLAN_STATUS_AUTHORIZATION_DEENABLED 107
 #define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
 #define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
+#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
 
 /* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
 #define WLAN_REASON_UNSPECIFIED 1
@@ -463,6 +464,7 @@
 #define WLAN_EID_EXT_FILS_NONCE 13
 #define WLAN_EID_EXT_FUTURE_CHANNEL_GUIDANCE 14
 #define WLAN_EID_EXT_OWE_DH_PARAM 32
+#define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33
 #define WLAN_EID_EXT_HE_CAPABILITIES 35
 #define WLAN_EID_EXT_HE_OPERATION 36
 
@@ -920,6 +922,16 @@
 					u8 variable[];
 				} STRUCT_PACKED bss_tm_query;
 				struct {
+					u8 action; /* 11 */
+					u8 dialog_token;
+					u8 req_info;
+				} STRUCT_PACKED coloc_intf_req;
+				struct {
+					u8 action; /* 12 */
+					u8 dialog_token;
+					u8 variable[];
+				} STRUCT_PACKED coloc_intf_report;
+				struct {
 					u8 action; /* 15 */
 					u8 variable[];
 				} STRUCT_PACKED slf_prot_action;
@@ -1317,6 +1329,7 @@
 #define HS20_INDICATION_OUI_TYPE 16
 #define HS20_ANQP_OUI_TYPE 17
 #define HS20_OSEN_OUI_TYPE 18
+#define HS20_ROAMING_CONS_SEL_OUI_TYPE 29
 #define HS20_STYPE_QUERY_LIST 1
 #define HS20_STYPE_CAPABILITY_LIST 2
 #define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
@@ -1327,15 +1340,20 @@
 #define HS20_STYPE_OSU_PROVIDERS_LIST 8
 #define HS20_STYPE_ICON_REQUEST 10
 #define HS20_STYPE_ICON_BINARY_FILE 11
+#define HS20_STYPE_OPERATOR_ICON_METADATA 12
+#define HS20_STYPE_OSU_PROVIDERS_NAI_LIST 13
 
 #define HS20_DGAF_DISABLED 0x01
 #define HS20_PPS_MO_ID_PRESENT 0x02
 #define HS20_ANQP_DOMAIN_ID_PRESENT 0x04
+#ifndef HS20_VERSION
 #define HS20_VERSION 0x10 /* Release 2 */
+#endif /* HS20_VERSION */
 
 /* WNM-Notification WFA vendors specific subtypes */
 #define HS20_WNM_SUB_REM_NEEDED 0
 #define HS20_WNM_DEAUTH_IMMINENT_NOTICE 1
+#define HS20_WNM_T_C_ACCEPTANCE 2
 
 #define HS20_DEAUTH_REASON_CODE_BSS 0
 #define HS20_DEAUTH_REASON_CODE_ESS 1
diff --git a/src/common/ieee802_1x_defs.h b/src/common/ieee802_1x_defs.h
index 280c439..e7acff1 100644
--- a/src/common/ieee802_1x_defs.h
+++ b/src/common/ieee802_1x_defs.h
@@ -12,6 +12,8 @@
 #define CS_ID_LEN		8
 #define CS_ID_GCM_AES_128	0x0080020001000001ULL
 #define CS_NAME_GCM_AES_128	"GCM-AES-128"
+#define CS_ID_GCM_AES_256	0x0080c20001000002ULL
+#define CS_NAME_GCM_AES_256	"GCM-AES-256"
 
 enum macsec_policy {
 	/**
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index b4f7d12..7a4da46 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,6 +1,7 @@
 /*
  * Qualcomm Atheros OUI and vendor specific assignments
  * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -49,7 +50,10 @@
  *
  * @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass
  *	NAN Request/Response and NAN Indication messages. These messages are
- *	interpreted between the framework and the firmware component.
+ *	interpreted between the framework and the firmware component. While
+ *	sending the command from userspace to the driver, payload is not
+ *	encapsulated inside any attribute. Attribute QCA_WLAN_VENDOR_ATTR_NAN
+ *	is used when receiving vendor events in userspace from the driver.
  *
  * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be
  *	used to configure PMK to the driver even when not connected. This can
@@ -90,6 +94,49 @@
  *	which supports DFS offloading, to indicate a radar pattern has been
  *	detected. The channel is now unusable.
  *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: Get the feature bitmap
+ *	based on enum wifi_logger_supported_features. Attributes defined in
+ *	enum qca_wlan_vendor_attr_get_logger_features.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA: Get the ring data from a particular
+ *	logger ring, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID is passed as the
+ *	attribute for this command. Attributes defined in
+ *	enum qca_wlan_vendor_attr_wifi_logger_start.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES: Get the supported TDLS
+ *	capabilities of the driver, parameters includes the attributes defined
+ *	in enum qca_wlan_vendor_attr_tdls_get_capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS: Vendor command used to offload
+ *	sending of certain periodic IP packet to firmware, attributes defined in
+ *	enum qca_wlan_vendor_attr_offloaded_packets.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI: Command used to configure RSSI
+ *	monitoring, defines min and max RSSI which are configured for RSSI
+ *	monitoring. Also used to notify the RSSI breach and provides the BSSID
+ *	and RSSI value that was breached. Attributes defined in
+ *	enum qca_wlan_vendor_attr_rssi_monitoring.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NDP: Command used for performing various NAN
+ *	Data Path (NDP) related operations, attributes defined in
+ *	enum qca_wlan_vendor_attr_ndp_params.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD: Command used to enable/disable
+ *	Neighbour Discovery offload, attributes defined in
+ *	enum qca_wlan_vendor_attr_nd_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER: Used to set/get the various
+ *	configuration parameter for BPF packet filter, attributes defined in
+ *	enum qca_wlan_vendor_attr_packet_filter.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE: Gets the driver-firmware
+ *	maximum supported size, attributes defined in
+ *	enum qca_wlan_vendor_drv_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS: Command to get various
+ *	data about wake reasons and datapath IP statistics, attributes defined
+ *	in enum qca_wlan_vendor_attr_wake_stats.
+ *
  * @QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG: Command used to set configuration
  *	for IEEE 802.11 communicating outside the context of a basic service
  *	set, called OCB command. Uses the attributes defines in
@@ -338,6 +385,95 @@
  *	information indicating the reason that triggered this detection. The
  *	attributes for this command are defined in
  *	enum qca_wlan_vendor_attr_hang.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CONFIG: Get the current values
+ *	of spectral parameters used. The spectral scan parameters are specified
+ *	by enum qca_wlan_vendor_attr_spectral_scan.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS: Get the debug stats
+ *	for spectral scan functionality. The debug stats are specified by
+ *	enum qca_wlan_vendor_attr_spectral_diag_stats.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO: Get spectral
+ *	scan system capabilities. The capabilities are specified
+ *	by enum qca_wlan_vendor_attr_spectral_cap.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS: Get the current
+ *	status of spectral scan. The status values are specified
+ *	by enum qca_wlan_vendor_attr_spectral_scan_status.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING: Sub-command to flush
+ *	peer pending packets. Specify the peer MAC address in
+ *	QCA_WLAN_VENDOR_ATTR_PEER_ADDR and the access category of the packets
+ *	in QCA_WLAN_VENDOR_ATTR_AC. The attributes are listed
+ *	in enum qca_wlan_vendor_attr_flush_pending.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO: Get vendor specific Representative
+ *	RF Operating Parameter (RROP) information. The attributes for this
+ *	information are defined in enum qca_wlan_vendor_attr_rrop_info. This is
+ *	intended for use by external Auto Channel Selection applications.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS: Get the Specific Absorption Rate
+ *	(SAR) power limits. This is a companion to the command
+ *	@QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS and is used to retrieve the
+ *	settings currently in use. The attributes returned by this command are
+ *	defined by enum qca_vendor_attr_sar_limits.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO: Provides the current behavior of
+ *	the WLAN hardware MAC. Also, provides the WLAN netdev interface
+ *	information attached to the respective MAC.
+ *	This works both as a query (user space asks the current mode) or event
+ *	interface (driver advertising the current mode to the user space).
+ *	Driver does not trigger this event for temporary hardware mode changes.
+ *	Mode changes w.r.t Wi-Fi connection update (VIZ creation / deletion,
+ *	channel change, etc.) are updated with this event. Attributes for this
+ *	interface are defined in enum qca_wlan_vendor_attr_mac.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH: Set MSDU queue depth threshold
+ *	per peer per TID. Attributes for this command are define in
+ *	enum qca_wlan_set_qdepth_thresh_attr.
+ * @QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD: Provides the thermal shutdown action
+ *	guide for WLAN driver. Request to suspend of driver and FW if the
+ *	temperature is higher than the suspend threshold; resume action is
+ *	requested to driver if the temperature is lower than the resume
+ *	threshold. In user poll mode, request temperature data by user. For test
+ *	purpose, getting thermal shutdown configuration parameters is needed.
+ *	Attributes for this interface are defined in
+ *	enum qca_wlan_vendor_attr_thermal_cmd.
+ * @QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT: Thermal events reported from
+ *	driver. Thermal temperature and indication of resume completion are
+ *	reported as thermal events. The attributes for this command are defined
+ *	in enum qca_wlan_vendor_attr_thermal_event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION: Sub command to set WiFi
+ *	test configuration. Attributes for this command are defined in
+ *	enum qca_wlan_vendor_attr_wifi_test_config.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER: This command is used to configure an
+ *	RX filter to receive frames from stations that are active on the
+ *	operating channel, but not associated with the local device (e.g., STAs
+ *	associated with other APs). Filtering is done based on a list of BSSIDs
+ *	and STA MAC addresses added by the user. This command is also used to
+ *	fetch the statistics of unassociated stations. The attributes used with
+ *	this command are defined in enum qca_wlan_vendor_attr_bss_filter.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NAN_EXT: An extendable version of NAN vendor
+ *	command. The earlier command for NAN, QCA_NL80211_VENDOR_SUBCMD_NAN,
+ *	carried a payload which was a binary blob of data. The command was not
+ *	extendable to send more information. The newer version carries the
+ *	legacy blob encapsulated within an attribute and can be extended with
+ *	additional vendor attributes that can enhance the NAN command interface.
+ * @QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT: Event to indicate scan triggered
+ *	or stopped within driver/firmware in order to initiate roaming. The
+ *	attributes used with this event are defined in enum
+ *	qca_wlan_vendor_attr_roam_scan. Some drivers may not send these events
+ *	in few cases, e.g., if the host processor is sleeping when this event
+ *	is generated in firmware.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG: This command is used to
+ *	configure parameters per peer to capture Channel Frequency Response
+ *	(CFR) and enable Periodic CFR capture. The attributes for this command
+ *	are defined in enum qca_wlan_vendor_peer_cfr_capture_attr.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -405,7 +541,17 @@
 	/* Wi-Fi configuration subcommands */
 	QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
 	QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75,
-	/* 76-90 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET = 76,
+	QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA = 77,
+	QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES = 78,
+	QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS = 79,
+	QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI = 80,
+	QCA_NL80211_VENDOR_SUBCMD_NDP = 81,
+	QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD = 82,
+	QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER = 83,
+	QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE = 84,
+	QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS = 85,
+	/* 86-90 - reserved for QCA */
 	QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
 	QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
 	QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
@@ -470,21 +616,44 @@
 	QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP = 155,
 	QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS = 156,
 	QCA_NL80211_VENDOR_SUBCMD_HANG = 157,
+	QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CONFIG = 158,
+	QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS = 159,
+	QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO = 160,
+	QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS = 161,
+	/* Flush peer pending data */
+	QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING = 162,
+	QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO = 163,
+	QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS = 164,
+	QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO = 165,
+	QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH = 166,
+	/* Thermal shutdown commands to protect wifi chip */
+	QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD = 167,
+	QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT = 168,
+	/* Wi-Fi test configuration subcommand */
+	QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION = 169,
+	/* Frame filter operations for other BSSs/unassociated STAs */
+	QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER = 170,
+	QCA_NL80211_VENDOR_SUBCMD_NAN_EXT = 171,
+	QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT = 172,
+	QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG = 173,
 };
 
-
 enum qca_wlan_vendor_attr {
 	QCA_WLAN_VENDOR_ATTR_INVALID = 0,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
 	QCA_WLAN_VENDOR_ATTR_DFS     = 1,
-	/* used by QCA_NL80211_VENDOR_SUBCMD_NAN */
+	/* Used only when driver sends vendor events to the userspace under the
+	 * command QCA_NL80211_VENDOR_SUBCMD_NAN. Not used when userspace sends
+	 * commands to the driver.
+	 */
 	QCA_WLAN_VENDOR_ATTR_NAN     = 2,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
 	QCA_WLAN_VENDOR_ATTR_STATS_EXT     = 3,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
 	QCA_WLAN_VENDOR_ATTR_IFINDEX     = 4,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_ROAMING, u32 with values defined
-	 * by enum qca_roaming_policy. */
+	 * by enum qca_roaming_policy.
+	 */
 	QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
 	QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
@@ -572,10 +741,12 @@
 	QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
 	/* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
 	 * to specify the chain number (unsigned 32 bit value) to inquire
-	 * the corresponding antenna RSSI value */
+	 * the corresponding antenna RSSI value
+	 */
 	QCA_WLAN_VENDOR_ATTR_CHAIN_INDEX = 26,
 	/* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
-	 * to report the specific antenna RSSI value (unsigned 32 bit value) */
+	 * to report the specific antenna RSSI value (unsigned 32 bit value)
+	 */
 	QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI = 27,
 	/* Frequency in MHz, various uses. Unsigned 32 bit value */
 	QCA_WLAN_VENDOR_ATTR_FREQ = 28,
@@ -642,7 +813,8 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_BRP_ANT_NUM_LIMIT = 39,
 	/* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
-	 * to report the corresponding antenna index to the chain RSSI value */
+	 * to report the corresponding antenna index to the chain RSSI value
+	 */
 	QCA_WLAN_VENDOR_ATTR_ANTENNA_INFO = 40,
 
 	/* keep last */
@@ -650,7 +822,6 @@
 	QCA_WLAN_VENDOR_ATTR_MAX	= QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
 };
 
-
 enum qca_roaming_policy {
 	QCA_ROAMING_NOT_ALLOWED,
 	QCA_ROAMING_ALLOWED_WITHIN_ESS,
@@ -778,7 +949,7 @@
  * @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
  *	band selection based on channel selection results.
  * @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports
- * 	simultaneous off-channel operations.
+ *	simultaneous off-channel operations.
  * @QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P
  *	Listen offload; a mechanism where the station's firmware takes care of
  *	responding to incoming Probe Request frames received from other P2P
@@ -794,6 +965,8 @@
  *	%QCA_WLAN_VENDOR_FEATURE_OCE_AP, the userspace shall assume that
  *	this Device may not support all OCE AP functionalities but can support
  *	only OCE STA-CFON functionalities.
+ * @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
+ *	managed regulatory.
  * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
  */
 enum qca_wlan_vendor_features {
@@ -804,6 +977,7 @@
 	QCA_WLAN_VENDOR_FEATURE_OCE_STA                 = 4,
 	QCA_WLAN_VENDOR_FEATURE_OCE_AP                  = 5,
 	QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON            = 6,
+	QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
 	NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
 };
 
@@ -947,6 +1121,12 @@
 	 * from kernel space to user space.
 	 */
 	QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST,
+	/* An array of nested values as per enum qca_wlan_vendor_attr_pcl
+	 * attribute. Each element contains frequency (MHz), weight, and flag
+	 * bit mask indicating how the frequency should be used in P2P
+	 * negotiation; sent from kernel space to user space.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL,
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX =
@@ -1127,16 +1307,16 @@
  * @QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES: Nested array attribute of supported
  *	rates to be included
  * @QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE: flag used to send probe requests
- * 	at non CCK rate in 2GHz band
+ *	at non CCK rate in 2GHz band
  * @QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS: Unsigned 32-bit scan flags
  * @QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE: Unsigned 64-bit cookie provided by the
- * 	driver for the specific scan request
+ *	driver for the specific scan request
  * @QCA_WLAN_VENDOR_ATTR_SCAN_STATUS: Unsigned 8-bit status of the scan
- * 	request decoded as in enum scan_status
+ *	request decoded as in enum scan_status
  * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC: 6-byte MAC address to use when randomisation
- * 	scan flag is set
+ *	scan flag is set
  * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with
- * 	randomisation
+ *	randomisation
  * @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
  *	specific BSSID to scan for.
  */
@@ -1160,10 +1340,10 @@
 
 /**
  * enum scan_status - Specifies the valid values the vendor scan attribute
- * 	QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take
+ *	QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take
  *
  * @VENDOR_SCAN_STATUS_NEW_RESULTS: implies the vendor scan is successful with
- * 	new scan results
+ *	new scan results
  * @VENDOR_SCAN_STATUS_ABORTED: implies the vendor scan was aborted in-between
  */
 enum scan_status {
@@ -1210,7 +1390,8 @@
 enum qca_vendor_attr_txpower_decr_db {
 	QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_INVALID,
 	/* 8-bit unsigned value to indicate the reduction of TX power in dB for
-	 * a virtual interface. */
+	 * a virtual interface.
+	 */
 	QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB,
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST,
@@ -1260,29 +1441,37 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND = 7,
 	/* 8-bit unsigned value to configure the maximum TX MPDU for
-	 * aggregation. */
+	 * aggregation.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION = 8,
 	/* 8-bit unsigned value to configure the maximum RX MPDU for
-	 * aggregation. */
+	 * aggregation.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION = 9,
 	/* 8-bit unsigned value to configure the Non aggregrate/11g sw
-	 * retry threshold (0 disable, 31 max). */
+	 * retry threshold (0 disable, 31 max).
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY = 10,
 	/* 8-bit unsigned value to configure the aggregrate sw
-	 * retry threshold (0 disable, 31 max). */
+	 * retry threshold (0 disable, 31 max).
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY = 11,
 	/* 8-bit unsigned value to configure the MGMT frame
-	 * retry threshold (0 disable, 31 max). */
+	 * retry threshold (0 disable, 31 max).
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY = 12,
 	/* 8-bit unsigned value to configure the CTRL frame
-	 * retry threshold (0 disable, 31 max). */
+	 * retry threshold (0 disable, 31 max).
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY = 13,
 	/* 8-bit unsigned value to configure the propagation delay for
-	 * 2G/5G band (0~63, units in us) */
+	 * 2G/5G band (0~63, units in us)
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY = 14,
 	/* Unsigned 32-bit value to configure the number of unicast TX fail
 	 * packet count. The peer is disconnected once this threshold is
-	 * reached. */
+	 * reached.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT = 15,
 	/* Attribute used to set scan default IEs to the driver.
 	 *
@@ -1293,7 +1482,8 @@
 	 * merged with the IEs received along with scan request coming to the
 	 * driver. If a particular IE is present in the scan default IEs but not
 	 * present in the scan request, then that IE should be added to the IEs
-	 * sent in the Probe Request frames for that scan request. */
+	 * sent in the Probe Request frames for that scan request.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES = 16,
 	/* Unsigned 32-bit attribute for generic commands */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND = 17,
@@ -1302,41 +1492,50 @@
 	/* Unsigned 32-bit data attribute for generic command response */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA = 19,
 	/* Unsigned 32-bit length attribute for
-	 * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+	 * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH = 20,
 	/* Unsigned 32-bit flags attribute for
-	 * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+	 * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS = 21,
 	/* Unsigned 32-bit, defining the access policy.
 	 * See enum qca_access_policy. Used with
-	 * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST. */
+	 * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY = 22,
 	/* Sets the list of full set of IEs for which a specific access policy
 	 * has to be applied. Used along with
 	 * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access.
-	 * Zero length payload can be used to clear this access constraint. */
+	 * Zero length payload can be used to clear this access constraint.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST = 23,
 	/* Unsigned 32-bit, specifies the interface index (netdev) for which the
 	 * corresponding configurations are applied. If the interface index is
 	 * not specified, the configurations are attributed to the respective
-	 * wiphy. */
+	 * wiphy.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX = 24,
 	/* 8-bit unsigned value to trigger QPower: 1-Enable, 0-Disable */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25,
 	/* 8-bit unsigned value to configure the driver and below layers to
 	 * ignore the assoc disallowed set by APs while connecting
-	 * 1-Ignore, 0-Don't ignore */
+	 * 1-Ignore, 0-Don't ignore
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED = 26,
 	/* 32-bit unsigned value to trigger antenna diversity features:
-	 * 1-Enable, 0-Disable */
+	 * 1-Enable, 0-Disable
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA = 27,
 	/* 32-bit unsigned value to configure specific chain antenna */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN = 28,
 	/* 32-bit unsigned value to trigger cycle selftest
-	 * 1-Enable, 0-Disable */
+	 * 1-Enable, 0-Disable
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST = 29,
 	/* 32-bit unsigned to configure the cycle time of selftest
-	 * the unit is micro-second */
+	 * the unit is micro-second
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL = 30,
 	/* 32-bit unsigned value to set reorder timeout for AC_VO */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VOICE = 31,
@@ -1360,10 +1559,12 @@
 	 * NL80211_CHAN_WIDTH_10 means 10 MHz. If set, the device work in 5 or
 	 * 10 MHz channel width, the station will not connect to a BSS using 20
 	 * MHz or higher bandwidth. Set to NL80211_CHAN_WIDTH_20_NOHT to
-	 * clear this constraint. */
+	 * clear this constraint.
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_SUB20_CHAN_WIDTH = 39,
 	/* 32-bit unsigned value to configure the propagation absolute delay
-	 * for 2G/5G band (units in us) */
+	 * for 2G/5G band (units in us)
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_ABS_DELAY = 40,
 	/* 32-bit unsigned value to set probe period */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_PERIOD = 41,
@@ -1431,7 +1632,7 @@
 	QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE = 51,
 
 	/* 8-bit unsigned value to set the total beacon miss count
-	 * This paramater will set the total beacon miss count.
+	 * This parameter will set the total beacon miss count.
 	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT = 52,
 
@@ -1443,9 +1644,32 @@
 
 	/* 8-bit unsigned value to configure the driver and below layers to
 	 * enable/disable all FILS features.
-	 * 0-enable, 1-disable */
+	 * 0-enable, 1-disable
+	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS = 54,
 
+	/* 16-bit unsigned value to configure the level of WLAN latency
+	 * module. See enum qca_wlan_vendor_attr_config_latency_level.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL = 55,
+
+	/* 8-bit unsigned value indicating the driver to use the RSNE as-is from
+	 * the connect interface. Exclusively used for the scenarios where the
+	 * device is used as a test bed device with special functionality and
+	 * not recommended for production. This helps driver to not validate the
+	 * RSNE passed from user space and thus allow arbitrary IE data to be
+	 * used for testing purposes.
+	 * 1-enable, 0-disable.
+	 * Applications set/reset this configuration. If not reset, this
+	 * parameter remains in use until the driver is unloaded.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE = 56,
+
+	/* 8-bit unsigned value to trigger green Tx power saving.
+	 * 1-Enable, 0-Disable
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -1478,7 +1702,8 @@
 enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
 	QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0,
 	/* Priority based frequency list (an array of u32 values in host byte
-	 * order) */
+	 * order)
+	 */
 	QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1,
 	/* Status of the conditional switch (u32).
 	 * 0: Success, Non-zero: Failure
@@ -1513,6 +1738,36 @@
 };
 
 /**
+ * qca_wlan_set_qdepth_thresh_attr - Parameters for setting
+ * MSDUQ depth threshold per peer per tid in the target
+ *
+ * Associated Vendor Command:
+ * QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH
+ */
+enum qca_wlan_set_qdepth_thresh_attr {
+	QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_INVALID = 0,
+	/* 6-byte MAC address */
+	QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_MAC_ADDR,
+	/* Unsigned 32-bit attribute for holding the TID */
+	QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_TID,
+	/* Unsigned 32-bit attribute for holding the update mask
+	 * bit 0 - Update high priority msdu qdepth threshold
+	 * bit 1 - Update low priority msdu qdepth threshold
+	 * bit 2 - Update UDP msdu qdepth threshold
+	 * bit 3 - Update Non UDP msdu qdepth threshold
+	 * rest of bits are reserved
+	 */
+	QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_UPDATE_MASK,
+	/* Unsigned 32-bit attribute for holding the threshold value */
+	QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_VALUE,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_LAST,
+	QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_MAX =
+		QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_LAST - 1,
+};
+
+/**
  * enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
  */
 enum qca_wlan_vendor_attr_get_hw_capability {
@@ -1684,6 +1939,12 @@
  * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF: per antenna NF value
  * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON: RSSI of beacon
  * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON: SNR of beacon
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME: u64
+ *    Absolute timestamp from 1970/1/1, unit in ms. After receiving the
+ *    message, user layer APP could call gettimeofday to get another
+ *    timestamp and calculate transfer delay for the message.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME: u32
+ *    Real period for this measurement, unit in us.
  */
 enum qca_wlan_vendor_attr_ll_stats_ext {
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0,
@@ -1777,6 +2038,9 @@
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON,
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON,
 
+	QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME,
+	QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME,
+
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST,
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX =
 		QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1
@@ -1830,7 +2094,7 @@
  * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver
  *	can run FTM sessions. QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION
  *	will be supported if set.
-* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
  *	supports immediate (ASAP) response.
  * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone
  *	AOA measurement using QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS.
@@ -2393,13 +2657,13 @@
 	/* Unsigned int 8 bit value; 0:20 MHz, 1:40 MHz, 2:80 MHz, 3:160 MHz */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW = 40,
 	/* Unsigned int 8 bit value; OFDM/CCK rate code would be as per IEEE Std
-	 * in the units of 0.5 Mbps HT/VHT it would be MCS index */
+	 * in the units of 0.5 Mbps HT/VHT it would be MCS index
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX = 41,
 
 	/* Unsigned 32 bit value. Bit rate in units of 100 kbps */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE = 42,
 
-
 	/* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_STAT_* could be
 	 * nested within the peer info stats.
 	 */
@@ -2558,14 +2822,18 @@
 	/* Unsigned 32 bit value */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT = 82,
 
+	/* Unsigned int 32 value.
+	 * Pending MSDUs corresponding to respective AC.
+	 */
+	QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_PENDING_MSDU = 83,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST - 1,
 };
 
-enum qca_wlan_vendor_attr_ll_stats_type
-{
+enum qca_wlan_vendor_attr_ll_stats_type {
 	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_INVALID = 0,
 	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO = 1,
 	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE = 2,
@@ -2682,10 +2950,14 @@
  *	limit feature.
  * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: Select the SAR power
  *	limits configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0: Select the SAR power
+ *	limits version 2.0 configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
  *
  * This enumerates the valid set of values that may be supplied for
  * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT in an instance of
- * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command.
+ * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command or in
+ * the response to an instance of the
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS vendor command.
  */
 enum qca_vendor_attr_sar_limits_selections {
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 = 0,
@@ -2695,6 +2967,7 @@
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4 = 4,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE = 5,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER = 6,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0 = 7,
 };
 
 /**
@@ -2709,7 +2982,8 @@
  * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION in an
  * instance of attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC in an
  * instance of the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor
- * command.
+ * command or in the response to an instance of the
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS vendor command.
  */
 enum qca_vendor_attr_sar_limits_spec_modulations {
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK = 0,
@@ -2740,7 +3014,12 @@
  *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN, and
  *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION and always
  *	contains as a payload the attribute
- *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT.
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT,
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX.
+ *	Either %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT or
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX is
+ *	needed based upon the value of
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE.
  *
  * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND: Optional (u32) value to
  *	indicate for which band this specification applies. Valid
@@ -2765,8 +3044,16 @@
  * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT: Required (u32)
  *	value to specify the actual power limit value in units of 0.5
  *	dBm (i.e., a value of 11 represents 5.5 dBm).
+ *	This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER.
  *
- * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX: Required (u32)
+ *	value to indicate SAR V2 indices (0 - 11) to select SAR V2 profiles.
+ *	This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0.
+ *
+ * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS
+ * and %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS.
  */
 enum qca_vendor_attr_sar_limits {
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_INVALID = 0,
@@ -2777,6 +3064,7 @@
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN = 5,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION = 6,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT = 7,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX = 8,
 
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX =
@@ -2824,7 +3112,7 @@
 
 	/* Unsigned 32-bit value; used to indicate the size of memory
 	 * dump to be allocated.
-	*/
+	 */
 	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE = 2,
 
 	/* keep last */
@@ -3255,6 +3543,14 @@
 
 	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED = 45,
 
+	/* Unsigned 32-bit value; a GSCAN Capabilities attribute.
+	 * This is used to limit the maximum number of BSSIDs while sending
+	 * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with attributes
+	 * QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID and
+	 * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX =
@@ -3528,7 +3824,8 @@
 /**
  * qca_wlan_vendor_attr_pcl: Represents attributes for
  * preferred channel list (PCL). These attributes are sent as part of
- * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL.
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL and
+ * QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST.
  */
 enum qca_wlan_vendor_attr_pcl {
 	QCA_WLAN_VENDOR_ATTR_PCL_INVALID = 0,
@@ -3537,6 +3834,17 @@
 	QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL = 1,
 	/* Channel weightage (u8) */
 	QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT = 2,
+	/* Channel frequency (u32) in MHz */
+	QCA_WLAN_VENDOR_ATTR_PCL_FREQ = 3,
+	/* Channel flags (u32)
+	 * bit 0 set: channel to be used for GO role,
+	 * bit 1 set: channel to be used on CLI role,
+	 * bit 2 set: channel must be considered for operating channel
+	 *                 selection & peer chosen operating channel should be
+	 *                 one of the channels with this flag set,
+	 * bit 3 set: channel should be excluded in GO negotiation
+	 */
+	QCA_WLAN_VENDOR_ATTR_PCL_FLAG = 4,
 };
 
 /**
@@ -3556,12 +3864,14 @@
 	/* Flag attribute to indicate if 11ac is offloaded to firmware */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_OFFLOAD_ENABLED = 3,
 	/* Flag attribute to indicate if driver provides additional channel
-	 * capability as part of scan operation */
+	 * capability as part of scan operation
+	 */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_ADD_CHAN_STATS_SUPPORT = 4,
 	/* Flag attribute to indicate interface status is UP */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AP_UP = 5,
 	/* Operating mode (u8) of interface. Takes one of enum nl80211_iftype
-	 * values. */
+	 * values.
+	 */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_SAP_MODE = 6,
 	/* Channel width (u8). It takes one of enum nl80211_chan_width values.
 	 * This is the upper bound of channel width. ACS logic should try to get
@@ -3572,7 +3882,8 @@
 	/* This (u8) will hold values of one of enum nl80211_bands */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_BAND = 8,
 	/* PHY/HW mode (u8). Takes one of enum qca_wlan_vendor_acs_hw_mode
-	 * values */
+	 * values
+	 */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PHY_MODE = 9,
 	/* Array of (u32) supported frequency list among which ACS should choose
 	 * best frequency.
@@ -3591,6 +3902,11 @@
 	 * qca_wlan_vendor_attr_external_acs_policy.
 	 */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_POLICY = 13,
+	/* Reference RF Operating Parameter (RROP) availability information
+	 * (u16). It uses values defined in enum
+	 * qca_wlan_vendor_attr_rropavail_info.
+	 */
+	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_RROPAVAIL_INFO = 14,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
@@ -3642,10 +3958,10 @@
 	/* Indicates if the reason for the failure is due to a protocol
 	 * layer/module.
 	 */
-        QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL = 0,
+	QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL = 0,
 	/* Indicates if the reason for the failure is due to a hardware issue.
 	 */
-        QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE = 1,
+	QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE = 1,
 };
 
 /**
@@ -3654,17 +3970,70 @@
  * information leading to the power save failure.
  */
 enum qca_attr_chip_power_save_failure {
-        QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID = 0,
-        /* Reason to cause the power save failure.
+	QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID = 0,
+	/* Reason to cause the power save failure.
 	 * These reasons are represented by
 	 * enum qca_chip_power_save_failure_reason.
 	 */
-        QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON = 1,
+	QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON = 1,
 
-        /* keep last */
-        QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST,
-        QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX =
-                QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST - 1,
+	/* keep last */
+	QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST,
+	QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX =
+		QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_nud_stats_data_pkt_flags: Flag representing the various
+ * data types for which the stats have to get collected.
+ */
+enum qca_wlan_vendor_nud_stats_data_pkt_flags {
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_ARP = 1 << 0,
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_DNS = 1 << 1,
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_HANDSHAKE = 1 << 2,
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_ICMPV4 = 1 << 3,
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_ICMPV6 = 1 << 4,
+	/* Used by QCA_ATTR_NUD_STATS_PKT_TYPE only in nud stats get
+	 * to represent the stats of respective data type.
+	 */
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_SYN = 1 << 5,
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_SYN_ACK = 1 << 6,
+	QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_ACK = 1 << 7,
+};
+
+enum qca_wlan_vendor_nud_stats_set_data_pkt_info {
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_INVALID = 0,
+	/* Represents the data packet type to be monitored (u32).
+	 * Host driver tracks the stats corresponding to each data frame
+	 * represented by these flags.
+	 * These data packets are represented by
+	 * enum qca_wlan_vendor_nud_stats_data_pkt_flags
+	 */
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_TYPE = 1,
+	/* Name corresponding to the DNS frame for which the respective DNS
+	 * stats have to get monitored (string). Max string length 255.
+	 */
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DNS_DOMAIN_NAME = 2,
+	/* source port on which the respective proto stats have to get
+	 * collected (u32).
+	 */
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_SRC_PORT = 3,
+	/* destination port on which the respective proto stats have to get
+	 * collected (u32).
+	 */
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_PORT = 4,
+	/* IPv4 address for which the destined data packets have to be
+	 * monitored. (in network byte order), u32.
+	 */
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV4 = 5,
+	/* IPv6 address for which the destined data packets have to be
+	 * monitored. (in network byte order), 16 bytes array.
+	 */
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV6 = 6,
+
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_LAST,
+	QCA_ATTR_NUD_STATS_DATA_PKT_INFO_MAX =
+		QCA_ATTR_NUD_STATS_DATA_PKT_INFO_LAST - 1,
 };
 
 /**
@@ -3679,8 +4048,15 @@
 	 * Start - If included, Stop - If not included
 	 */
 	QCA_ATTR_NUD_STATS_SET_START = 1,
-	/* IPv4 address of the default gateway (in network byte order) */
+	/* IPv4 address of the default gateway (in network byte order), u32 */
 	QCA_ATTR_NUD_STATS_GW_IPV4 = 2,
+	/* Represents the list of data packet types to be monitored.
+	 * Host driver tracks the stats corresponding to each data frame
+	 * represented by these flags.
+	 * These data packets are represented by
+	 * enum qca_wlan_vendor_nud_stats_set_data_pkt_info
+	 */
+	QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO = 3,
 
 	/* keep last */
 	QCA_ATTR_NUD_STATS_SET_LAST,
@@ -3688,6 +4064,58 @@
 		QCA_ATTR_NUD_STATS_SET_LAST - 1,
 };
 
+enum qca_attr_nud_data_stats {
+	QCA_ATTR_NUD_DATA_STATS_INVALID = 0,
+	/* Data packet type for which the stats are collected (u32).
+	 * Represented by enum qca_wlan_vendor_nud_stats_data_pkt_flags
+	 */
+	QCA_ATTR_NUD_STATS_PKT_TYPE = 1,
+	/* Name corresponding to the DNS frame for which the respective DNS
+	 * stats are monitored (string). Max string length 255.
+	 */
+	QCA_ATTR_NUD_STATS_PKT_DNS_DOMAIN_NAME = 2,
+	/* source port on which the respective proto stats are collected (u32).
+	 */
+	QCA_ATTR_NUD_STATS_PKT_SRC_PORT = 3,
+	/* destination port on which the respective proto stats are collected
+	 * (u32).
+	 */
+	QCA_ATTR_NUD_STATS_PKT_DEST_PORT = 4,
+	/* IPv4 address for which the destined data packets have to be
+	 * monitored. (in network byte order), u32.
+	 */
+	QCA_ATTR_NUD_STATS_PKT_DEST_IPV4 = 5,
+	/* IPv6 address for which the destined data packets have to be
+	 * monitored. (in network byte order), 16 bytes array.
+	 */
+	QCA_ATTR_NUD_STATS_PKT_DEST_IPV6 = 6,
+	/* Data packet Request count received from netdev (u32). */
+	QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_FROM_NETDEV = 7,
+	/* Data packet Request count sent to lower MAC from upper MAC (u32). */
+	QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TO_LOWER_MAC = 8,
+	/* Data packet Request count received by lower MAC from upper MAC
+	 * (u32)
+	 */
+	QCA_ATTR_NUD_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC = 9,
+	/* Data packet Request count successfully transmitted by the device
+	 * (u32)
+	 */
+	QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TX_SUCCESS = 10,
+	/* Data packet Response count received by lower MAC (u32) */
+	QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC = 11,
+	/* Data packet Response count received by upper MAC (u32) */
+	QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC = 12,
+	/* Data packet Response count delivered to netdev (u32) */
+	QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_TO_NETDEV = 13,
+	/* Data Packet Response count that are dropped out of order (u32) */
+	QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP = 14,
+
+	/* keep last */
+	QCA_ATTR_NUD_DATA_STATS_LAST,
+	QCA_ATTR_NUD_DATA_STATS_MAX =
+		QCA_ATTR_NUD_DATA_STATS_LAST - 1,
+};
+
 /**
  * qca_attr_nud_stats_get: Attributes to vendor subcmd
  * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carries the requisite
@@ -3695,21 +4123,21 @@
  */
 enum qca_attr_nud_stats_get {
 	QCA_ATTR_NUD_STATS_GET_INVALID = 0,
-	/* ARP Request count from netdev */
+	/* ARP Request count from netdev (u32) */
 	QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1,
-	/* ARP Request count sent to lower MAC from upper MAC */
+	/* ARP Request count sent to lower MAC from upper MAC (u32) */
 	QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2,
-	/* ARP Request count received by lower MAC from upper MAC */
+	/* ARP Request count received by lower MAC from upper MAC (u32) */
 	QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3,
-	/* ARP Request count successfully transmitted by the device */
+	/* ARP Request count successfully transmitted by the device (u32) */
 	QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4,
-	/* ARP Response count received by lower MAC */
+	/* ARP Response count received by lower MAC (u32) */
 	QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5,
-	/* ARP Response count received by upper MAC */
+	/* ARP Response count received by upper MAC (u32) */
 	QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6,
-	/* ARP Response count delivered to netdev */
+	/* ARP Response count delivered to netdev (u32) */
 	QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7,
-	/* ARP Response count delivered to netdev */
+	/* ARP Response count dropped due to out of order reception (u32) */
 	QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8,
 	/* Flag indicating if the station's link to the AP is active.
 	 * Active Link - If included, Inactive link - If not included
@@ -3719,6 +4147,11 @@
 	 * Yes - If detected, No - If not detected.
 	 */
 	QCA_ATTR_NUD_STATS_IS_DAD = 10,
+	/* List of Data packet types for which the stats are requested.
+	 * This list does not carry ARP stats as they are done by the
+	 * above attributes. Represented by enum qca_attr_nud_data_stats.
+	 */
+	QCA_ATTR_NUD_STATS_DATA_PKT_STATS = 11,
 
 	/* keep last */
 	QCA_ATTR_NUD_STATS_GET_LAST,
@@ -3784,7 +4217,8 @@
 enum qca_wlan_vendor_attr_get_he_capabilities {
 	QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0,
 	/* Whether HE capabilities is supported
-	 * (u8 attribute: 0 = not supported, 1 = supported) */
+	 * (u8 attribute: 0 = not supported, 1 = supported)
+	 */
 	QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED = 1,
 	/* HE PHY capabilities, array of 3 u32 values  */
 	QCA_WLAN_VENDOR_ATTR_PHY_CAPAB = 2,
@@ -3895,12 +4329,138 @@
 	 * specific scan to be stopped.
 	 */
 	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE = 19,
+	/* Skip interval for FFT reports. u32 attribute */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD = 20,
+	/* Set to report only one set of FFT results.
+	 * u32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT = 21,
+	/* Debug level for spectral module in driver.
+	 * 0 : Verbosity level 0
+	 * 1 : Verbosity level 1
+	 * 2 : Verbosity level 2
+	 * 3 : Matched filterID display
+	 * 4 : One time dump of FFT report
+	 * u32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL = 22,
+	/* Type of spectral scan request. u32 attribute.
+	 * It uses values defined in enum
+	 * qca_wlan_vendor_attr_spectral_scan_request_type.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE = 23,
 
 	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_vendor_attr_spectral_diag_stats - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS.
+ */
+enum qca_wlan_vendor_attr_spectral_diag_stats {
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_INVALID = 0,
+	/* Number of spectral TLV signature mismatches.
+	 * u64 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SIG_MISMATCH = 1,
+	/* Number of spectral phyerror events with insufficient length when
+	 * parsing for secondary 80 search FFT report. u64 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SEC80_SFFT_INSUFFLEN = 2,
+	/* Number of spectral phyerror events without secondary 80
+	 * search FFT report. u64 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_NOSEC80_SFFT = 3,
+	/* Number of spectral phyerror events with vht operation segment 1 id
+	 * mismatches in search fft report. u64 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG1ID_MISMATCH = 4,
+	/* Number of spectral phyerror events with vht operation segment 2 id
+	 * mismatches in search fft report. u64 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH = 5,
+
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX =
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_cap - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO.
+ */
+enum qca_wlan_vendor_attr_spectral_cap {
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_INVALID = 0,
+	/* Flag attribute to indicate phydiag capability */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_PHYDIAG = 1,
+	/* Flag attribute to indicate radar detection capability */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RADAR = 2,
+	/* Flag attribute to indicate spectral capability */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_SPECTRAL = 3,
+	/* Flag attribute to indicate advanced spectral capability */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_ADVANCED_SPECTRAL = 4,
+	/* Spectral hardware generation. u32 attribute.
+	 * It uses values defined in enum
+	 * qca_wlan_vendor_spectral_scan_cap_hw_gen.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN = 5,
+
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_scan_status - used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS.
+ */
+enum qca_wlan_vendor_attr_spectral_scan_status {
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_INVALID = 0,
+	/* Flag attribute to indicate whether spectral scan is enabled */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ENABLED = 1,
+	/* Flag attribute to indicate whether spectral scan is in progress*/
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE = 2,
+
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX =
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_spectral_scan_request_type: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START. This represents the
+ * spectral scan request types.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN_AND_CONFIG: Request to
+ * set the spectral parameters and start scan.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN: Request to
+ * only set the spectral parameters.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG: Request to
+ * only start the spectral scan.
+ */
+enum qca_wlan_vendor_attr_spectral_scan_request_type {
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN_AND_CONFIG,
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN,
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG,
+};
+
+/**
+ * qca_wlan_vendor_spectral_scan_cap_hw_gen: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO. This represents the
+ * spectral hardware generation.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_1: generation 1
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_2: generation 2
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_3: generation 3
+ */
+enum qca_wlan_vendor_spectral_scan_cap_hw_gen {
+	QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_1 = 0,
+	QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_2 = 1,
+	QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_3 = 2,
+};
+
 enum qca_wlan_vendor_tos {
 	QCA_WLAN_VENDOR_TOS_BK = 0,
 	QCA_WLAN_VENDOR_TOS_BE = 1,
@@ -3969,4 +4529,1465 @@
 		QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_vendor_attr_flush_pending - Attributes for
+ * flushing pending traffic in firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_ADDR: Configure peer MAC address.
+ * @QCA_WLAN_VENDOR_ATTR_AC: Configure access category of the pending
+ * packets. It is u8 value with bit 0~3 represent AC_BE, AC_BK,
+ * AC_VI, AC_VO respectively. Set the corresponding bit to 1 to
+ * flush packets with access category.
+ */
+enum qca_wlan_vendor_attr_flush_pending {
+	QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_PEER_ADDR = 1,
+	QCA_WLAN_VENDOR_ATTR_AC = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX =
+	QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rropavail_info - Specifies whether Representative
+ * RF Operating Parameter (RROP) information is available, and if so, at which
+ * point in the application-driver interaction sequence it can be retrieved by
+ * the application from the driver. This point may vary by architecture and
+ * other factors. This is a u16 value.
+ */
+enum qca_wlan_vendor_attr_rropavail_info {
+	/* RROP information is unavailable. */
+	QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_UNAVAILABLE,
+	/* RROP information is available and the application can retrieve the
+	 * information after receiving an QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS
+	 * event from the driver.
+	 */
+	QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_EXTERNAL_ACS_START,
+	/* RROP information is available only after a vendor specific scan
+	 * (requested using QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN) has
+	 * successfully completed. The application can retrieve the information
+	 * after receiving the QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE event from
+	 * the driver.
+	 */
+	QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_VSCAN_END,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rrop_info - Specifies vendor specific
+ * Representative RF Operating Parameter (RROP) information. It is sent for the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO. This information is
+ * intended for use by external Auto Channel Selection applications. It provides
+ * guidance values for some RF parameters that are used by the system during
+ * operation. These values could vary by channel, band, radio, and so on.
+ */
+enum qca_wlan_vendor_attr_rrop_info {
+	QCA_WLAN_VENDOR_ATTR_RROP_INFO_INVALID = 0,
+
+	/* Representative Tx Power List (RTPL) which has an array of nested
+	 * values as per attributes in enum qca_wlan_vendor_attr_rtplinst.
+	 */
+	QCA_WLAN_VENDOR_ATTR_RROP_INFO_RTPL = 1,
+
+	QCA_WLAN_VENDOR_ATTR_RROP_INFO_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_RROP_INFO_MAX =
+	QCA_WLAN_VENDOR_ATTR_RROP_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rtplinst - Specifies attributes for individual list
+ * entry instances in the Representative Tx Power List (RTPL). It provides
+ * simplified power values intended for helping external Auto channel Selection
+ * applications compare potential Tx power performance between channels, other
+ * operating conditions remaining identical. These values are not necessarily
+ * the actual Tx power values that will be used by the system. They are also not
+ * necessarily the max or average values that will be used. Instead, they are
+ * relative, summarized keys for algorithmic use computed by the driver or
+ * underlying firmware considering a number of vendor specific factors.
+ */
+enum qca_wlan_vendor_attr_rtplinst {
+	QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0,
+
+	/* Primary channel number (u8) */
+	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,
+
+	QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX =
+		QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_latency_level - Level for
+ * wlan latency module.
+ *
+ * There will be various of Wi-Fi functionality like scan/roaming/adaptive
+ * power saving which would causing data exchange out of service, this
+ * would be a big impact on latency. For latency sensitive applications over
+ * Wi-Fi are intolerant to such operations and thus would configure them
+ * to meet their respective needs. It is well understood by such applications
+ * that altering the default behavior would degrade the Wi-Fi functionality
+ * w.r.t the above pointed WLAN operations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL:
+ *	Default WLAN operation level which throughput orientated.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE:
+ *	Use moderate level to improve latency by limit scan duration.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW:
+ *	Use low latency level to benifit application like concurrent
+ *	downloading or video streaming via constraint scan/adaptive PS.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW:
+ *	Use ultra low latency level to benefit for gaming/voice
+ *	application via constraint scan/roaming/adaptive PS.
+ */
+enum qca_wlan_vendor_attr_config_latency_level {
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL = 1,
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE = 2,
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW = 3,
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW = 4,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MAX =
+	QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_wlan_mac - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO.
+ */
+enum qca_wlan_vendor_attr_mac {
+	QCA_WLAN_VENDOR_ATTR_MAC_INVALID = 0,
+
+	/* MAC mode info list which has an array of nested values as
+	 * per attributes in enum qca_wlan_vendor_attr_mac_mode_info.
+	 */
+	QCA_WLAN_VENDOR_ATTR_MAC_INFO = 1,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_MAC_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_MAC_MAX =
+	QCA_WLAN_VENDOR_ATTR_MAC_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mac_iface_info - Information of the connected
+ *	Wi-Fi netdev interface on a respective MAC.
+ *	Used by the attribute QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO.
+ */
+enum qca_wlan_vendor_attr_mac_iface_info {
+	QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_INVALID = 0,
+	/* Wi-Fi netdev's interface index (u32) */
+	QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX = 1,
+	/* Associated frequency in MHz of the connected Wi-Fi interface (u32) */
+	QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX =
+	QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mac_info - Points to MAC the information.
+ *	Used by the attribute QCA_WLAN_VENDOR_ATTR_MAC_INFO of the
+ *	vendor command QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO.
+ */
+enum qca_wlan_vendor_attr_mac_info {
+	QCA_WLAN_VENDOR_ATTR_MAC_INFO_INVALID = 0,
+	/* Hardware MAC ID associated for the MAC (u32) */
+	QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID = 1,
+	/* Band supported by the MAC at a given point.
+	 * This is a u32 bitmask of BIT(NL80211_BAND_*) as described in %enum
+	 * nl80211_band.
+	 */
+	QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND = 2,
+	/* Refers to list of WLAN netdev interfaces associated with this MAC.
+	 * Represented by enum qca_wlan_vendor_attr_mac_iface_info.
+	 */
+	QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO = 3,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_MAC_INFO_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX =
+	QCA_WLAN_VENDOR_ATTR_MAC_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_logger_features - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET.
+ */
+enum qca_wlan_vendor_attr_get_logger_features {
+	QCA_WLAN_VENDOR_ATTR_LOGGER_INVALID = 0,
+	/* Unsigned 32-bit enum value of wifi_logger_supported_features */
+	QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED = 1,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_LOGGER_MAX =
+		QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST - 1,
+};
+
+/**
+ * enum wifi_logger_supported_features - Values for supported logger features
+ */
+enum wifi_logger_supported_features {
+	WIFI_LOGGER_MEMORY_DUMP_FEATURE = (1 << (0)),
+	WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_FEATURE = (1 << (1)),
+	WIFI_LOGGER_CONNECT_EVENT_FEATURE = (1 << (2)),
+	WIFI_LOGGER_POWER_EVENT_FEATURE = (1 << (3)),
+	WIFI_LOGGER_WAKE_LOCK_FEATURE = (1 << (4)),
+	WIFI_LOGGER_VERBOSE_FEATURE = (1 << (5)),
+	WIFI_LOGGER_WATCHDOG_TIMER_FEATURE = (1 << (6)),
+	WIFI_LOGGER_DRIVER_DUMP_FEATURE = (1 << (7)),
+	WIFI_LOGGER_PACKET_FATE_FEATURE = (1 << (8)),
+};
+
+/**
+ * enum qca_wlan_tdls_caps_features_supported - Values for TDLS get
+ * capabilities features
+ */
+enum qca_wlan_tdls_caps_features_supported {
+	WIFI_TDLS_SUPPORT = (1 << (0)),
+	WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT = (1 << (1)),
+	WIFI_TDLS_OFFCHANNEL_SUPPORT = (1 << (2))
+};
+
+/**
+ * enum qca_wlan_vendor_attr_tdls_get_capabilities - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES.
+ */
+enum qca_wlan_vendor_attr_tdls_get_capabilities {
+	QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_INVALID = 0,
+	/* Indicates the max concurrent sessions */
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS,
+	/* Indicates the support for features */
+	/* Unsigned 32-bit bitmap qca_wlan_tdls_caps_features_supported
+	 */
+	QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX =
+		QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_offloaded_packets_sending_control - Offload packets control
+ * command used as value for the attribute
+ * QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL.
+ */
+enum qca_wlan_offloaded_packets_sending_control {
+	QCA_WLAN_OFFLOADED_PACKETS_SENDING_CONTROL_INVALID = 0,
+	QCA_WLAN_OFFLOADED_PACKETS_SENDING_START,
+	QCA_WLAN_OFFLOADED_PACKETS_SENDING_STOP
+};
+
+/**
+ * enum qca_wlan_vendor_attr_offloaded_packets - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS.
+ */
+enum qca_wlan_vendor_attr_offloaded_packets {
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_INVALID = 0,
+	/* Takes valid value from the enum
+	 * qca_wlan_offloaded_packets_sending_control
+	 * Unsigned 32-bit value
+	 */
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID,
+	/* array of u8 len: Max packet size */
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA,
+	/* 6-byte MAC address used to represent source MAC address */
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR,
+	/* 6-byte MAC address used to represent destination MAC address */
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR,
+	/* Unsigned 32-bit value, in milli seconds */
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX =
+		QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_rssi_monitoring_control - RSSI control commands used as values
+ * by the attribute QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL.
+ */
+enum qca_wlan_rssi_monitoring_control {
+	QCA_WLAN_RSSI_MONITORING_CONTROL_INVALID = 0,
+	QCA_WLAN_RSSI_MONITORING_START,
+	QCA_WLAN_RSSI_MONITORING_STOP,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rssi_monitoring - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI.
+ */
+enum qca_wlan_vendor_attr_rssi_monitoring {
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_INVALID = 0,
+	/* Takes valid value from the enum
+	 * qca_wlan_rssi_monitoring_control
+	 * Unsigned 32-bit value enum qca_wlan_rssi_monitoring_control
+	 */
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
+	/* Unsigned 32-bit value */
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
+	/* Signed 8-bit value in dBm */
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
+	/* Signed 8-bit value in dBm */
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
+	/* attributes to be used/received in callback */
+	/* 6-byte MAC address used to represent current BSSID MAC address */
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
+	/* Signed 8-bit value indicating the current RSSI */
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX =
+		QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ndp_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NDP.
+ */
+enum qca_wlan_vendor_attr_ndp_params {
+	QCA_WLAN_VENDOR_ATTR_NDP_PARAM_INVALID = 0,
+	/* Unsigned 32-bit value
+	 * enum of sub commands values in qca_wlan_ndp_sub_cmd
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
+	/* Unsigned 16-bit value */
+	QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
+	/* NL attributes for data used NDP SUB cmds */
+	/* Unsigned 32-bit value indicating a service info */
+	QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID,
+	/* Unsigned 32-bit value; channel frequency in MHz */
+	QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL,
+	/* Interface Discovery MAC address. An array of 6 Unsigned int8 */
+	QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR,
+	/* Interface name on which NDP is being created */
+	QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
+	/* Unsigned 32-bit value for security */
+	/* CONFIG_SECURITY is deprecated, use NCS_SK_TYPE/PMK/SCID instead */
+	QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY,
+	/* Unsigned 32-bit value for QoS */
+	QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS,
+	/* Array of u8: len = QCA_WLAN_VENDOR_ATTR_NAN_DP_APP_INFO_LEN */
+	QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO,
+	/* Unsigned 32-bit value for NDP instance Id */
+	QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID,
+	/* Array of instance Ids */
+	QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY,
+	/* Unsigned 32-bit value for initiator/responder NDP response code
+	 * accept/reject
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE,
+	/* NDI MAC address. An array of 6 Unsigned int8 */
+	QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR,
+	/* Unsigned 32-bit value errors types returned by driver
+	 * The wifi_nan.h in AOSP project platform/hardware/libhardware_legacy
+	 * NanStatusType includes these values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE,
+	/* Unsigned 32-bit value error values returned by driver
+	 * The nan_i.h in AOSP project platform/hardware/qcom/wlan
+	 * NanInternalStatusType includes these values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE,
+	/* Unsigned 32-bit value for Channel setup configuration
+	 * The wifi_nan.h in AOSP project platform/hardware/libhardware_legacy
+	 * NanDataPathChannelCfg includes these values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG,
+	/* Unsigned 32-bit value for Cipher Suite Shared Key Type */
+	QCA_WLAN_VENDOR_ATTR_NDP_CSID,
+	/* Array of u8: len = NAN_PMK_INFO_LEN 32 bytes */
+	QCA_WLAN_VENDOR_ATTR_NDP_PMK,
+	/* Security Context Identifier that contains the PMKID
+	 * Array of u8: len = NAN_SCID_BUF_LEN 1024 bytes
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_SCID,
+	/* Array of u8: len = NAN_SECURITY_MAX_PASSPHRASE_LEN 63 bytes */
+	QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE,
+	/* Array of u8: len = NAN_MAX_SERVICE_NAME_LEN 255 bytes */
+	QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME,
+	/* Unsigned 32-bit bitmap indicating schedule update
+	 * BIT_0: NSS Update
+	 * BIT_1: Channel list update
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON,
+	/* Unsigned 32-bit value for NSS */
+	QCA_WLAN_VENDOR_ATTR_NDP_NSS,
+	/* Unsigned 32-bit value for NUMBER NDP CHANNEL */
+	QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS,
+	/* Unsigned 32-bit value for CHANNEL BANDWIDTH
+	 * 0:20 MHz, 1:40 MHz, 2:80 MHz, 3:160 MHz
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH,
+	/* Array of channel/band width */
+	QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO,
+	/* IPv6 address used by NDP (in network byte order), 16 bytes array.
+	 * This attribute is used and optional for ndp request, ndp response,
+	 * ndp indication, and ndp confirm.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR = 27,
+	/* Unsigned 16-bit value indicating transport port used by NDP.
+	 * This attribute is used and optional for ndp response, ndp indication,
+	 * and ndp confirm.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT = 28,
+	/* Unsigned 8-bit value indicating protocol used by NDP and assigned by
+	 * the Internet Assigned Numbers Authority (IANA) as per:
+	 * https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+	 * This attribute is used and optional for ndp response, ndp indication,
+	 * and ndp confirm.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL = 29,
+	/* Unsigned 8-bit value indicating if NDP remote peer supports NAN NDPE.
+	 * 1:support 0:not support
+	 */
+	QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX =
+		QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_ndp_sub_cmd {
+	QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0,
+	/* Command to create a NAN data path interface */
+	QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1,
+	/* Command to delete a NAN data path interface */
+	QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2,
+	/* Command to initiate a NAN data path session */
+	QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3,
+	/* Command to notify if the NAN data path session was sent */
+	QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE = 4,
+	/* Command to respond to NAN data path session */
+	QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST = 5,
+	/* Command to notify on the responder about the response */
+	QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE = 6,
+	/* Command to initiate a NAN data path end */
+	QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST = 7,
+	/* Command to notify the if end request was sent */
+	QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE = 8,
+	/* Command to notify the peer about the end request */
+	QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND = 9,
+	/* Command to confirm the NAN data path session is complete */
+	QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND = 10,
+	/* Command to indicate the peer about the end request being received */
+	QCA_WLAN_VENDOR_ATTR_NDP_END_IND = 11,
+	/* Command to indicate the peer of schedule update */
+	QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_IND = 12
+};
+
+/**
+ * enum qca_wlan_vendor_attr_nd_offload - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD.
+ */
+enum qca_wlan_vendor_attr_nd_offload {
+	QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_INVALID = 0,
+	/* Flag to set Neighbour Discovery offload */
+	QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG,
+	/* Keep last */
+	QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX =
+		QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST - 1,
+};
+
+/**
+ * enum packet_filter_sub_cmd - Packet filter sub commands
+ */
+enum packet_filter_sub_cmd {
+	/**
+	 * Write packet filter program and/or data. The driver/firmware should
+	 * disable APF before writing into local buffer and re-enable APF after
+	 * writing is done.
+	 */
+	QCA_WLAN_SET_PACKET_FILTER = 1,
+	/* Get packet filter feature capabilities from driver */
+	QCA_WLAN_GET_PACKET_FILTER = 2,
+	/**
+	 * Write packet filter program and/or data. User space will send the
+	 * %QCA_WLAN_DISABLE_PACKET_FILTER command before issuing this command
+	 * and will send the %QCA_WLAN_ENABLE_PACKET_FILTER afterwards. The key
+	 * difference from that %QCA_WLAN_SET_PACKET_FILTER is the control over
+	 * enable/disable is given to user space with this command. Also,
+	 * user space sends the length of program portion in the buffer within
+	 * %QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH.
+	 */
+	QCA_WLAN_WRITE_PACKET_FILTER = 3,
+	/* Read packet filter program and/or data */
+	QCA_WLAN_READ_PACKET_FILTER = 4,
+	/* Enable APF feature */
+	QCA_WLAN_ENABLE_PACKET_FILTER = 5,
+	/* Disable APF feature */
+	QCA_WLAN_DISABLE_PACKET_FILTER = 6,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_packet_filter - BPF control commands used by
+ * vendor QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER.
+ */
+enum qca_wlan_vendor_attr_packet_filter {
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID = 0,
+	/* Unsigned 32-bit enum passed using packet_filter_sub_cmd */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
+	/* Unsigned 32-bit value indicating the packet filter version */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION,
+	/* Unsigned 32-bit value indicating the packet filter id */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID,
+	/**
+	 * Unsigned 32-bit value indicating the packet filter size including
+	 * program + data.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE,
+	/* Unsigned 32-bit value indicating the packet filter current offset */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
+	/* Program and/or data in bytes */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM,
+	/* Unsigned 32-bit value of the length of the program section in packet
+	 * filter buffer.
+	 */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH = 7,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX =
+	QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_drv_info - WLAN driver info used by vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE.
+ */
+enum qca_wlan_vendor_drv_info {
+	QCA_WLAN_VENDOR_ATTR_DRV_INFO_INVALID = 0,
+	/* Maximum Message size info between firmware & HOST
+	 * Unsigned 32-bit value
+	 */
+	QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_DRV_INFO_MAX =
+		QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_wake_stats - Wake lock stats used by vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS.
+ */
+enum qca_wlan_vendor_attr_wake_stats {
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_INVALID = 0,
+	/* Unsigned 32-bit value indicating the total count of wake event */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_CMD_EVENT_WAKE,
+	/* Array of individual wake count, each index representing wake reason
+	 */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR,
+	/* Unsigned 32-bit value representing wake count array */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ,
+	/* Unsigned 32-bit total wake count value of driver/fw */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE,
+	/* Array of wake stats of driver/fw */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR,
+	/* Unsigned 32-bit total wake count value of driver/fw */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ,
+	/* Unsigned 32-bit total wake count value of packets received */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_RX_DATA_WAKE,
+	/* Unsigned 32-bit wake count value unicast packets received */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_UNICAST_CNT,
+	/* Unsigned 32-bit wake count value multicast packets received */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_MULTICAST_CNT,
+	/* Unsigned 32-bit wake count value broadcast packets received */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_BROADCAST_CNT,
+	/* Unsigned 32-bit wake count value of ICMP packets */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP_PKT,
+	/* Unsigned 32-bit wake count value of ICMP6 packets */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_PKT,
+	/* Unsigned 32-bit value ICMP6 router advertisement */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RA,
+	/* Unsigned 32-bit value ICMP6 neighbor advertisement */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NA,
+	/* Unsigned 32-bit value ICMP6 neighbor solicitation */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NS,
+	/* Unsigned 32-bit wake count value of receive side ICMP4 multicast */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP4_RX_MULTICAST_CNT,
+	/* Unsigned 32-bit wake count value of receive side ICMP6 multicast */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RX_MULTICAST_CNT,
+	/* Unsigned 32-bit wake count value of receive side multicast */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_OTHER_RX_MULTICAST_CNT,
+	/* Unsigned 32-bit wake count value of a given RSSI breach */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RSSI_BREACH_CNT,
+	/* Unsigned 32-bit wake count value of low RSSI */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_LOW_RSSI_CNT,
+	/* Unsigned 32-bit value GSCAN count */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_GSCAN_CNT,
+	/* Unsigned 32-bit value PNO complete count */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_COMPLETE_CNT,
+	/* Unsigned 32-bit value PNO match count */
+	QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_MATCH_CNT,
+	/* keep last */
+	QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST,
+	QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX =
+		QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST - 1,
+};
+
+/**
+ * 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.
+ */
+enum qca_wlan_vendor_attr_thermal_cmd {
+	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_INVALID = 0,
+	/* The value of command, driver will implement different operations
+	 * according to this value. It uses values defined in
+	 * enum qca_wlan_vendor_attr_thermal_cmd_type.
+	 * u32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX =
+	QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST - 1
+};
+
+/**
+ * qca_wlan_vendor_attr_thermal_cmd_type: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD. This represents the
+ * thermal command types sent to driver.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS: Request to
+ * get thermal shutdown configuration parameters for display. Parameters
+ * responded from driver are defined in
+ * enum qca_wlan_vendor_attr_get_thermal_params_rsp.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE: Request to
+ * get temperature. Host should respond with a temperature data. It is defined
+ * in enum qca_wlan_vendor_attr_thermal_get_temperature.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND: Request to execute thermal
+ * suspend action.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal
+ * resume action.
+ */
+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,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_get_temperature - vendor subcmd attributes
+ * to get chip temperature by user.
+ * enum values are used for NL attributes for data used by
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE command for data used
+ * by QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_get_temperature {
+	QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_INVALID = 0,
+	/* Temperature value (degree Celsius) from driver.
+	 * u32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_DATA,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_MAX =
+	QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_thermal_params_rsp - vendor subcmd attributes
+ * to get configuration parameters of thermal shutdown feature. Enum values are
+ * used by QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS command for data
+ * used by QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_get_thermal_params_rsp {
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_INVALID = 0,
+	/* Indicate if the thermal shutdown feature is enabled.
+	 * NLA_FLAG attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SHUTDOWN_EN,
+	/* Indicate if the auto mode is enabled.
+	 * Enable: Driver triggers the suspend/resume action.
+	 * Disable: User space triggers the suspend/resume action.
+	 * NLA_FLAG attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SHUTDOWN_AUTO_EN,
+	/* Thermal resume threshold (degree Celsius). Issue the resume command
+	 * if the temperature value is lower than this threshold.
+	 * u16 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_RESUME_THRESH,
+	/* Thermal warning threshold (degree Celsius). FW reports temperature
+	 * to driver if it's higher than this threshold.
+	 * u16 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_WARNING_THRESH,
+	/* Thermal suspend threshold (degree Celsius). Issue the suspend command
+	 * if the temperature value is higher than this threshold.
+	 * u16 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SUSPEND_THRESH,
+	/* FW reports temperature data periodically at this interval (ms).
+	 * u16 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SAMPLE_RATE,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_MAX =
+	QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_event - vendor subcmd attributes to
+ * report thermal events from driver to user space.
+ * enum values are used for NL attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_event {
+	QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_INVALID = 0,
+	/* Temperature value (degree Celsius) from driver.
+	 * u32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_TEMPERATURE,
+	/* Indication of resume completion from power save mode.
+	 * NLA_FLAG attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_RESUME_COMPLETE,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_MAX =
+	QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST - 1,
+};
+
+/**
+ * enum he_fragmentation_val - HE fragmentation support values
+ * Indicates level of dynamic fragmentation that is supported by
+ * a STA as a recipient.
+ * HE fragmentation values are defined in IEEE P802.11ax/D2.0, 9.4.2.237.2
+ * (HE MAC Capabilities Information field) and are used in HE Capabilities
+ * element to advertise the support. These values are validated in the driver
+ * to check the device capability and advertised in the HE Capabilities
+ * element. These values are used to configure testbed device to allow the
+ * advertised hardware capabilities to be downgraded for testing purposes.
+ *
+ * @HE_FRAG_DISABLE: no support for dynamic fragmentation
+ * @HE_FRAG_LEVEL1: support for dynamic fragments that are
+ *	contained within an MPDU or S-MPDU, no support for dynamic fragments
+ *	within an A-MPDU that is not an S-MPDU.
+ * @HE_FRAG_LEVEL2: support for dynamic fragments that are
+ *	contained within an MPDU or S-MPDU and support for up to one dynamic
+ *	fragment for each MSDU, each A-MSDU if supported by the recipient, and
+ *	each MMPDU within an A-MPDU or multi-TID A-MPDU that is not an
+ *	MPDU or S-MPDU.
+ * @HE_FRAG_LEVEL3: support for dynamic fragments that are
+ *	contained within an MPDU or S-MPDU and support for multiple dynamic
+ *	fragments for each MSDU and for each A-MSDU if supported by the
+ *	recipient within an A-MPDU or multi-TID AMPDU and up to one dynamic
+ *	fragment for each MMPDU in a multi-TID A-MPDU that is not an S-MPDU.
+ */
+enum he_fragmentation_val {
+	HE_FRAG_DISABLE,
+	HE_FRAG_LEVEL1,
+	HE_FRAG_LEVEL2,
+	HE_FRAG_LEVEL3,
+};
+
+/**
+ * enum he_mcs_config - HE MCS support configuration
+ *
+ * Configures the HE Tx/Rx MCS map in HE capability IE for given bandwidth.
+ * These values are used in driver to configure the HE MCS map to advertise
+ * Tx/Rx MCS map in HE capability and these values are applied for all the
+ * streams supported by the device. To configure MCS for different bandwidths,
+ * vendor command needs to be sent using this attribute with appropriate value.
+ * For example, to configure HE_80_MCS_0_7, send vendor command using HE MCS
+ * attribute with HE_80_MCS0_7. And to configure HE MCS for HE_160_MCS0_11
+ * send this command using HE MCS config attribute with value HE_160_MCS0_11.
+ * These values are used to configure testbed device to allow the advertised
+ * hardware capabilities to be downgraded for testing purposes. The enum values
+ * are defined such that BIT[1:0] indicates the MCS map value. Values 3,7 and
+ * 11 are not used as BIT[1:0] value is 3 which is used to disable MCS map.
+ * These values are validated in the driver before setting the MCS map and
+ * driver returns error if the input is other than these enum values.
+ *
+ * @HE_80_MCS0_7: support for HE 80/40/20 MHz MCS 0 to 7
+ * @HE_80_MCS0_9: support for HE 80/40/20 MHz MCS 0 to 9
+ * @HE_80_MCS0_11: support for HE 80/40/20 MHz MCS 0 to 11
+ * @HE_160_MCS0_7: support for HE 160 MHz MCS 0 to 7
+ * @HE_160_MCS0_9: support for HE 160 MHz MCS 0 to 9
+ * @HE_160_MCS0_11: support for HE 160 MHz MCS 0 to 11
+ * @HE_80P80_MCS0_7: support for HE 80p80 MHz MCS 0 to 7
+ * @HE_80P80_MCS0_9: support for HE 80p80 MHz MCS 0 to 9
+ * @HE_80P80_MCS0_11: support for HE 80p80 MHz MCS 0 to 11
+ */
+enum he_mcs_config {
+	HE_80_MCS0_7 = 0,
+	HE_80_MCS0_9 = 1,
+	HE_80_MCS0_11 = 2,
+	HE_160_MCS0_7 = 4,
+	HE_160_MCS0_9 = 5,
+	HE_160_MCS0_11 = 6,
+	HE_80P80_MCS0_7 = 8,
+	HE_80P80_MCS0_9 = 9,
+	HE_80P80_MCS0_11 = 10,
+};
+
+/**
+ * enum qca_wlan_ba_session_config - BA session configuration
+ *
+ * Indicates the configuration values for BA session configuration attribute.
+ *
+ * @QCA_WLAN_ADD_BA: Establish a new BA session with given configuration.
+ * @QCA_WLAN_DELETE_BA: Delete the existing BA session for given TID.
+ */
+enum qca_wlan_ba_session_config {
+	QCA_WLAN_ADD_BA = 1,
+	QCA_WLAN_DELETE_BA = 2,
+};
+
+/**
+ * enum qca_wlan_ac_type - Access category type
+ *
+ * Indicates the access category type value.
+ *
+ * @QCA_WLAN_AC_BE: BE access category
+ * @QCA_WLAN_AC_BK: BK access category
+ * @QCA_WLAN_AC_VI: VI access category
+ * @QCA_WLAN_AC_VO: VO access category
+ * @QCA_WLAN_AC_ALL: All ACs
+ */
+enum qca_wlan_ac_type {
+	QCA_WLAN_AC_BE = 0,
+	QCA_WLAN_AC_BK = 1,
+	QCA_WLAN_AC_VI = 2,
+	QCA_WLAN_AC_VO = 3,
+	QCA_WLAN_AC_ALL = 4,
+};
+
+/**
+ * enum qca_wlan_he_ltf_cfg - HE LTF configuration
+ *
+ * Indicates the HE LTF configuration value.
+ *
+ * @QCA_WLAN_HE_LTF_AUTO: HE-LTF is automatically set to the mandatory HE-LTF,
+ * based on the GI setting
+ * @QCA_WLAN_HE_LTF_1X: 1X HE LTF is 3.2us LTF
+ * @QCA_WLAN_HE_LTF_2X: 2X HE LTF is 6.4us LTF
+ * @QCA_WLAN_HE_LTF_4X: 4X HE LTF is 12.8us LTF
+ */
+enum qca_wlan_he_ltf_cfg {
+	QCA_WLAN_HE_LTF_AUTO = 0,
+	QCA_WLAN_HE_LTF_1X = 1,
+	QCA_WLAN_HE_LTF_2X = 2,
+	QCA_WLAN_HE_LTF_4X = 3,
+};
+
+/**
+ * enum qca_wlan_he_mac_padding_dur - HE trigger frame MAC padding duration
+ *
+ * Indicates the HE trigger frame MAC padding duration value.
+ *
+ * @QCA_WLAN_HE_NO_ADDITIONAL_PROCESS_TIME: no additional time required to
+ * process the trigger frame.
+ * @QCA_WLAN_HE_8US_OF_PROCESS_TIME: indicates the 8us of processing time for
+ * trigger frame.
+ * @QCA_WLAN_HE_16US_OF_PROCESS_TIME: indicates the 16us of processing time for
+ * trigger frame.
+ */
+enum qca_wlan_he_mac_padding_dur {
+	QCA_WLAN_HE_NO_ADDITIONAL_PROCESS_TIME = 0,
+	QCA_WLAN_HE_8US_OF_PROCESS_TIME = 1,
+	QCA_WLAN_HE_16US_OF_PROCESS_TIME = 2,
+};
+
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
+ */
+enum qca_wlan_vendor_attr_wifi_test_config {
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_INVALID = 0,
+	/* 8-bit unsigned value to configure the driver to enable/disable
+	 * WMM feature. This attribute is used to configure testbed device.
+	 * 1-enable, 0-disable
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WMM_ENABLE = 1,
+
+	/* 8-bit unsigned value to configure the driver to accept/reject
+	 * the addba request from peer. This attribute is used to configure
+	 * the testbed device.
+	 * 1-accept addba, 0-reject addba
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ACCEPT_ADDBA_REQ = 2,
+
+	/* 8-bit unsigned value to configure the driver to send or not to
+	 * send the addba request to peer.
+	 * This attribute is used to configure the testbed device.
+	 * 1-send addba, 0-do not send addba
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SEND_ADDBA_REQ = 3,
+
+	/* 8-bit unsigned value to indicate the HE fragmentation support.
+	 * Uses enum he_fragmentation_val values.
+	 * This attribute is used to configure the testbed device to
+	 * allow the advertised hardware capabilities to be downgraded
+	 * for testing purposes.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_FRAGMENTATION = 4,
+
+	/* 8-bit unsigned value to indicate the HE MCS support.
+	 * Uses enum he_mcs_config values.
+	 * This attribute is used to configure the testbed device to
+	 * allow the advertised hardware capabilities to be downgraded
+	 * for testing purposes.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MCS = 5,
+
+	/* 8-bit unsigned value to configure the driver to allow or not to
+	 * allow the connection with WEP/TKIP in HT/VHT/HE modes.
+	 * This attribute is used to configure the testbed device.
+	 * 1-allow WEP/TKIP in HT/VHT/HE, 0-do not allow WEP/TKIP.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WEP_TKIP_IN_HE = 6,
+
+	/* 8-bit unsigned value to configure the driver to add a
+	 * new BA session or delete the existing BA session for
+	 * given TID. ADDBA command uses the buffer size and TID
+	 * configuration if user specifies the values else default
+	 * value for buffer size is used for all TIDs if the TID
+	 * also not specified. For DEL_BA command TID value is
+	 * required to process the command.
+	 * Uses enum qca_wlan_ba_session_config values.
+	 * This attribute is used to configure the testbed device.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADD_DEL_BA_SESSION = 7,
+
+	/* 16-bit unsigned value to configure the buffer size in addba
+	 * request and response frames.
+	 * This attribute is used to configure the testbed device.
+	 * The range of the value is 0 to 256.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE = 8,
+
+	/* 8-bit unsigned value to configure the buffer size in addba
+	 * request and response frames.
+	 * This attribute is used to configure the testbed device.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BA_TID = 9,
+
+	/* 8-bit unsigned value to configure the no ack policy.
+	 * To configure no ack policy, access category value is
+	 * required to process the command.
+	 * This attribute is used to configure the testbed device.
+	 * 1 - enable no ack, 0 - disable no ack.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_NO_ACK = 10,
+
+	/* 8-bit unsigned value to configure the AC for no ack policy
+	 * This attribute is used to configure the testbed device.
+	 * Uses the enum qca_wlan_ac_type values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_NO_ACK_AC = 11,
+
+	/* 8-bit unsigned value to configure the HE LTF
+	 * This attribute is used to configure the testbed device.
+	 * Uses the enum qca_wlan_he_ltf_cfg values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_LTF = 12,
+
+	/* 8-bit unsigned value to configure the tx beamformee.
+	 * This attribute is used to configure the testbed device.
+	 * 1-enable, 0-disable.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_TX_BEAMFORMEE = 13,
+
+	/* 8-bit unsigned value to configure the tx beamformee number
+	 * of space-time streams.
+	 * This attribute is used to configure the testbed device.
+	 * The range of the value is 0 to 8.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_BEAMFORMEE_NSTS = 14,
+
+	/* 8-bit unsigned value to configure the MU EDCA params for given AC
+	 * This attribute is used to configure the testbed device.
+	 * Uses the enum qca_wlan_ac_type values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_AC = 15,
+
+	/* 8-bit unsigned value to configure the MU EDCA AIFSN for given AC
+	 * To configure MU EDCA AIFSN value, MU EDCA access category value
+	 * is required to process the command.
+	 * This attribute is used to configure the testbed device.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_AIFSN = 16,
+
+	/* 8-bit unsigned value to configure the MU EDCA ECW min value for
+	 * given AC.
+	 * To configure MU EDCA ECW min value, MU EDCA access category value
+	 * is required to process the command.
+	 * This attribute is used to configure the testbed device.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_ECWMIN = 17,
+
+	/* 8-bit unsigned value to configure the MU EDCA ECW max value for
+	 * given AC.
+	 * To configure MU EDCA ECW max value, MU EDCA access category value
+	 * is required to process the command.
+	 * This attribute is used to configure the testbed device.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_ECWMAX = 18,
+
+	/* 8-bit unsigned value to configure the MU EDCA timer for given AC
+	 * To configure MU EDCA timer value, MU EDCA access category value
+	 * is required to process the command.
+	 * This attribute is used to configure the testbed device.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_TIMER = 19,
+
+	/* 8-bit unsigned value to configure the HE trigger frame MAC padding
+	 * duration.
+	 * This attribute is used to configure the testbed device.
+	 * Uses the enum qca_wlan_he_mac_padding_dur values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MAC_PADDING_DUR = 20,
+
+	/* 8-bit unsigned value to override the MU EDCA params to defaults
+	 * regardless of the AP beacon MU EDCA params. If it is enabled use
+	 * the default values else use the MU EDCA params from AP beacon.
+	 * This attribute is used to configure the testbed device.
+	 * 1-enable, 0-disable.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OVERRIDE_MU_EDCA = 21,
+
+	/* 8-bit unsigned value to configure the support for receiving
+	 * an MPDU that contains an operating mode control subfield.
+	 * This attribute is used to configure the testbed device.
+	 * 1-enable, 0-disable.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_SUPP = 22,
+
+	/* Nested attribute values required to setup the TWT session.
+	 * enum qca_wlan_vendor_attr_twt_setup provides the necessary
+	 * information to set up the session. It contains broadcast flags,
+	 * set_up flags, trigger value, flow type, flow ID, wake interval
+	 * exponent, protection, target wake time, wake duration, wake interval
+	 * mantissa. These nested attributes are used to setup a host triggered
+	 * TWT session.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP = 23,
+
+	/* This nested attribute is used to terminate the current TWT session.
+	 * It does not currently carry any attributes.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_TERMINATE = 24,
+
+	/* This nested attribute is used to suspend the current TWT session.
+	 * It does not currently carry any attributes.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SUSPEND = 25,
+
+	/* Nested attribute values to indicate the request for resume.
+	 * This attribute is used to resume the TWT session.
+	 * enum qca_wlan_vendor_attr_twt_resume provides the necessary
+	 * parameters required to resume the TWT session.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME = 26,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_bss_filter - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ * The user can add/delete the filter by specifying the BSSID/STA MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, filter type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, add/delete action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user can get the
+ * statistics of an unassociated station by specifying the MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, station type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, GET action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user also can get
+ * the statistics of all unassociated stations by specifying the Broadcast MAC
+ * address (ff:ff:ff:ff:ff:ff) in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR with
+ * above procedure. In the response, driver shall specify statistics
+ * information nested in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS.
+ */
+enum qca_wlan_vendor_attr_bss_filter {
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR = 1,
+	/* Other BSS filter type, unsigned 8 bit value. One of the values
+	 * in enum qca_wlan_vendor_bss_filter_type.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE = 2,
+	/* Other BSS filter action, unsigned 8 bit value. One of the values
+	 * in enum qca_wlan_vendor_bss_filter_action.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION = 3,
+	/* Array of nested attributes where each entry is the statistics
+	 * information of the specified station that belong to another BSS.
+	 * Attributes for each entry are taken from enum
+	 * qca_wlan_vendor_bss_filter_sta_stats.
+	 * Other BSS station configured in
+	 * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER with filter type
+	 * QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA.
+	 * Statistics returned by QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER
+	 * with filter action QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS = 4,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX =
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_type - Type of
+ * filter used in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID: BSSID filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA: Station MAC address filter
+ */
+enum qca_wlan_vendor_bss_filter_type {
+	QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID,
+	QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_action - Type of
+ * action in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD: Add filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL: Delete filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET: Get the statistics
+ */
+enum qca_wlan_vendor_bss_filter_action {
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD,
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL,
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_sta_stats - Attributes for
+ * the statistics of a specific unassociated station belonging to another BSS.
+ * The statistics provides information of the unassociated station
+ * filtered by other BSS operation - such as MAC, signal value.
+ * Used by the vendor command QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC: MAC address of the station.
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI: Last received signal strength
+ *	of the station. Unsigned 8 bit number containing RSSI.
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS: Time stamp of the host
+ *	driver for the last received RSSI. Unsigned 64 bit number containing
+ *	nanoseconds from the boottime.
+ */
+enum qca_wlan_vendor_bss_filter_sta_stats {
+	QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_INVALID = 0,
+	QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC = 1,
+	QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI = 2,
+	QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS = 3,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST,
+	QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAX =
+	QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST - 1
+};
+
+/* enum qca_wlan_nan_subcmd_type - Type of NAN command used by attribute
+ * QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE as a part of vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT.
+ */
+enum qca_wlan_nan_ext_subcmd_type {
+	/* Subcmd of type NAN Enable Request */
+	QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ = 1,
+	/* Subcmd of type NAN Disable Request */
+	QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_nan_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT.
+ */
+enum qca_wlan_vendor_attr_nan_params {
+	QCA_WLAN_VENDOR_ATTR_NAN_INVALID = 0,
+	/* Carries NAN command for firmware component. Every vendor command
+	 * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT must contain this attribute with a
+	 * payload containing the NAN command. NLA_BINARY attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA = 1,
+	/* Indicates the type of NAN command sent with
+	 * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT. enum qca_wlan_nan_ext_subcmd_type
+	 * describes the possible range of values. This attribute is mandatory
+	 * if the command being issued is either
+	 * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ or
+	 * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ. NLA_U32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE = 2,
+	/* Frequency (in MHz) of primary NAN discovery social channel in 2.4 GHz
+	 * band. This attribute is mandatory when command type is
+	 * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ. NLA_U32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NAN_DISC_24GHZ_BAND_FREQ = 3,
+	/* Frequency (in MHz) of secondary NAN discovery social channel in 5 GHz
+	 * band. This attribute is optional and should be included when command
+	 * type is QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ and NAN discovery
+	 * has to be started on 5GHz along with 2.4GHz. NLA_U32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_NAN_DISC_5GHZ_BAND_FREQ = 4,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX =
+		QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_setup: Represents attributes for
+ * TWT (Target Wake Time) setup request. These attributes are sent as part of
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST: Flag attribute.
+ * Disable (flag attribute not present) - Individual TWT
+ * Enable (flag attribute present) - Broadcast TWT.
+ * Individual means the session is between the STA and the AP.
+ * This session is established using a separate negotiation between
+ * STA and AP.
+ * Broadcast means the session is across multiple STAs and an AP. The
+ * configuration parameters are announced in Beacon frames by the AP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE: Required (u8).
+ * Unsigned 8-bit qca_wlan_vendor_twt_setup_req_type to
+ * specify the TWT request type
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER: Flag attribute
+ * Enable (flag attribute present) - TWT with trigger support.
+ * Disable (flag attribute not present) - TWT without trigger support.
+ * Trigger means the AP will send the trigger frame to allow STA to send data.
+ * Without trigger, the STA will wait for the MU EDCA timer before
+ * transmitting the data.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE: Required (u8)
+ * 0 - Announced TWT - In this mode, STA may skip few service periods to
+ * save more power. If STA wants to wake up, it will send a PS-POLL/QoS
+ * NULL frame to AP.
+ * 1 - Unannounced TWT - The STA will wakeup during every SP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID: Optional (u8)
+ * Flow ID is the unique identifier for each TWT session.
+ * Currently this is not required and dialog ID will be set to zero.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP: Required (u8)
+ * This attribute (exp) is used along with the mantissa to derive the
+ * wake interval using the following formula:
+ * pow(2,exp) = wake_intvl_us/wake_intvl_mantis
+ * Wake interval is the interval between 2 successive SP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION: Flag attribute
+ * Enable (flag attribute present) - Protection required.
+ * Disable (flag attribute not present) - Protection not required.
+ * If protection is enabled, then the AP will use protection
+ * mechanism using RTS/CTS to self to reserve the airtime.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME: Optional (u32)
+ * This attribute is used as the SP offset which is the offset from
+ * TSF after which the wake happens. The units are in microseconds. If
+ * this attribute is not provided, then the value will be set to zero.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION: Required (u32)
+ * This is the duration of the service period. The units are in TU.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA: Required (u32)
+ * This attribute is used to configure wake interval mantissa.
+ * The units are in TU.
+ */
+enum qca_wlan_vendor_attr_twt_setup {
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST = 1,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE = 2,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER = 3,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE = 4,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID = 5,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP = 6,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION = 7,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME = 8,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION = 9,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA = 10,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
+	QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_resume: Represents attributes for
+ * TWT (Target Wake Time) resume request. These attributes are sent as part of
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME and
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT: Optional (u8)
+ * This attribute is used as the SP offset which is the offset from
+ * TSF after which the wake happens. The units are in microseconds.
+ * If this attribute is not provided, then the value will be set to
+ * zero.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE: Required (u32)
+ * This attribute represents the next TWT subfield size.
+ */
+enum qca_wlan_vendor_attr_twt_resume {
+	QCA_WLAN_VENDOR_ATTR_TWT_RESUME_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT = 1,
+	QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX =
+	QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_twt_setup_req_type - Required (u8)
+ * Represents the setup type being requested for TWT.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_REQUEST: STA is not specifying all the TWT
+ * parameters but relying on AP to fill the parameters during the negotiation.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST: STA will provide all the suggested
+ * values which the AP may accept or AP may provide alternative parameters
+ * which the STA may accept.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_DEMAND: STA is not willing to accept any
+ * alternate parameters than the requested ones.
+ */
+enum qca_wlan_vendor_twt_setup_req_type {
+	QCA_WLAN_VENDOR_TWT_SETUP_REQUEST = 1,
+	QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST = 2,
+	QCA_WLAN_VENDOR_TWT_SETUP_DEMAND = 3,
+};
+
+/**
+ * enum qca_wlan_roam_scan_event_type - Type of roam scan event
+ *
+ * Indicates the type of roam scan event sent by firmware/driver.
+ *
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_EVENT: Roam scan trigger event type.
+ * @QCA_WLAN_ROAM_SCAN_STOP_EVENT: Roam scan stopped event type.
+ */
+enum qca_wlan_roam_scan_event_type {
+	QCA_WLAN_ROAM_SCAN_TRIGGER_EVENT = 0,
+	QCA_WLAN_ROAM_SCAN_STOP_EVENT = 1,
+};
+
+/**
+ * enum qca_wlan_roam_scan_trigger_reason - Roam scan trigger reason
+ *
+ * Indicates the reason for triggering roam scan by firmware/driver.
+ *
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_LOW_RSSI: Due to low RSSI of current AP.
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_HIGH_PER: Due to high packet error rate.
+ */
+enum qca_wlan_roam_scan_trigger_reason {
+	QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_LOW_RSSI = 0,
+	QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_HIGH_PER = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_roam_scan - Vendor subcmd attributes to report
+ * roam scan related details from driver/firmware to user space. enum values
+ * are used for NL attributes sent with
+ * %QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_roam_scan {
+	QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_INVALID = 0,
+	/* Encapsulates type of roam scan event being reported. enum
+	 * qca_wlan_roam_scan_event_type describes the possible range of
+	 * values. u32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_EVENT_TYPE = 1,
+	/* Encapsulates reason for triggering roam scan. enum
+	 * qca_wlan_roam_scan_trigger_reason describes the possible range of
+	 * values. u32 attribute.
+	 */
+	QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_TRIGGER_REASON = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_MAX =
+	QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_AFTER_LAST - 1,
+};
+
+/**
+ * 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.
+ */
+enum qca_wlan_vendor_cfr_method {
+	/* CFR method using QOS Null frame */
+	QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0,
+};
+
+/**
+ * enum qca_wlan_vendor_peer_cfr_capture_attr - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer
+ * Channel Frequency Response capture parameters and enable periodic CFR
+ * capture.
+ */
+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,
+
+	/* Keep last */
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX =
+	QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 9f70f03..981e788 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -29,6 +29,8 @@
 	/* First, check if this is an ECC group */
 	tmp->ec = crypto_ec_init(group);
 	if (tmp->ec) {
+		wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
+			   group);
 		sae->group = group;
 		tmp->prime_len = crypto_ec_prime_len(tmp->ec);
 		tmp->prime = crypto_ec_get_prime(tmp->ec);
@@ -39,6 +41,8 @@
 	/* Not an ECC group, check FFC */
 	tmp->dh = dh_groups_get(group);
 	if (tmp->dh) {
+		wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
+			   group);
 		sae->group = group;
 		tmp->prime_len = tmp->dh->prime_len;
 		if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
@@ -66,6 +70,8 @@
 	}
 
 	/* Unsupported group */
+	wpa_printf(MSG_DEBUG,
+		   "SAE: Group %d not supported by the crypto library", group);
 	return -1;
 }
 
@@ -88,6 +94,7 @@
 	crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
 	crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
 	wpabuf_free(tmp->anti_clogging_token);
+	os_free(tmp->pw_id);
 	bin_clear_free(tmp, sizeof(*tmp));
 	sae->tmp = NULL;
 }
@@ -417,12 +424,13 @@
 
 static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
 			      const u8 *addr2, const u8 *password,
-			      size_t password_len)
+			      size_t password_len, const char *identifier)
 {
 	u8 counter, k = 40;
 	u8 addrs[2 * ETH_ALEN];
-	const u8 *addr[2];
-	size_t len[2];
+	const u8 *addr[3];
+	size_t len[3];
+	size_t num_elem;
 	u8 dummy_password[32];
 	size_t dummy_password_len;
 	int pwd_seed_odd = 0;
@@ -454,10 +462,13 @@
 
 	wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
 			      password, password_len);
+	if (identifier)
+		wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+			   identifier);
 
 	/*
 	 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
-	 * base = password
+	 * base = password [|| identifier]
 	 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
 	 *              base || counter)
 	 */
@@ -465,8 +476,15 @@
 
 	addr[0] = password;
 	len[0] = password_len;
-	addr[1] = &counter;
-	len[1] = sizeof(counter);
+	num_elem = 1;
+	if (identifier) {
+		addr[num_elem] = (const u8 *) identifier;
+		len[num_elem] = os_strlen(identifier);
+		num_elem++;
+	}
+	addr[num_elem] = &counter;
+	len[num_elem] = sizeof(counter);
+	num_elem++;
 
 	/*
 	 * Continue for at least k iterations to protect against side-channel
@@ -484,8 +502,8 @@
 		}
 
 		wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
-		if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
-				       pwd_seed) < 0)
+		if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+				       addr, len, pwd_seed) < 0)
 			break;
 
 		res = sae_test_pwd_seed_ecc(sae, pwd_seed,
@@ -544,12 +562,13 @@
 
 static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
 			      const u8 *addr2, const u8 *password,
-			      size_t password_len)
+			      size_t password_len, const char *identifier)
 {
 	u8 counter;
 	u8 addrs[2 * ETH_ALEN];
-	const u8 *addr[2];
-	size_t len[2];
+	const u8 *addr[3];
+	size_t len[3];
+	size_t num_elem;
 	int found = 0;
 
 	if (sae->tmp->pwe_ffc == NULL) {
@@ -564,14 +583,21 @@
 	/*
 	 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
 	 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
-	 *              password || counter)
+	 *              password [|| identifier] || counter)
 	 */
 	sae_pwd_seed_key(addr1, addr2, addrs);
 
 	addr[0] = password;
 	len[0] = password_len;
-	addr[1] = &counter;
-	len[1] = sizeof(counter);
+	num_elem = 1;
+	if (identifier) {
+		addr[num_elem] = (const u8 *) identifier;
+		len[num_elem] = os_strlen(identifier);
+		num_elem++;
+	}
+	addr[num_elem] = &counter;
+	len[num_elem] = sizeof(counter);
+	num_elem++;
 
 	for (counter = 1; !found; counter++) {
 		u8 pwd_seed[SHA256_MAC_LEN];
@@ -584,8 +610,8 @@
 		}
 
 		wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
-		if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
-				       pwd_seed) < 0)
+		if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+				       addr, len, pwd_seed) < 0)
 			break;
 		res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
 		if (res < 0)
@@ -696,13 +722,15 @@
 
 int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
 		       const u8 *password, size_t password_len,
-		       struct sae_data *sae)
+		       const char *identifier, struct sae_data *sae)
 {
 	if (sae->tmp == NULL ||
 	    (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
-						password_len) < 0) ||
+						password_len,
+						identifier) < 0) ||
 	    (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
-						password_len) < 0) ||
+						password_len,
+						identifier) < 0) ||
 	    sae_derive_commit(sae) < 0)
 		return -1;
 	return 0;
@@ -842,7 +870,7 @@
 
 
 void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
-		      const struct wpabuf *token)
+		      const struct wpabuf *token, const char *identifier)
 {
 	u8 *pos;
 
@@ -876,6 +904,16 @@
 		wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
 			    pos, sae->tmp->prime_len);
 	}
+
+	if (identifier) {
+		/* Password Identifier element */
+		wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+		wpabuf_put_u8(buf, 1 + os_strlen(identifier));
+		wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
+		wpabuf_put_str(buf, identifier);
+		wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
+			   identifier);
+	}
 }
 
 
@@ -921,25 +959,70 @@
 }
 
 
+static int sae_is_password_id_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_PASSWORD_IDENTIFIER;
+}
+
+
 static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
 				   const u8 *end, const u8 **token,
 				   size_t *token_len)
 {
-	if ((sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end - *pos) {
-		size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
-				     sae->tmp->prime_len);
-		wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
-		if (token)
-			*token = *pos;
-		if (token_len)
-			*token_len = tlen;
-		*pos += tlen;
-	} else {
-		if (token)
-			*token = NULL;
-		if (token_len)
-			*token_len = 0;
+	size_t scalar_elem_len, tlen;
+	const u8 *elem;
+
+	if (token)
+		*token = NULL;
+	if (token_len)
+		*token_len = 0;
+
+	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.
+	 */
+	tlen = end - (*pos + scalar_elem_len);
+
+	if (tlen < SHA256_MAC_LEN) {
+		wpa_printf(MSG_DEBUG,
+			   "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
+			   (unsigned int) tlen);
+		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;
+	}
+
+	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];
+	}
+
+	wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
+	if (token)
+		*token = *pos;
+	if (token_len)
+		*token_len = tlen;
+	*pos += tlen;
 }
 
 
@@ -991,12 +1074,12 @@
 }
 
 
-static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
 					const u8 *end)
 {
 	u8 prime[SAE_MAX_ECC_PRIME_LEN];
 
-	if (2 * sae->tmp->prime_len > end - pos) {
+	if (2 * sae->tmp->prime_len > end - *pos) {
 		wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
 			   "commit-element");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1007,8 +1090,8 @@
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
 	/* element x and y coordinates < p */
-	if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
-	    os_memcmp(pos + sae->tmp->prime_len, prime,
+	if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
+	    os_memcmp(*pos + sae->tmp->prime_len, prime,
 		      sae->tmp->prime_len) >= 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
 			   "element");
@@ -1016,13 +1099,13 @@
 	}
 
 	wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
-		    pos, sae->tmp->prime_len);
+		    *pos, sae->tmp->prime_len);
 	wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
-		    pos + sae->tmp->prime_len, sae->tmp->prime_len);
+		    *pos + sae->tmp->prime_len, sae->tmp->prime_len);
 
 	crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
 	sae->tmp->peer_commit_element_ecc =
-		crypto_ec_point_from_bin(sae->tmp->ec, pos);
+		crypto_ec_point_from_bin(sae->tmp->ec, *pos);
 	if (sae->tmp->peer_commit_element_ecc == NULL)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
@@ -1032,27 +1115,29 @@
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
 
+	*pos += 2 * sae->tmp->prime_len;
+
 	return WLAN_STATUS_SUCCESS;
 }
 
 
-static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
 					const u8 *end)
 {
 	struct crypto_bignum *res, *one;
 	const u8 one_bin[1] = { 0x01 };
 
-	if (sae->tmp->prime_len > end - pos) {
+	if (sae->tmp->prime_len > end - *pos) {
 		wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
 			   "commit-element");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	}
-	wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
+	wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
 		    sae->tmp->prime_len);
 
 	crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
 	sae->tmp->peer_commit_element_ffc =
-		crypto_bignum_init_set(pos, sae->tmp->prime_len);
+		crypto_bignum_init_set(*pos, sae->tmp->prime_len);
 	if (sae->tmp->peer_commit_element_ffc == NULL)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 	/* 1 < element < p - 1 */
@@ -1080,11 +1165,13 @@
 	}
 	crypto_bignum_deinit(res, 0);
 
+	*pos += sae->tmp->prime_len;
+
 	return WLAN_STATUS_SUCCESS;
 }
 
 
-static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
 				    const u8 *end)
 {
 	if (sae->tmp->dh)
@@ -1093,6 +1180,44 @@
 }
 
 
+static int sae_parse_password_identifier(struct sae_data *sae,
+					 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_password_id_elem(pos, end)) {
+		if (sae->tmp->pw_id) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: No Password Identifier included, but expected one (%s)",
+				   sae->tmp->pw_id);
+			return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+		}
+		os_free(sae->tmp->pw_id);
+		sae->tmp->pw_id = NULL;
+		return WLAN_STATUS_SUCCESS; /* No Password Identifier */
+	}
+
+	if (sae->tmp->pw_id &&
+	    (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
+	     os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
+		wpa_printf(MSG_DEBUG,
+			   "SAE: The included Password Identifier does not match the expected one (%s)",
+			   sae->tmp->pw_id);
+		return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+	}
+
+	os_free(sae->tmp->pw_id);
+	sae->tmp->pw_id = os_malloc(pos[1]);
+	if (!sae->tmp->pw_id)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
+	sae->tmp->pw_id[pos[1] - 1] = '\0';
+	wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
+			  sae->tmp->pw_id, pos[1] -  1);
+	return WLAN_STATUS_SUCCESS;
+}
+
+
 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
 		     const u8 **token, size_t *token_len, int *allowed_groups)
 {
@@ -1116,7 +1241,12 @@
 		return res;
 
 	/* commit-element */
-	res = sae_parse_commit_element(sae, pos, end);
+	res = sae_parse_commit_element(sae, &pos, end);
+	if (res != WLAN_STATUS_SUCCESS)
+		return res;
+
+	/* Optional Password Identifier element */
+	res = sae_parse_password_identifier(sae, pos, end);
 	if (res != WLAN_STATUS_SUCCESS)
 		return res;
 
@@ -1235,7 +1365,8 @@
 	/* Send-Confirm */
 	sc = wpabuf_put(buf, 0);
 	wpabuf_put_le16(buf, sae->send_confirm);
-	sae->send_confirm++;
+	if (sae->send_confirm < 0xffff)
+		sae->send_confirm++;
 
 	if (sae->tmp->ec)
 		sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
@@ -1292,3 +1423,19 @@
 
 	return 0;
 }
+
+
+const char * sae_state_txt(enum sae_state state)
+{
+	switch (state) {
+	case SAE_NOTHING:
+		return "Nothing";
+	case SAE_COMMITTED:
+		return "Committed";
+	case SAE_CONFIRMED:
+		return "Confirmed";
+	case SAE_ACCEPTED:
+		return "Accepted";
+	}
+	return "?";
+}
diff --git a/src/common/sae.h b/src/common/sae.h
index a4270bc..3fbcb58 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -39,16 +39,22 @@
 	struct crypto_bignum *prime_buf;
 	struct crypto_bignum *order_buf;
 	struct wpabuf *anti_clogging_token;
+	char *pw_id;
+};
+
+enum sae_state {
+	SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED
 };
 
 struct sae_data {
-	enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
+	enum sae_state state;
 	u16 send_confirm;
 	u8 pmk[SAE_PMK_LEN];
 	u8 pmkid[SAE_PMKID_LEN];
 	struct crypto_bignum *peer_commit_scalar;
 	int group;
-	int sync;
+	unsigned int sync; /* protocol instance variable: Sync */
+	u16 rc; /* protocol instance variable: Rc (received send-confirm) */
 	struct sae_temporary_data *tmp;
 };
 
@@ -58,14 +64,15 @@
 
 int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
 		       const u8 *password, size_t password_len,
-		       struct sae_data *sae);
+		       const char *identifier, struct sae_data *sae);
 int sae_process_commit(struct sae_data *sae);
 void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
-		      const struct wpabuf *token);
+		      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);
 void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
 u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
+const char * sae_state_txt(enum sae_state state);
 
 #endif /* SAE_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 4bab6b9..14c5769 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1,6 +1,6 @@
 /*
  * WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -25,6 +25,7 @@
 {
 	switch (akmp) {
 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
 		return 24;
 	case WPA_KEY_MGMT_FILS_SHA256:
 	case WPA_KEY_MGMT_FT_FILS_SHA256:
@@ -41,6 +42,21 @@
 }
 
 
+#ifdef CONFIG_IEEE80211R
+static unsigned int wpa_kck2_len(int akmp)
+{
+	switch (akmp) {
+	case WPA_KEY_MGMT_FT_FILS_SHA256:
+		return 16;
+	case WPA_KEY_MGMT_FT_FILS_SHA384:
+		return 24;
+	default:
+		return 0;
+	}
+}
+#endif /* CONFIG_IEEE80211R */
+
+
 static unsigned int wpa_kek_len(int akmp, size_t pmk_len)
 {
 	switch (akmp) {
@@ -50,6 +66,7 @@
 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
 	case WPA_KEY_MGMT_FILS_SHA256:
 	case WPA_KEY_MGMT_FT_FILS_SHA256:
+	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
 		return 32;
 	case WPA_KEY_MGMT_DPP:
 		return pmk_len <= 32 ? 16 : 32;
@@ -61,10 +78,26 @@
 }
 
 
+#ifdef CONFIG_IEEE80211R
+static unsigned int wpa_kek2_len(int akmp)
+{
+	switch (akmp) {
+	case WPA_KEY_MGMT_FT_FILS_SHA256:
+		return 16;
+	case WPA_KEY_MGMT_FT_FILS_SHA384:
+		return 32;
+	default:
+		return 0;
+	}
+}
+#endif /* CONFIG_IEEE80211R */
+
+
 unsigned int wpa_mic_len(int akmp, size_t pmk_len)
 {
 	switch (akmp) {
 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
 		return 24;
 	case WPA_KEY_MGMT_FILS_SHA256:
 	case WPA_KEY_MGMT_FILS_SHA384:
@@ -82,6 +115,61 @@
 
 
 /**
+ * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise
+ */
+int wpa_use_akm_defined(int akmp)
+{
+	return akmp == WPA_KEY_MGMT_OSEN ||
+		akmp == WPA_KEY_MGMT_OWE ||
+		akmp == WPA_KEY_MGMT_DPP ||
+		akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
+		wpa_key_mgmt_sae(akmp) ||
+		wpa_key_mgmt_suite_b(akmp) ||
+		wpa_key_mgmt_fils(akmp);
+}
+
+
+/**
+ * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if CMAC is used; 0 otherwise
+ */
+int wpa_use_cmac(int akmp)
+{
+	return akmp == WPA_KEY_MGMT_OSEN ||
+		akmp == WPA_KEY_MGMT_OWE ||
+		akmp == WPA_KEY_MGMT_DPP ||
+		wpa_key_mgmt_ft(akmp) ||
+		wpa_key_mgmt_sha256(akmp) ||
+		wpa_key_mgmt_sae(akmp) ||
+		wpa_key_mgmt_suite_b(akmp);
+}
+
+
+/**
+ * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if AES Keywrap is used; 0 otherwise
+ *
+ * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether
+ * to use AES Keywrap based on the negotiated pairwise cipher. This function
+ * does not cover those special cases.
+ */
+int wpa_use_aes_key_wrap(int akmp)
+{
+	return akmp == WPA_KEY_MGMT_OSEN ||
+		akmp == WPA_KEY_MGMT_OWE ||
+		akmp == WPA_KEY_MGMT_DPP ||
+		wpa_key_mgmt_ft(akmp) ||
+		wpa_key_mgmt_sha256(akmp) ||
+		wpa_key_mgmt_sae(akmp) ||
+		wpa_key_mgmt_suite_b(akmp);
+}
+
+
+/**
  * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
  * @key: EAPOL-Key Key Confirmation Key (KCK)
  * @key_len: KCK length in octets
@@ -131,6 +219,13 @@
 #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
 	case WPA_KEY_INFO_TYPE_AKM_DEFINED:
 		switch (akmp) {
+#ifdef CONFIG_SAE
+		case WPA_KEY_MGMT_SAE:
+		case WPA_KEY_MGMT_FT_SAE:
+			wpa_printf(MSG_DEBUG,
+				   "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
+			return omac1_aes_128(key, buf, len, mic);
+#endif /* CONFIG_SAE */
 #ifdef CONFIG_HS20
 		case WPA_KEY_MGMT_OSEN:
 			wpa_printf(MSG_DEBUG,
@@ -201,6 +296,15 @@
 			os_memcpy(mic, hash, key_len);
 			break;
 #endif /* CONFIG_DPP */
+#if defined(CONFIG_IEEE80211R) && defined(CONFIG_SHA384)
+		case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+			wpa_printf(MSG_DEBUG,
+				   "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - FT 802.1X SHA384)");
+			if (hmac_sha384(key, key_len, buf, len, hash))
+				return -1;
+			os_memcpy(mic, hash, 24);
+			break;
+#endif /* CONFIG_IEEE80211R && CONFIG_SHA384 */
 		default:
 			wpa_printf(MSG_DEBUG,
 				   "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)",
@@ -248,7 +352,7 @@
 	size_t ptk_len;
 
 	if (pmk_len == 0) {
-		wpa_printf(MSG_ERROR, "WPA: No PMK set for PT derivation");
+		wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
 		return -1;
 	}
 
@@ -273,6 +377,12 @@
 	ptk->kck_len = wpa_kck_len(akmp, pmk_len);
 	ptk->kek_len = wpa_kek_len(akmp, pmk_len);
 	ptk->tk_len = wpa_cipher_key_len(cipher);
+	if (ptk->tk_len == 0) {
+		wpa_printf(MSG_ERROR,
+			   "WPA: Unsupported cipher (0x%x) used in PTK derivation",
+			   cipher);
+		return -1;
+	}
 	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
 
 	if (wpa_key_mgmt_sha384(akmp)) {
@@ -285,14 +395,14 @@
 		return -1;
 #endif /* CONFIG_SUITEB192 || CONFIG_FILS */
 	} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
-#ifdef CONFIG_IEEE80211W
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
 		if (sha256_prf(pmk, pmk_len, label, data, sizeof(data),
 			       tmp, ptk_len) < 0)
 			return -1;
-#else /* CONFIG_IEEE80211W */
+#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
 		return -1;
-#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
 #ifdef CONFIG_DPP
 	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -337,6 +447,9 @@
 	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
 	wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
 
+	ptk->kek2_len = 0;
+	ptk->kck2_len = 0;
+
 	os_memset(tmp, 0, sizeof(tmp));
 	return 0;
 }
@@ -386,6 +499,8 @@
 					 addr, len, pmk);
 	if (res == 0)
 		wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
+	else
+		*pmk_len = 0;
 	return res;
 }
 
@@ -515,6 +630,9 @@
 				fils_ft, *fils_ft_len);
 	}
 
+	ptk->kek2_len = 0;
+	ptk->kck2_len = 0;
+
 	os_memset(tmp, 0, sizeof(tmp));
 	ret = 0;
 err:
@@ -625,14 +743,23 @@
 	const u8 *addr[9];
 	size_t len[9];
 	size_t i, num_elem = 0;
-	u8 zero_mic[16];
+	u8 zero_mic[24];
+	size_t mic_len, fte_fixed_len;
 
-	if (kck_len != 16) {
+	if (kck_len == 16) {
+		mic_len = 16;
+#ifdef CONFIG_SHA384
+	} else if (kck_len == 24) {
+		mic_len = 24;
+#endif /* CONFIG_SHA384 */
+	} else {
 		wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
 			   (unsigned int) kck_len);
 		return -1;
 	}
 
+	fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len;
+
 	addr[num_elem] = sta_addr;
 	len[num_elem] = ETH_ALEN;
 	num_elem++;
@@ -656,7 +783,7 @@
 		num_elem++;
 	}
 	if (ftie) {
-		if (ftie_len < 2 + sizeof(struct rsn_ftie))
+		if (ftie_len < 2 + fte_fixed_len)
 			return -1;
 
 		/* IE hdr and mic_control */
@@ -665,14 +792,14 @@
 		num_elem++;
 
 		/* MIC field with all zeros */
-		os_memset(zero_mic, 0, sizeof(zero_mic));
+		os_memset(zero_mic, 0, mic_len);
 		addr[num_elem] = zero_mic;
-		len[num_elem] = sizeof(zero_mic);
+		len[num_elem] = mic_len;
 		num_elem++;
 
 		/* Rest of FTIE */
-		addr[num_elem] = ftie + 2 + 2 + 16;
-		len[num_elem] = ftie_len - (2 + 2 + 16);
+		addr[num_elem] = ftie + 2 + 2 + mic_len;
+		len[num_elem] = ftie_len - (2 + 2 + mic_len);
 		num_elem++;
 	}
 	if (ric) {
@@ -683,7 +810,17 @@
 
 	for (i = 0; i < num_elem; i++)
 		wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
-	if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
+#ifdef CONFIG_SHA384
+	if (kck_len == 24) {
+		u8 hash[SHA384_MAC_LEN];
+
+		if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash))
+			return -1;
+		os_memcpy(mic, hash, 24);
+	}
+#endif /* CONFIG_SHA384 */
+	if (kck_len == 16 &&
+	    omac1_aes_128_vector(kck, num_elem, addr, len, mic))
 		return -1;
 
 	return 0;
@@ -691,23 +828,27 @@
 
 
 static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-			     struct wpa_ft_ies *parse)
+			     struct wpa_ft_ies *parse, int use_sha384)
 {
 	const u8 *end, *pos;
 
 	parse->ftie = ie;
 	parse->ftie_len = ie_len;
 
-	pos = ie + sizeof(struct rsn_ftie);
+	pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
+		    sizeof(struct rsn_ftie));
 	end = ie + ie_len;
+	wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
 
 	while (end - pos >= 2) {
 		u8 id, len;
 
 		id = *pos++;
 		len = *pos++;
-		if (len > end - pos)
+		if (len > end - pos) {
+			wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
 			break;
+		}
 
 		switch (id) {
 		case FTIE_SUBELEM_R1KH_ID:
@@ -739,6 +880,9 @@
 			parse->igtk_len = len;
 			break;
 #endif /* CONFIG_IEEE80211W */
+		default:
+			wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
+			break;
 		}
 
 		pos += len;
@@ -749,13 +893,19 @@
 
 
 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-		     struct wpa_ft_ies *parse)
+		     struct wpa_ft_ies *parse, int use_sha384)
 {
 	const u8 *end, *pos;
 	struct wpa_ie_data data;
 	int ret;
 	const struct rsn_ftie *ftie;
 	int prot_ie_count = 0;
+	int update_use_sha384 = 0;
+
+	if (use_sha384 < 0) {
+		use_sha384 = 0;
+		update_use_sha384 = 1;
+	}
 
 	os_memset(parse, 0, sizeof(*parse));
 	if (ies == NULL)
@@ -773,6 +923,7 @@
 
 		switch (id) {
 		case WLAN_EID_RSN:
+			wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len);
 			parse->rsn = pos;
 			parse->rsn_len = len;
 			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
@@ -787,22 +938,63 @@
 				parse->rsn_pmkid = data.pmkid;
 			parse->key_mgmt = data.key_mgmt;
 			parse->pairwise_cipher = data.pairwise_cipher;
+			if (update_use_sha384) {
+				use_sha384 =
+					wpa_key_mgmt_sha384(parse->key_mgmt);
+				update_use_sha384 = 0;
+			}
 			break;
 		case WLAN_EID_MOBILITY_DOMAIN:
+			wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
 			if (len < sizeof(struct rsn_mdie))
 				return -1;
 			parse->mdie = pos;
 			parse->mdie_len = len;
 			break;
 		case WLAN_EID_FAST_BSS_TRANSITION:
+			wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
+			if (use_sha384) {
+				const struct rsn_ftie_sha384 *ftie_sha384;
+
+				if (len < sizeof(*ftie_sha384))
+					return -1;
+				ftie_sha384 =
+					(const struct rsn_ftie_sha384 *) pos;
+				wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
+					    ftie_sha384->mic_control, 2);
+				wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
+					    ftie_sha384->mic,
+					    sizeof(ftie_sha384->mic));
+				wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+					    ftie_sha384->anonce,
+					    WPA_NONCE_LEN);
+				wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+					    ftie_sha384->snonce,
+					    WPA_NONCE_LEN);
+				prot_ie_count = ftie_sha384->mic_control[1];
+				if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
+					return -1;
+				break;
+			}
+
 			if (len < sizeof(*ftie))
 				return -1;
 			ftie = (const struct rsn_ftie *) pos;
+			wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
+				    ftie->mic_control, 2);
+			wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
+				    ftie->mic, sizeof(ftie->mic));
+			wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+				    ftie->anonce, WPA_NONCE_LEN);
+			wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+				    ftie->snonce, WPA_NONCE_LEN);
 			prot_ie_count = ftie->mic_control[1];
-			if (wpa_ft_parse_ftie(pos, len, parse) < 0)
+			if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
 				return -1;
 			break;
 		case WLAN_EID_TIMEOUT_INTERVAL:
+			wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval",
+				    pos, len);
 			if (len != 5)
 				break;
 			parse->tie = pos;
@@ -904,6 +1096,10 @@
 		return WPA_KEY_MGMT_FT_IEEE8021X;
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
 		return WPA_KEY_MGMT_FT_PSK;
+#ifdef CONFIG_SHA384
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384)
+		return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_IEEE80211W
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
@@ -1279,24 +1475,36 @@
 int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
 		      const u8 *ssid, size_t ssid_len,
 		      const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
-		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
+		      int use_sha384)
 {
 	u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
 	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
-	u8 *pos, r0_key_data[48], hash[32];
+	u8 *pos, r0_key_data[64], hash[48];
 	const u8 *addr[2];
 	size_t len[2];
+	size_t q = use_sha384 ? 48 : 32;
+	size_t r0_key_data_len = q + 16;
 
 	/*
 	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
 	 *                       SSIDlength || SSID || MDID || R0KHlength ||
 	 *                       R0KH-ID || S0KH-ID)
-	 * XXKey is either the second 256 bits of MSK or PSK.
-	 * PMK-R0 = L(R0-Key-Data, 0, 256)
-	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
+	 * XXKey is either the second 256 bits of MSK or PSK; or the first
+	 * 384 bits of MSK for FT-EAP-SHA384.
+	 * PMK-R0 = L(R0-Key-Data, 0, Q)
+	 * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128)
+	 * Q = 384 for FT-EAP-SHA384; otherwise, 256
 	 */
 	if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
 		return -1;
+	wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s",
+		   use_sha384 ? "SHA384" : "SHA256");
+	wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len);
+	wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN);
+	wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len);
+	wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id));
 	pos = buf;
 	*pos++ = ssid_len;
 	os_memcpy(pos, ssid, ssid_len);
@@ -1309,22 +1517,50 @@
 	os_memcpy(pos, s0kh_id, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
-		       r0_key_data, sizeof(r0_key_data)) < 0)
-		return -1;
-	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
+#ifdef CONFIG_SHA384
+	if (use_sha384) {
+		if (xxkey_len != SHA384_MAC_LEN) {
+			wpa_printf(MSG_ERROR,
+				   "FT: Unexpected XXKey length %d (expected %d)",
+				   (int) xxkey_len, SHA384_MAC_LEN);
+			return -1;
+		}
+		if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+			       r0_key_data, r0_key_data_len) < 0)
+			return -1;
+	}
+#endif /* CONFIG_SHA384 */
+	if (!use_sha384) {
+		if (xxkey_len != PMK_LEN) {
+			wpa_printf(MSG_ERROR,
+				   "FT: Unexpected XXKey length %d (expected %d)",
+				   (int) xxkey_len, PMK_LEN);
+			return -1;
+		}
+		if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+			       r0_key_data, r0_key_data_len) < 0)
+			return -1;
+	}
+	os_memcpy(pmk_r0, r0_key_data, q);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16);
 
 	/*
-	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
+	 * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt)
 	 */
 	addr[0] = (const u8 *) "FT-R0N";
 	len[0] = 6;
-	addr[1] = r0_key_data + PMK_LEN;
+	addr[1] = &r0_key_data[q];
 	len[1] = 16;
 
-	if (sha256_vector(2, addr, len, hash) < 0)
+#ifdef CONFIG_SHA384
+	if (use_sha384 && sha384_vector(2, addr, len, hash) < 0)
+		return -1;
+#endif /* CONFIG_SHA384 */
+	if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
 		return -1;
 	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+	os_memset(r0_key_data, 0, sizeof(r0_key_data));
 	return 0;
 }
 
@@ -1335,15 +1571,15 @@
  * IEEE Std 802.11r-2008 - 8.5.1.5.4
  */
 int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
-			   const u8 *s1kh_id, u8 *pmk_r1_name)
+			   const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384)
 {
-	u8 hash[32];
+	u8 hash[48];
 	const u8 *addr[4];
 	size_t len[4];
 
 	/*
-	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
-	 *                                  R1KH-ID || S1KH-ID))
+	 * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name ||
+	 *                               R1KH-ID || S1KH-ID))
 	 */
 	addr[0] = (const u8 *) "FT-R1N";
 	len[0] = 6;
@@ -1354,7 +1590,11 @@
 	addr[3] = s1kh_id;
 	len[3] = ETH_ALEN;
 
-	if (sha256_vector(4, addr, len, hash) < 0)
+#ifdef CONFIG_SHA384
+	if (use_sha384 && sha384_vector(4, addr, len, hash) < 0)
+		return -1;
+#endif /* CONFIG_SHA384 */
+	if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
 		return -1;
 	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
 	return 0;
@@ -1366,7 +1606,8 @@
  *
  * IEEE Std 802.11r-2008 - 8.5.1.5.4
  */
-int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
+		      const u8 *pmk_r0_name,
 		      const u8 *r1kh_id, const u8 *s1kh_id,
 		      u8 *pmk_r1, u8 *pmk_r1_name)
 {
@@ -1374,18 +1615,37 @@
 	u8 *pos;
 
 	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+	wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s",
+		   pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256");
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
+	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN);
+	wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id));
 	pos = buf;
 	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
 	pos += FT_R1KH_ID_LEN;
 	os_memcpy(pos, s1kh_id, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	if (sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf,
-		       pmk_r1, PMK_LEN) < 0)
+#ifdef CONFIG_SHA384
+	if (pmk_r0_len == SHA384_MAC_LEN &&
+	    sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
+		       buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
 		return -1;
+#endif /* CONFIG_SHA384 */
+	if (pmk_r0_len == PMK_LEN &&
+	    sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
+		       buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
+		return -1;
+	if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) {
+		wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d",
+			   (int) pmk_r0_len);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len);
 
 	return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
-				      pmk_r1_name);
+				      pmk_r1_name,
+				      pmk_r0_len == SHA384_MAC_LEN);
 }
 
 
@@ -1394,7 +1654,8 @@
  *
  * IEEE Std 802.11r-2008 - 8.5.1.5.5
  */
-int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
+		      const u8 *snonce, const u8 *anonce,
 		      const u8 *sta_addr, const u8 *bssid,
 		      const u8 *pmk_r1_name,
 		      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
@@ -1403,13 +1664,21 @@
 	u8 *pos, hash[32];
 	const u8 *addr[6];
 	size_t len[6];
-	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
-	size_t ptk_len;
+	u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+	size_t ptk_len, offset;
+	int use_sha384 = wpa_key_mgmt_sha384(akmp);
 
 	/*
 	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
 	 *                  BSSID || STA-ADDR)
 	 */
+	wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s",
+		   use_sha384 ? "SHA384" : "SHA256");
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
+	wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
+	wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR,
+		   MAC2STR(bssid), MAC2STR(sta_addr));
 	pos = buf;
 	os_memcpy(pos, snonce, WPA_NONCE_LEN);
 	pos += WPA_NONCE_LEN;
@@ -1421,18 +1690,44 @@
 	pos += ETH_ALEN;
 
 	ptk->kck_len = wpa_kck_len(akmp, PMK_LEN);
+	ptk->kck2_len = wpa_kck2_len(akmp);
 	ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
+	ptk->kek2_len = wpa_kek2_len(akmp);
 	ptk->tk_len = wpa_cipher_key_len(cipher);
-	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
+		ptk->kck2_len + ptk->kek2_len;
 
-	if (sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf,
-		       tmp, ptk_len) < 0)
-		return -1;
+#ifdef CONFIG_SHA384
+	if (use_sha384) {
+		if (pmk_r1_len != SHA384_MAC_LEN) {
+			wpa_printf(MSG_ERROR,
+				   "FT: Unexpected PMK-R1 length %d (expected %d)",
+				   (int) pmk_r1_len, SHA384_MAC_LEN);
+			return -1;
+		}
+		if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+			       buf, pos - buf, tmp, ptk_len) < 0)
+			return -1;
+	}
+#endif /* CONFIG_SHA384 */
+	if (!use_sha384) {
+		if (pmk_r1_len != PMK_LEN) {
+			wpa_printf(MSG_ERROR,
+				   "FT: Unexpected PMK-R1 length %d (expected %d)",
+				   (int) pmk_r1_len, PMK_LEN);
+			return -1;
+		}
+		if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+			       buf, pos - buf, tmp, ptk_len) < 0)
+			return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len);
 
 	/*
 	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
 	 *                                ANonce || BSSID || STA-ADDR))
 	 */
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
 	addr[0] = pmk_r1_name;
 	len[0] = WPA_PMK_NAME_LEN;
 	addr[1] = (const u8 *) "FT-PTKN";
@@ -1451,11 +1746,23 @@
 	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
 
 	os_memcpy(ptk->kck, tmp, ptk->kck_len);
-	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
-	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+	offset = ptk->kck_len;
+	os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
+	offset += ptk->kek_len;
+	os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
+	offset += ptk->tk_len;
+	os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
+	offset = ptk->kck2_len;
+	os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
 
 	wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
 	wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+	if (ptk->kck2_len)
+		wpa_hexdump_key(MSG_DEBUG, "FT: KCK2",
+				ptk->kck2, ptk->kck2_len);
+	if (ptk->kek2_len)
+		wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
+				ptk->kek2, ptk->kek2_len);
 	wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
 	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
 
@@ -1483,7 +1790,7 @@
  * See rsn_pmkid_suite_b()
  * AKM: 00-0F-AC:12
  * See rsn_pmkid_suite_b_192()
- * AKM: 00-0F-AC:15, 00-0F-AC:17
+ * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17
  * PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA))
  * Otherwise:
  * PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA))
@@ -1501,11 +1808,11 @@
 	addr[2] = spa;
 
 	if (0) {
-#ifdef CONFIG_FILS
+#if defined(CONFIG_FILS) || defined(CONFIG_SHA384)
 	} else if (wpa_key_mgmt_sha384(akmp)) {
 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
 		hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
-#endif /* CONFIG_FILS */
+#endif /* CONFIG_FILS || CONFIG_SHA384 */
 #if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
 	} else if (wpa_key_mgmt_sha256(akmp)) {
 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
@@ -1656,6 +1963,8 @@
 #ifdef CONFIG_IEEE80211R
 	case WPA_KEY_MGMT_FT_IEEE8021X:
 		return "FT-EAP";
+	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+		return "FT-EAP-SHA384";
 	case WPA_KEY_MGMT_FT_PSK:
 		return "FT-PSK";
 #endif /* CONFIG_IEEE80211R */
@@ -1697,6 +2006,8 @@
 
 u32 wpa_akm_to_suite(int akm)
 {
+	if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+		return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
 	if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
 		return RSN_AUTH_KEY_MGMT_FT_802_1X;
 	if (akm & WPA_KEY_MGMT_FT_PSK)
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 3b8c1fb..6261744 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -1,6 +1,6 @@
 /*
  * WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -62,8 +62,7 @@
 #define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
 #define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
 #define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
-#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
-RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
 #define RSN_AUTH_KEY_MGMT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
 #define RSN_AUTH_KEY_MGMT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 15)
 #define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
@@ -210,9 +209,13 @@
 	u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
 	u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
 	u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
+	u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
+	u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
 	size_t kck_len;
 	size_t kek_len;
 	size_t tk_len;
+	size_t kck2_len;
+	size_t kek2_len;
 	int installed; /* 1 if key has already been installed to driver */
 };
 
@@ -311,6 +314,14 @@
 	/* followed by optional parameters */
 } STRUCT_PACKED;
 
+struct rsn_ftie_sha384 {
+	u8 mic_control[2];
+	u8 mic[24];
+	u8 anonce[WPA_NONCE_LEN];
+	u8 snonce[WPA_NONCE_LEN];
+	/* followed by optional parameters */
+} STRUCT_PACKED;
+
 #define FTIE_SUBELEM_R1KH_ID 1
 #define FTIE_SUBELEM_GTK 2
 #define FTIE_SUBELEM_R0KH_ID 3
@@ -361,14 +372,16 @@
 int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
 		      const u8 *ssid, size_t ssid_len,
 		      const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
-		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
+		      int use_sha384);
 int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
-			   const u8 *s1kh_id, u8 *pmk_r1_name);
-int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+			   const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384);
+int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
+		      const u8 *pmk_r0_name,
 		      const u8 *r1kh_id, const u8 *s1kh_id,
 		      u8 *pmk_r1, u8 *pmk_r1_name);
-int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
-		      const u8 *sta_addr, const u8 *bssid,
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, const u8 *snonce,
+		      const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
 		      const u8 *pmk_r1_name,
 		      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
 #endif /* CONFIG_IEEE80211R */
@@ -444,7 +457,8 @@
 	int pairwise_cipher;
 };
 
-int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
+		     int use_sha384);
 
 int wpa_cipher_key_len(int cipher);
 int wpa_cipher_rsc_len(int cipher);
@@ -461,6 +475,9 @@
 int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
 int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
 unsigned int wpa_mic_len(int akmp, size_t pmk_len);
+int wpa_use_akm_defined(int akmp);
+int wpa_use_cmac(int akmp);
+int wpa_use_aes_key_wrap(int akmp);
 int fils_domain_name_hash(const char *domain, u8 *hash);
 
 #endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index c59bc60..f65077e 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -50,10 +50,19 @@
 #define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
 /** EAP status */
 #define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
+/** Retransmit the previous request packet */
+#define WPA_EVENT_EAP_RETRANSMIT "CTRL-EVENT-EAP-RETRANSMIT "
+#define WPA_EVENT_EAP_RETRANSMIT2 "CTRL-EVENT-EAP-RETRANSMIT2 "
 /** EAP authentication completed successfully */
 #define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+#define WPA_EVENT_EAP_SUCCESS2 "CTRL-EVENT-EAP-SUCCESS2 "
 /** EAP authentication failed (EAP-Failure received) */
 #define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+#define WPA_EVENT_EAP_FAILURE2 "CTRL-EVENT-EAP-FAILURE2 "
+/** EAP authentication failed due to no response received */
+#define WPA_EVENT_EAP_TIMEOUT_FAILURE "CTRL-EVENT-EAP-TIMEOUT-FAILURE "
+#define WPA_EVENT_EAP_TIMEOUT_FAILURE2 "CTRL-EVENT-EAP-TIMEOUT-FAILURE2 "
+#define WPA_EVENT_EAP_ERROR_CODE "EAP-ERROR-CODE "
 /** Network block temporarily disabled (e.g., due to authentication failure) */
 #define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
 /** Temporarily disabled network block re-enabled */
@@ -80,6 +89,9 @@
 #define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
 /** Channel switch (followed by freq=<MHz> and other channel parameters) */
 #define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
+/** SAE authentication failed due to unknown password identifier */
+#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
+	"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
 
 /** IP subnet status change notification
  *
@@ -145,12 +157,15 @@
 
 /* DPP events */
 #define DPP_EVENT_AUTH_SUCCESS "DPP-AUTH-SUCCESS "
+#define DPP_EVENT_AUTH_INIT_FAILED "DPP-AUTH-INIT-FAILED "
 #define DPP_EVENT_NOT_COMPATIBLE "DPP-NOT-COMPATIBLE "
 #define DPP_EVENT_RESPONSE_PENDING "DPP-RESPONSE-PENDING "
 #define DPP_EVENT_SCAN_PEER_QR_CODE "DPP-SCAN-PEER-QR-CODE "
+#define DPP_EVENT_AUTH_DIRECTION "DPP-AUTH-DIRECTION "
 #define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
 #define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
 #define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
+#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
 #define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
 #define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
 #define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
@@ -159,6 +174,13 @@
 #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_RX "DPP-RX "
+#define DPP_EVENT_TX "DPP-TX "
+#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
+#define DPP_EVENT_FAIL "DPP-FAIL "
+#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 "
 
 /* MESH events */
 #define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -253,8 +275,12 @@
 #define RX_HS20_ICON "RX-HS20-ICON "
 #define RX_MBO_ANQP "RX-MBO-ANQP "
 
+/* parameters: <Venue Number> <Venue URL> */
+#define RX_VENUE_URL "RX-VENUE-URL "
+
 #define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
 #define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
+#define HS20_T_C_ACCEPTANCE "HS20-T-C-ACCEPTANCE "
 
 #define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
 #define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
@@ -278,6 +304,9 @@
 #define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
 #define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
 
+#define HS20_T_C_FILTERING_ADD "HS20-T-C-FILTERING-ADD "
+#define HS20_T_C_FILTERING_REMOVE "HS20-T-C-FILTERING-REMOVE "
+
 #define AP_EVENT_ENABLED "AP-ENABLED "
 #define AP_EVENT_DISABLED "AP-DISABLED "
 
@@ -303,6 +332,13 @@
 /* BSS Transition Management Response frame received */
 #define BSS_TM_RESP "BSS-TM-RESP "
 
+/* Collocated Interference Request frame received;
+ * parameters: <dialog token> <automatic report enabled> <report timeout> */
+#define COLOC_INTF_REQ "COLOC-INTF-REQ "
+/* Collocated Interference Report frame received;
+ * parameters: <STA address> <dialog token> <hexdump of report elements> */
+#define COLOC_INTF_REPORT "COLOC-INTF-REPORT "
+
 /* MBO IE with cellular data connection preference received */
 #define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE "
 
@@ -323,6 +359,19 @@
  */
 #define FILS_HLP_RX "FILS-HLP-RX "
 
+/* Event to indicate Probe Request frame;
+ * parameters: sa=<STA MAC address> signal=<signal> */
+#define RX_PROBE_REQUEST "RX-PROBE-REQUEST "
+
+/* Event to indicate station's HT/VHT operation mode change information */
+#define STA_OPMODE_MAX_BW_CHANGED "STA-OPMODE-MAX-BW-CHANGED "
+#define STA_OPMODE_SMPS_MODE_CHANGED "STA-OPMODE-SMPS-MODE-CHANGED "
+#define STA_OPMODE_N_SS_CHANGED "STA-OPMODE-N_SS-CHANGED "
+
+/* New interface addition or removal for 4addr WDS SDA */
+#define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
+#define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
@@ -424,7 +473,7 @@
  *
  * This function is used to send commands to wpa_supplicant/hostapd. Received
  * response will be written to reply and reply_len is set to the actual length
- * of the reply. This function will block for up to two seconds while waiting
+ * of the reply. This function will block for up to 10 seconds while waiting
  * for the reply. If unsolicited messages are received, the blocking time may
  * be longer.
  *
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index a723201..507b7ca 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -417,6 +417,13 @@
 	struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
 	u8 *plain, size_t *plain_len);
 
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+		   u8 *pubkey);
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+			    const u8 *privkey, size_t privkey_len,
+			    const u8 *pubkey, size_t pubkey_len,
+			    u8 *secret, size_t *len);
+
 /**
  * crypto_global_init - Initialize crypto wrapper
  *
@@ -529,6 +536,14 @@
 			 u8 *buf, size_t buflen, size_t padlen);
 
 /**
+ * crypto_bignum_rand - Create a random number in range of modulus
+ * @r: Bignum; set to a random value
+ * @m: Bignum; modulus
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m);
+
+/**
  * crypto_bignum_add - c = a + b
  * @a: Bignum
  * @b: Bignum
@@ -610,6 +625,16 @@
 			 struct crypto_bignum *d);
 
 /**
+ * crypto_bignum_rshift - r = a >> n
+ * @a: Bignum
+ * @n: Number of bits
+ * @r: Bignum; used to store the result of a >> n
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+			 struct crypto_bignum *r);
+
+/**
  * crypto_bignum_cmp - Compare two bignums
  * @a: Bignum
  * @b: Bignum
@@ -640,6 +665,13 @@
 int crypto_bignum_is_one(const struct crypto_bignum *a);
 
 /**
+ * crypto_bignum_is_odd - Is the given bignum odd
+ * @a: Bignum
+ * Returns: 1 if @a is odd or 0 if not
+ */
+int crypto_bignum_is_odd(const struct crypto_bignum *a);
+
+/**
  * crypto_bignum_legendre - Compute the Legendre symbol (a/p)
  * @a: Bignum
  * @p: Bignum
@@ -671,6 +703,14 @@
 void crypto_ec_deinit(struct crypto_ec *e);
 
 /**
+ * crypto_ec_cofactor - Set the cofactor into the big number
+ * @e: EC context from crypto_ec_init()
+ * @cofactor: Cofactor of curve.
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor);
+
+/**
  * crypto_ec_prime_len - Get length of the prime in octets
  * @e: EC context from crypto_ec_init()
  * Returns: Length of the prime defining the group
@@ -685,6 +725,13 @@
 size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
 
 /**
+ * crypto_ec_order_len - Get length of the order in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the order defining the group
+ */
+size_t crypto_ec_order_len(struct crypto_ec *e);
+
+/**
  * crypto_ec_get_prime - Get prime defining an EC group
  * @e: EC context from crypto_ec_init()
  * Returns: Prime (bignum) defining the group
@@ -721,6 +768,16 @@
 void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
 
 /**
+ * crypto_ec_point_x - Copies the x-ordinate point into big number
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point data
+ * @x: Big number to set to the copy of x-ordinate
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+		      struct crypto_bignum *x);
+
+/**
  * crypto_ec_point_to_bin - Write EC point value as binary data
  * @e: EC context from crypto_ec_init()
  * @p: EC point data from crypto_ec_point_init()
@@ -749,7 +806,7 @@
 						  const u8 *val);
 
 /**
- * crypto_bignum_add - c = a + b
+ * crypto_ec_point_add - c = a + b
  * @e: EC context from crypto_ec_init()
  * @a: Bignum
  * @b: Bignum
@@ -761,7 +818,7 @@
 			struct crypto_ec_point *c);
 
 /**
- * crypto_bignum_mul - res = b * p
+ * crypto_ec_point_mul - res = b * p
  * @e: EC context from crypto_ec_init()
  * @p: EC point
  * @b: Bignum
diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c
index 31a580e..7a797b5 100644
--- a/src/crypto/crypto_gnutls.c
+++ b/src/crypto/crypto_gnutls.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / wrapper functions for libgcrypt
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,26 +10,41 @@
 #include <gcrypt.h>
 
 #include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
 #include "crypto.h"
 
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+static int gnutls_digest_vector(int algo, size_t num_elem,
+				const u8 *addr[], const size_t *len, u8 *mac)
 {
 	gcry_md_hd_t hd;
 	unsigned char *p;
 	size_t i;
 
-	if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
+	if (TEST_FAIL())
+		return -1;
+
+	if (gcry_md_open(&hd, algo, 0) != GPG_ERR_NO_ERROR)
 		return -1;
 	for (i = 0; i < num_elem; i++)
 		gcry_md_write(hd, addr[i], len[i]);
-	p = gcry_md_read(hd, GCRY_MD_MD4);
+	p = gcry_md_read(hd, algo);
 	if (p)
-		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
+		memcpy(mac, p, gcry_md_get_algo_dlen(algo));
 	gcry_md_close(hd);
 	return 0;
 }
 
 
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_digest_vector(GCRY_MD_MD4, num_elem, addr, len, mac);
+}
+
+
 int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
 {
 	gcry_cipher_hd_t hd;
@@ -55,44 +70,155 @@
 
 int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
-	gcry_md_hd_t hd;
-	unsigned char *p;
-	size_t i;
-
-	if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
-		return -1;
-	for (i = 0; i < num_elem; i++)
-		gcry_md_write(hd, addr[i], len[i]);
-	p = gcry_md_read(hd, GCRY_MD_MD5);
-	if (p)
-		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
-	gcry_md_close(hd);
-	return 0;
+	return gnutls_digest_vector(GCRY_MD_MD5, num_elem, addr, len, mac);
 }
 
 
 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
+	return gnutls_digest_vector(GCRY_MD_SHA1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_digest_vector(GCRY_MD_SHA256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_digest_vector(GCRY_MD_SHA384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_digest_vector(GCRY_MD_SHA512, num_elem, addr, len, mac);
+}
+
+
+static int gnutls_hmac_vector(int algo, const u8 *key, size_t key_len,
+			      size_t num_elem, const u8 *addr[],
+			      const size_t *len, u8 *mac)
+{
 	gcry_md_hd_t hd;
 	unsigned char *p;
 	size_t i;
 
-	if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
+	if (TEST_FAIL())
 		return -1;
+
+	if (gcry_md_open(&hd, algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR)
+		return -1;
+	if (gcry_md_setkey(hd, key, key_len) != GPG_ERR_NO_ERROR) {
+		gcry_md_close(hd);
+		return -1;
+	}
 	for (i = 0; i < num_elem; i++)
 		gcry_md_write(hd, addr[i], len[i]);
-	p = gcry_md_read(hd, GCRY_MD_SHA1);
+	p = gcry_md_read(hd, algo);
 	if (p)
-		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
+		memcpy(mac, p, gcry_md_get_algo_dlen(algo));
 	gcry_md_close(hd);
 	return 0;
 }
 
 
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_hmac_vector(GCRY_MD_MD5, key, key_len, num_elem, addr,
+				  len, mac);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_hmac_vector(GCRY_MD_SHA1, key, key_len, num_elem, addr,
+				  len, mac);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_hmac_vector(GCRY_MD_SHA256, key, key_len, num_elem, addr,
+				  len, mac);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_hmac_vector(GCRY_MD_SHA384, key, key_len, num_elem, addr,
+				  len, mac);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return gnutls_hmac_vector(GCRY_MD_SHA512, key, key_len, num_elem, addr,
+				  len, mac);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
 void * aes_encrypt_init(const u8 *key, size_t len)
 {
 	gcry_cipher_hd_t hd;
 
+	if (TEST_FAIL())
+		return NULL;
+
 	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
 	    GPG_ERR_NO_ERROR) {
 		printf("cipher open failed\n");
@@ -127,6 +253,9 @@
 {
 	gcry_cipher_hd_t hd;
 
+	if (TEST_FAIL())
+		return NULL;
+
 	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
 	    GPG_ERR_NO_ERROR)
 		return NULL;
@@ -154,6 +283,42 @@
 }
 
 
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+		   u8 *pubkey)
+{
+	size_t pubkey_len, pad;
+
+	if (os_get_random(privkey, prime_len) < 0)
+		return -1;
+	if (os_memcmp(privkey, prime, prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		privkey[0] = 0;
+	}
+
+	pubkey_len = prime_len;
+	if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+			   pubkey, &pubkey_len) < 0)
+		return -1;
+	if (pubkey_len < prime_len) {
+		pad = prime_len - pubkey_len;
+		os_memmove(pubkey + pad, pubkey, pubkey_len);
+		os_memset(pubkey, 0, pad);
+	}
+
+	return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+			    const u8 *privkey, size_t privkey_len,
+			    const u8 *pubkey, size_t pubkey_len,
+			    u8 *secret, size_t *len)
+{
+	return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+			      prime, prime_len, secret, len);
+}
+
+
 int crypto_mod_exp(const u8 *base, size_t base_len,
 		   const u8 *power, size_t power_len,
 		   const u8 *modulus, size_t modulus_len,
diff --git a/src/crypto/crypto_internal-modexp.c b/src/crypto/crypto_internal-modexp.c
index 9dcabb9..92581ac 100644
--- a/src/crypto/crypto_internal-modexp.c
+++ b/src/crypto/crypto_internal-modexp.c
@@ -13,6 +13,42 @@
 #include "crypto.h"
 
 
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+		   u8 *pubkey)
+{
+	size_t pubkey_len, pad;
+
+	if (os_get_random(privkey, prime_len) < 0)
+		return -1;
+	if (os_memcmp(privkey, prime, prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		privkey[0] = 0;
+	}
+
+	pubkey_len = prime_len;
+	if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+			   pubkey, &pubkey_len) < 0)
+		return -1;
+	if (pubkey_len < prime_len) {
+		pad = prime_len - pubkey_len;
+		os_memmove(pubkey + pad, pubkey, pubkey_len);
+		os_memset(pubkey, 0, pad);
+	}
+
+	return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+			    const u8 *privkey, size_t privkey_len,
+			    const u8 *pubkey, size_t pubkey_len,
+			    u8 *secret, size_t *len)
+{
+	return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+			      prime, prime_len, secret, len);
+}
+
+
 int crypto_mod_exp(const u8 *base, size_t base_len,
 		   const u8 *power, size_t power_len,
 		   const u8 *modulus, size_t modulus_len,
diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c
index b80ad57..259f995 100644
--- a/src/crypto/crypto_libtomcrypt.c
+++ b/src/crypto/crypto_libtomcrypt.c
@@ -694,6 +694,42 @@
 
 #ifdef CONFIG_MODEXP
 
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+		   u8 *pubkey)
+{
+	size_t pubkey_len, pad;
+
+	if (os_get_random(privkey, prime_len) < 0)
+		return -1;
+	if (os_memcmp(privkey, prime, prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		privkey[0] = 0;
+	}
+
+	pubkey_len = prime_len;
+	if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+			   pubkey, &pubkey_len) < 0)
+		return -1;
+	if (pubkey_len < prime_len) {
+		pad = prime_len - pubkey_len;
+		os_memmove(pubkey + pad, pubkey, pubkey_len);
+		os_memset(pubkey, 0, pad);
+	}
+
+	return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+			    const u8 *privkey, size_t privkey_len,
+			    const u8 *pubkey, size_t pubkey_len,
+			    u8 *secret, size_t *len)
+{
+	return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+			      prime, prime_len, secret, len);
+}
+
+
 int crypto_mod_exp(const u8 *base, size_t base_len,
 		   const u8 *power, size_t power_len,
 		   const u8 *modulus, size_t modulus_len,
diff --git a/src/crypto/crypto_nettle.c b/src/crypto/crypto_nettle.c
new file mode 100644
index 0000000..4e31bc8
--- /dev/null
+++ b/src/crypto/crypto_nettle.c
@@ -0,0 +1,437 @@
+/*
+ * Wrapper functions for libnettle and libgmp
+ * Copyright (c) 2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <nettle/nettle-meta.h>
+#include <nettle/des.h>
+#undef des_encrypt
+#include <nettle/hmac.h>
+#include <nettle/aes.h>
+#undef aes_encrypt
+#undef aes_decrypt
+#include <nettle/arcfour.h>
+#include <nettle/bignum.h>
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	struct des_ctx ctx;
+	u8 pkey[8], next, tmp;
+	int i;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	nettle_des_set_key(&ctx, pkey);
+	nettle_des_encrypt(&ctx, DES_BLOCK_SIZE, cypher, clear);
+	os_memset(&ctx, 0, sizeof(ctx));
+	return 0;
+}
+
+
+static int nettle_digest_vector(const struct nettle_hash *alg, size_t num_elem,
+				const u8 *addr[], const size_t *len, u8 *mac)
+{
+	void *ctx;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	ctx = os_malloc(alg->context_size);
+	if (!ctx)
+		return -1;
+	alg->init(ctx);
+	for (i = 0; i < num_elem; i++)
+		alg->update(ctx, len[i], addr[i]);
+	alg->digest(ctx, alg->digest_size, mac);
+	bin_clear_free(ctx, alg->context_size);
+	return 0;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nettle_digest_vector(&nettle_md4, num_elem, addr, len, mac);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nettle_digest_vector(&nettle_md5, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nettle_digest_vector(&nettle_sha1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nettle_digest_vector(&nettle_sha256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nettle_digest_vector(&nettle_sha384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nettle_digest_vector(&nettle_sha512, num_elem, addr, len, mac);
+}
+
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	struct hmac_md5_ctx ctx;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	hmac_md5_set_key(&ctx, key_len, key);
+	for (i = 0; i < num_elem; i++)
+		hmac_md5_update(&ctx, len[i], addr[i]);
+	hmac_md5_digest(&ctx, MD5_DIGEST_SIZE, mac);
+	os_memset(&ctx, 0, sizeof(ctx));
+	return 0;
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	struct hmac_sha1_ctx ctx;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	hmac_sha1_set_key(&ctx, key_len, key);
+	for (i = 0; i < num_elem; i++)
+		hmac_sha1_update(&ctx, len[i], addr[i]);
+	hmac_sha1_digest(&ctx, SHA1_DIGEST_SIZE, mac);
+	os_memset(&ctx, 0, sizeof(ctx));
+	return 0;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	struct hmac_sha256_ctx ctx;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	hmac_sha256_set_key(&ctx, key_len, key);
+	for (i = 0; i < num_elem; i++)
+		hmac_sha256_update(&ctx, len[i], addr[i]);
+	hmac_sha256_digest(&ctx, SHA256_DIGEST_SIZE, mac);
+	os_memset(&ctx, 0, sizeof(ctx));
+	return 0;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	struct hmac_sha384_ctx ctx;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	hmac_sha384_set_key(&ctx, key_len, key);
+	for (i = 0; i < num_elem; i++)
+		hmac_sha384_update(&ctx, len[i], addr[i]);
+	hmac_sha384_digest(&ctx, SHA384_DIGEST_SIZE, mac);
+	os_memset(&ctx, 0, sizeof(ctx));
+	return 0;
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	struct hmac_sha512_ctx ctx;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	hmac_sha512_set_key(&ctx, key_len, key);
+	for (i = 0; i < num_elem; i++)
+		hmac_sha512_update(&ctx, len[i], addr[i]);
+	hmac_sha512_digest(&ctx, SHA512_DIGEST_SIZE, mac);
+	os_memset(&ctx, 0, sizeof(ctx));
+	return 0;
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	struct aes_ctx *ctx;
+
+	if (TEST_FAIL())
+		return NULL;
+	ctx = os_malloc(sizeof(*ctx));
+	if (!ctx)
+		return NULL;
+
+	nettle_aes_set_encrypt_key(ctx, len, key);
+
+	return ctx;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	struct aes_ctx *actx = ctx;
+	nettle_aes_encrypt(actx, AES_BLOCK_SIZE, crypt, plain);
+	return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	struct aes_ctx *actx = ctx;
+	bin_clear_free(actx, sizeof(*actx));
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	struct aes_ctx *ctx;
+
+	if (TEST_FAIL())
+		return NULL;
+	ctx = os_malloc(sizeof(*ctx));
+	if (!ctx)
+		return NULL;
+
+	nettle_aes_set_decrypt_key(ctx, len, key);
+
+	return ctx;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	struct aes_ctx *actx = ctx;
+	nettle_aes_decrypt(actx, AES_BLOCK_SIZE, plain, crypt);
+	return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	struct aes_ctx *actx = ctx;
+	bin_clear_free(actx, sizeof(*actx));
+}
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+		   u8 *pubkey)
+{
+	size_t pubkey_len, pad;
+
+	if (os_get_random(privkey, prime_len) < 0)
+		return -1;
+	if (os_memcmp(privkey, prime, prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		privkey[0] = 0;
+	}
+
+	pubkey_len = prime_len;
+	if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+			   pubkey, &pubkey_len) < 0)
+		return -1;
+	if (pubkey_len < prime_len) {
+		pad = prime_len - pubkey_len;
+		os_memmove(pubkey + pad, pubkey, pubkey_len);
+		os_memset(pubkey, 0, pad);
+	}
+
+	return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+			    const u8 *privkey, size_t privkey_len,
+			    const u8 *pubkey, size_t pubkey_len,
+			    u8 *secret, size_t *len)
+{
+	return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+			      prime, prime_len, secret, len);
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	mpz_t bn_base, bn_exp, bn_modulus, bn_result;
+	int ret = -1;
+	size_t len;
+
+	mpz_inits(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+	mpz_import(bn_base, base_len, 1, 1, 1, 0, base);
+	mpz_import(bn_exp, power_len, 1, 1, 1, 0, power);
+	mpz_import(bn_modulus, modulus_len, 1, 1, 1, 0, modulus);
+
+	mpz_powm(bn_result, bn_base, bn_exp, bn_modulus);
+	len = mpz_sizeinbase(bn_result, 2);
+	len = (len + 7) / 8;
+	if (*result_len < len)
+		goto error;
+	mpz_export(result, result_len, 1, 1, 1, 0, bn_result);
+	ret = 0;
+
+error:
+	mpz_clears(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+	return ret;
+}
+
+
+struct crypto_cipher {
+	enum crypto_cipher_alg alg;
+	union {
+		struct arcfour_ctx arcfour_ctx;
+	} u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (!ctx)
+		return NULL;
+
+	ctx->alg = alg;
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		nettle_arcfour_set_key(&ctx->u.arcfour_ctx, key_len, key);
+		break;
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, crypt, plain);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, plain, crypt);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	bin_clear_free(ctx, sizeof(*ctx));
+}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 6bff202..f4cff43 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -33,7 +33,9 @@
 #include "aes_wrap.h"
 #include "crypto.h"
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 /* Compatibility wrappers for older versions. */
 
 static HMAC_CTX * HMAC_CTX_new(void)
@@ -79,7 +81,9 @@
 
 static BIGNUM * get_group5_prime(void)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+	!(defined(LIBRESSL_VERSION_NUMBER) && \
+	  LIBRESSL_VERSION_NUMBER < 0x20700000L)
 	return BN_get_rfc3526_prime_1536(NULL);
 #elif !defined(OPENSSL_IS_BORINGSSL)
 	return get_rfc3526_prime_1536(NULL);
@@ -270,10 +274,8 @@
 	switch (keylen) {
 	case 16:
 		return EVP_aes_128_ecb();
-#ifndef OPENSSL_IS_BORINGSSL
 	case 24:
 		return EVP_aes_192_ecb();
-#endif /* OPENSSL_IS_BORINGSSL */
 	case 32:
 		return EVP_aes_256_ecb();
 	}
@@ -291,8 +293,11 @@
 		return NULL;
 
 	type = aes_get_evp_cipher(len);
-	if (type == NULL)
+	if (!type) {
+		wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+			   __func__, (unsigned int) len);
 		return NULL;
+	}
 
 	ctx = EVP_CIPHER_CTX_new();
 	if (ctx == NULL)
@@ -345,8 +350,11 @@
 		return NULL;
 
 	type = aes_get_evp_cipher(len);
-	if (type == NULL)
+	if (!type) {
+		wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+			   __func__, (unsigned int) len);
 		return NULL;
+	}
 
 	ctx = EVP_CIPHER_CTX_new();
 	if (ctx == NULL)
@@ -482,6 +490,42 @@
 }
 
 
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+		   u8 *pubkey)
+{
+	size_t pubkey_len, pad;
+
+	if (os_get_random(privkey, prime_len) < 0)
+		return -1;
+	if (os_memcmp(privkey, prime, prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		privkey[0] = 0;
+	}
+
+	pubkey_len = prime_len;
+	if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+			   pubkey, &pubkey_len) < 0)
+		return -1;
+	if (pubkey_len < prime_len) {
+		pad = prime_len - pubkey_len;
+		os_memmove(pubkey + pad, pubkey, pubkey_len);
+		os_memset(pubkey, 0, pad);
+	}
+
+	return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+			    const u8 *privkey, size_t privkey_len,
+			    const u8 *pubkey, size_t pubkey_len,
+			    u8 *secret, size_t *len)
+{
+	return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+			      prime, prime_len, secret, len);
+}
+
+
 int crypto_mod_exp(const u8 *base, size_t base_len,
 		   const u8 *power, size_t power_len,
 		   const u8 *modulus, size_t modulus_len,
@@ -641,7 +685,9 @@
 
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 	DH *dh;
 	struct wpabuf *pubkey = NULL, *privkey = NULL;
 	size_t publen, privlen;
@@ -742,7 +788,9 @@
 
 void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 	DH *dh;
 
 	dh = DH_new();
@@ -1199,6 +1247,12 @@
 }
 
 
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+	return BN_rand_range((BIGNUM *) r, (const BIGNUM *) m) == 1 ? 0 : -1;
+}
+
+
 int crypto_bignum_add(const struct crypto_bignum *a,
 		      const struct crypto_bignum *b,
 		      struct crypto_bignum *c)
@@ -1324,6 +1378,15 @@
 }
 
 
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+			 struct crypto_bignum *r)
+{
+	/* Note: BN_rshift() does not modify the first argument even though it
+	 * has not been marked const. */
+	return BN_rshift((BIGNUM *) a, (BIGNUM *) r, n) == 1 ? 0 : -1;
+}
+
+
 int crypto_bignum_cmp(const struct crypto_bignum *a,
 		      const struct crypto_bignum *b)
 {
@@ -1349,6 +1412,12 @@
 }
 
 
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+	return BN_is_odd((const BIGNUM *) a);
+}
+
+
 int crypto_bignum_legendre(const struct crypto_bignum *a,
 			   const struct crypto_bignum *p)
 {
@@ -1483,6 +1552,13 @@
 }
 
 
+int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor)
+{
+	return EC_GROUP_get_cofactor(e->group, (BIGNUM *) cofactor,
+				     e->bnctx) == 0 ? -1 : 0;
+}
+
+
 struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
 {
 	if (TEST_FAIL())
@@ -1505,6 +1581,12 @@
 }
 
 
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+	return BN_num_bytes(e->order);
+}
+
+
 const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
 {
 	return (const struct crypto_bignum *) e->prime;
@@ -1526,6 +1608,16 @@
 }
 
 
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+		      struct crypto_bignum *x)
+{
+	return EC_POINT_get_affine_coordinates_GFp(e->group,
+						   (const EC_POINT *) p,
+						   (BIGNUM *) x, NULL,
+						   e->bnctx) == 1 ? 0 : -1;
+}
+
+
 int crypto_ec_point_to_bin(struct crypto_ec *e,
 			   const struct crypto_ec_point *point, u8 *x, u8 *y)
 {
@@ -1701,7 +1793,7 @@
 {
 	struct crypto_ecdh *ecdh;
 	EVP_PKEY *params = NULL;
-	EVP_PKEY_CTX *pctx = NULL;
+	EC_KEY *ec_params;
 	EVP_PKEY_CTX *kctx = NULL;
 
 	ecdh = os_zalloc(sizeof(*ecdh));
@@ -1712,27 +1804,17 @@
 	if (!ecdh->ec)
 		goto fail;
 
-	pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
-	if (!pctx)
-		goto fail;
-
-	if (EVP_PKEY_paramgen_init(pctx) != 1) {
+	ec_params = EC_KEY_new_by_curve_name(ecdh->ec->nid);
+	if (!ec_params) {
 		wpa_printf(MSG_ERROR,
-			   "OpenSSL: EVP_PKEY_paramgen_init failed: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+			   "OpenSSL: Failed to generate EC_KEY parameters");
 		goto fail;
 	}
-
-	if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecdh->ec->nid) != 1) {
+	EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
+	params = EVP_PKEY_new();
+	if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
 		wpa_printf(MSG_ERROR,
-			   "OpenSSL: EVP_PKEY_CTX_set_ec_paramgen_curve_nid failed: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
-		goto fail;
-	}
-
-	if (EVP_PKEY_paramgen(pctx, &params) != 1) {
-		wpa_printf(MSG_ERROR, "OpenSSL: EVP_PKEY_paramgen failed: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+			   "OpenSSL: Failed to generate EVP_PKEY parameters");
 		goto fail;
 	}
 
@@ -1755,7 +1837,6 @@
 
 done:
 	EVP_PKEY_free(params);
-	EVP_PKEY_CTX_free(pctx);
 	EVP_PKEY_CTX_free(kctx);
 
 	return ecdh;
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
new file mode 100644
index 0000000..b5a1e3f
--- /dev/null
+++ b/src/crypto/crypto_wolfssl.c
@@ -0,0 +1,1791 @@
+/*
+ * Wrapper functions for libwolfssl
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+/* wolfSSL headers */
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/md4.h>
+#include <wolfssl/wolfcrypt/md5.h>
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/sha256.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/arc4.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/dh.h>
+#include <wolfssl/wolfcrypt/cmac.h>
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/openssl/bn.h>
+
+
+#ifndef CONFIG_FIPS
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	Md4 md4;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	wc_InitMd4(&md4);
+
+	for (i = 0; i < num_elem; i++)
+		wc_Md4Update(&md4, addr[i], len[i]);
+
+	wc_Md4Final(&md4, mac);
+
+	return 0;
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	wc_Md5 md5;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	wc_InitMd5(&md5);
+
+	for (i = 0; i < num_elem; i++)
+		wc_Md5Update(&md5, addr[i], len[i]);
+
+	wc_Md5Final(&md5, mac);
+
+	return 0;
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	wc_Sha sha;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	wc_InitSha(&sha);
+
+	for (i = 0; i < num_elem; i++)
+		wc_ShaUpdate(&sha, addr[i], len[i]);
+
+	wc_ShaFinal(&sha, mac);
+
+	return 0;
+}
+
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	wc_Sha256 sha256;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	wc_InitSha256(&sha256);
+
+	for (i = 0; i < num_elem; i++)
+		wc_Sha256Update(&sha256, addr[i], len[i]);
+
+	wc_Sha256Final(&sha256, mac);
+
+	return 0;
+}
+#endif /* NO_SHA256_WRAPPER */
+
+
+#ifdef CONFIG_SHA384
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	wc_Sha384 sha384;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	wc_InitSha384(&sha384);
+
+	for (i = 0; i < num_elem; i++)
+		wc_Sha384Update(&sha384, addr[i], len[i]);
+
+	wc_Sha384Final(&sha384, mac);
+
+	return 0;
+}
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	wc_Sha512 sha512;
+	size_t i;
+
+	if (TEST_FAIL())
+		return -1;
+
+	wc_InitSha512(&sha512);
+
+	for (i = 0; i < num_elem; i++)
+		wc_Sha512Update(&sha512, addr[i], len[i]);
+
+	wc_Sha512Final(&sha512, mac);
+
+	return 0;
+}
+#endif /* CONFIG_SHA512 */
+
+
+static int wolfssl_hmac_vector(int type, const u8 *key,
+			       size_t key_len, size_t num_elem,
+			       const u8 *addr[], const size_t *len, u8 *mac,
+			       unsigned int mdlen)
+{
+	Hmac hmac;
+	size_t i;
+
+	(void) mdlen;
+
+	if (TEST_FAIL())
+		return -1;
+
+	if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+		return -1;
+	for (i = 0; i < num_elem; i++)
+		if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
+			return -1;
+	if (wc_HmacFinal(&hmac, mac) != 0)
+		return -1;
+	return 0;
+}
+
+
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return wolfssl_hmac_vector(WC_MD5, key, key_len, num_elem, addr, len,
+				   mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return wolfssl_hmac_vector(WC_SHA, key, key_len, num_elem, addr, len,
+				   mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	      u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return wolfssl_hmac_vector(WC_SHA256, key, key_len, num_elem, addr, len,
+				   mac, 32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return wolfssl_hmac_vector(WC_SHA384, key, key_len, num_elem, addr, len,
+				   mac, 48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return wolfssl_hmac_vector(WC_SHA512, key, key_len, num_elem, addr, len,
+				   mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+	if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
+		      ssid_len, iterations, buflen, WC_SHA) != 0)
+		return -1;
+	return 0;
+}
+
+
+#ifdef CONFIG_DES
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	Des des;
+	u8  pkey[8], next, tmp;
+	int i;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	wc_Des_SetKey(&des, pkey, NULL, DES_ENCRYPTION);
+	wc_Des_EcbEncrypt(&des, cypher, clear, DES_BLOCK_SIZE);
+
+	return 0;
+}
+#endif /* CONFIG_DES */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	Aes *aes;
+
+	if (TEST_FAIL())
+		return NULL;
+
+	aes = os_malloc(sizeof(Aes));
+	if (!aes)
+		return NULL;
+
+	if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) {
+		os_free(aes);
+		return NULL;
+	}
+
+	return aes;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	wc_AesEncryptDirect(ctx, crypt, plain);
+	return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	os_free(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	Aes *aes;
+
+	if (TEST_FAIL())
+		return NULL;
+
+	aes = os_malloc(sizeof(Aes));
+	if (!aes)
+		return NULL;
+
+	if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) {
+		os_free(aes);
+		return NULL;
+	}
+
+	return aes;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	wc_AesDecryptDirect(ctx, plain, crypt);
+	return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	os_free(ctx);
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	Aes aes;
+	int ret;
+
+	if (TEST_FAIL())
+		return -1;
+
+	ret = wc_AesSetKey(&aes, key, 16, iv, AES_ENCRYPTION);
+	if (ret != 0)
+		return -1;
+
+	ret = wc_AesCbcEncrypt(&aes, data, data, data_len);
+	if (ret != 0)
+		return -1;
+	return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	Aes aes;
+	int ret;
+
+	if (TEST_FAIL())
+		return -1;
+
+	ret = wc_AesSetKey(&aes, key, 16, iv, AES_DECRYPTION);
+	if (ret != 0)
+		return -1;
+
+	ret = wc_AesCbcDecrypt(&aes, data, data, data_len);
+	if (ret != 0)
+		return -1;
+	return 0;
+}
+
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+	int ret;
+
+	if (TEST_FAIL())
+		return -1;
+
+	ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
+			    NULL);
+	return ret != (n + 1) * 8 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+	       u8 *plain)
+{
+	int ret;
+
+	if (TEST_FAIL())
+		return -1;
+
+	ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
+			      NULL);
+	return ret != n * 8 ? -1 : 0;
+}
+
+
+#ifndef CONFIG_NO_RC4
+int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data,
+	     size_t data_len)
+{
+#ifndef NO_RC4
+	Arc4 arc4;
+	unsigned char skip_buf[16];
+
+	wc_Arc4SetKey(&arc4, key, keylen);
+
+	while (skip >= sizeof(skip_buf)) {
+		size_t len = skip;
+
+		if (len > sizeof(skip_buf))
+			len = sizeof(skip_buf);
+		wc_Arc4Process(&arc4, skip_buf, skip_buf, len);
+		skip -= len;
+	}
+
+	wc_Arc4Process(&arc4, data, data, data_len);
+
+	return 0;
+#else /* NO_RC4 */
+	return -1;
+#endif /* NO_RC4 */
+}
+#endif /* CONFIG_NO_RC4 */
+
+
+#if defined(EAP_IKEV2) || defined(EAP_IKEV2_DYNAMIC) \
+		       || defined(EAP_SERVER_IKEV2)
+union wolfssl_cipher {
+	Aes aes;
+	Des3 des3;
+	Arc4 arc4;
+};
+
+struct crypto_cipher {
+	enum crypto_cipher_alg alg;
+	union wolfssl_cipher enc;
+	union wolfssl_cipher dec;
+};
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (!ctx)
+		return NULL;
+
+	switch (alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+	case CRYPTO_CIPHER_ALG_RC4:
+		wc_Arc4SetKey(&ctx->enc.arc4, key, key_len);
+		wc_Arc4SetKey(&ctx->dec.arc4, key, key_len);
+		break;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+	case CRYPTO_CIPHER_ALG_AES:
+		switch (key_len) {
+		case 16:
+		case 24:
+		case 32:
+			break;
+		default:
+			os_free(ctx);
+			return NULL;
+		}
+		if (wc_AesSetKey(&ctx->enc.aes, key, key_len, iv,
+				 AES_ENCRYPTION) ||
+		    wc_AesSetKey(&ctx->dec.aes, key, key_len, iv,
+				 AES_DECRYPTION)) {
+			os_free(ctx);
+			return NULL;
+		}
+		break;
+#endif /* NO_AES */
+#ifndef NO_DES3
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (key_len != DES3_KEYLEN ||
+		    wc_Des3_SetKey(&ctx->enc.des3, key, iv, DES_ENCRYPTION) ||
+		    wc_Des3_SetKey(&ctx->dec.des3, key, iv, DES_DECRYPTION)) {
+			os_free(ctx);
+			return NULL;
+		}
+		break;
+#endif /* NO_DES3 */
+	case CRYPTO_CIPHER_ALG_RC2:
+	case CRYPTO_CIPHER_ALG_DES:
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	ctx->alg = alg;
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+	case CRYPTO_CIPHER_ALG_RC4:
+		wc_Arc4Process(&ctx->enc.arc4, crypt, plain, len);
+		return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+	case CRYPTO_CIPHER_ALG_AES:
+		if (wc_AesCbcEncrypt(&ctx->enc.aes, crypt, plain, len) != 0)
+			return -1;
+		return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (wc_Des3_CbcEncrypt(&ctx->enc.des3, crypt, plain, len) != 0)
+			return -1;
+		return 0;
+#endif /* NO_DES3 */
+	default:
+		return -1;
+	}
+	return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+	case CRYPTO_CIPHER_ALG_RC4:
+		wc_Arc4Process(&ctx->dec.arc4, plain, crypt, len);
+		return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+	case CRYPTO_CIPHER_ALG_AES:
+		if (wc_AesCbcDecrypt(&ctx->dec.aes, plain, crypt, len) != 0)
+			return -1;
+		return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (wc_Des3_CbcDecrypt(&ctx->dec.des3, plain, crypt, len) != 0)
+			return -1;
+		return 0;
+#endif /* NO_DES3 */
+	default:
+		return -1;
+	}
+	return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	os_free(ctx);
+}
+
+#endif
+
+
+#ifdef CONFIG_WPS_NFC
+
+static const unsigned char RFC3526_PRIME_1536[] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+	0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+	0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+	0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+	0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
+	0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
+	0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
+	0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static const unsigned char RFC3526_GENERATOR_1536[] = {
+	0x02
+};
+
+#define RFC3526_LEN sizeof(RFC3526_PRIME_1536)
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	WC_RNG rng;
+	DhKey *ret = NULL;
+	DhKey *dh = NULL;
+	struct wpabuf *privkey = NULL;
+	struct wpabuf *pubkey = NULL;
+	word32 priv_sz, pub_sz;
+
+	*priv = NULL;
+	wpabuf_free(*publ);
+	*publ = NULL;
+
+	dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+	if (!dh)
+		return NULL;
+	wc_InitDhKey(dh);
+
+	if (wc_InitRng(&rng) != 0) {
+		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+		return NULL;
+	}
+
+	privkey = wpabuf_alloc(RFC3526_LEN);
+	pubkey = wpabuf_alloc(RFC3526_LEN);
+	if (!privkey || !pubkey)
+		goto done;
+
+	if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+			RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+	    != 0)
+		goto done;
+
+	if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz,
+				 wpabuf_mhead(pubkey), &pub_sz) != 0)
+		goto done;
+
+	wpabuf_put(privkey, priv_sz);
+	wpabuf_put(pubkey, pub_sz);
+
+	ret = dh;
+	*priv = privkey;
+	*publ = pubkey;
+	dh = NULL;
+	privkey = NULL;
+	pubkey = NULL;
+done:
+	wpabuf_clear_free(pubkey);
+	wpabuf_clear_free(privkey);
+	if (dh) {
+		wc_FreeDhKey(dh);
+		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+	}
+	wc_FreeRng(&rng);
+	return ret;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+	DhKey *ret = NULL;
+	DhKey *dh;
+	byte *secret;
+	word32 secret_sz;
+
+	dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+	if (!dh)
+		return NULL;
+	wc_InitDhKey(dh);
+
+	secret = XMALLOC(RFC3526_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+	if (!secret)
+		goto done;
+
+	if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+			RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+	    != 0)
+		goto done;
+
+	if (wc_DhAgree(dh, secret, &secret_sz, wpabuf_head(priv),
+		       wpabuf_len(priv), RFC3526_GENERATOR_1536,
+		       sizeof(RFC3526_GENERATOR_1536)) != 0)
+		goto done;
+
+	if (secret_sz != wpabuf_len(publ) ||
+	    os_memcmp(secret, wpabuf_head(publ), secret_sz) != 0)
+		goto done;
+
+	ret = dh;
+	dh = NULL;
+done:
+	if (dh) {
+		wc_FreeDhKey(dh);
+		XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+	}
+	XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+	return ret;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	struct wpabuf *ret = NULL;
+	struct wpabuf *secret;
+	word32 secret_sz;
+
+	secret = wpabuf_alloc(RFC3526_LEN);
+	if (!secret)
+		goto done;
+
+	if (wc_DhAgree(ctx, wpabuf_mhead(secret), &secret_sz,
+		       wpabuf_head(own_private), wpabuf_len(own_private),
+		       wpabuf_head(peer_public), wpabuf_len(peer_public)) != 0)
+		goto done;
+
+	wpabuf_put(secret, secret_sz);
+
+	ret = secret;
+	secret = NULL;
+done:
+	wpabuf_clear_free(secret);
+	return ret;
+}
+
+
+void dh5_free(void *ctx)
+{
+	if (!ctx)
+		return;
+
+	wc_FreeDhKey(ctx);
+	XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+		   u8 *pubkey)
+{
+	int ret = -1;
+	WC_RNG rng;
+	DhKey *dh = NULL;
+	word32 priv_sz, pub_sz;
+
+	if (TEST_FAIL())
+		return -1;
+
+	dh = os_malloc(sizeof(DhKey));
+	if (!dh)
+		return -1;
+	wc_InitDhKey(dh);
+
+	if (wc_InitRng(&rng) != 0) {
+		os_free(dh);
+		return -1;
+	}
+
+	if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+		goto done;
+
+	if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz)
+	    != 0)
+		goto done;
+
+	if (priv_sz < prime_len) {
+		size_t pad_sz = prime_len - priv_sz;
+
+		os_memmove(privkey + pad_sz, privkey, priv_sz);
+		os_memset(privkey, 0, pad_sz);
+	}
+
+	if (pub_sz < prime_len) {
+		size_t pad_sz = prime_len - pub_sz;
+
+		os_memmove(pubkey + pad_sz, pubkey, pub_sz);
+		os_memset(pubkey, 0, pad_sz);
+	}
+	ret = 0;
+done:
+	wc_FreeDhKey(dh);
+	os_free(dh);
+	wc_FreeRng(&rng);
+	return ret;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+			    const u8 *privkey, size_t privkey_len,
+			    const u8 *pubkey, size_t pubkey_len,
+			    u8 *secret, size_t *len)
+{
+	int ret = -1;
+	DhKey *dh;
+	word32 secret_sz;
+
+	dh = os_malloc(sizeof(DhKey));
+	if (!dh)
+		return -1;
+	wc_InitDhKey(dh);
+
+	if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+		goto done;
+
+	if (wc_DhAgree(dh, secret, &secret_sz, privkey, privkey_len, pubkey,
+		       pubkey_len) != 0)
+		goto done;
+
+	*len = secret_sz;
+	ret = 0;
+done:
+	wc_FreeDhKey(dh);
+	os_free(dh);
+	return ret;
+}
+
+
+#ifdef CONFIG_FIPS
+int crypto_get_random(void *buf, size_t len)
+{
+	int ret = 0;
+	WC_RNG rng;
+
+	if (wc_InitRng(&rng) != 0)
+		return -1;
+	if (wc_RNG_GenerateBlock(&rng, buf, len) != 0)
+		ret = -1;
+	wc_FreeRng(&rng);
+	return ret;
+}
+#endif /* CONFIG_FIPS */
+
+
+#if defined(EAP_PWD) || defined(EAP_SERVER_PWD)
+struct crypto_hash {
+	Hmac hmac;
+	int size;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ret = NULL;
+	struct crypto_hash *hash;
+	int type;
+
+	hash = os_zalloc(sizeof(*hash));
+	if (!hash)
+		goto done;
+
+	switch (alg) {
+#ifndef NO_MD5
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		hash->size = 16;
+		type = WC_MD5;
+		break;
+#endif /* NO_MD5 */
+#ifndef NO_SHA
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		type = WC_SHA;
+		hash->size = 20;
+		break;
+#endif /* NO_SHA */
+#ifdef CONFIG_SHA256
+#ifndef NO_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		type = WC_SHA256;
+		hash->size = 32;
+		break;
+#endif /* NO_SHA256 */
+#endif /* CONFIG_SHA256 */
+	default:
+		goto done;
+	}
+
+	if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+		goto done;
+
+	ret = hash;
+	hash = NULL;
+done:
+	os_free(hash);
+	return ret;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (!ctx)
+		return;
+	wc_HmacUpdate(&ctx->hmac, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	int ret = 0;
+
+	if (!ctx)
+		return -2;
+
+	if (!mac || !len)
+		goto done;
+
+	if (wc_HmacFinal(&ctx->hmac, mac) != 0) {
+		ret = -1;
+		goto done;
+	}
+
+	*len = ctx->size;
+	ret = 0;
+done:
+	bin_clear_free(ctx, sizeof(*ctx));
+	return ret;
+}
+
+#endif
+
+
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	Cmac cmac;
+	size_t i;
+	word32 sz;
+
+	if (TEST_FAIL())
+		return -1;
+
+	if (wc_InitCmac(&cmac, key, key_len, WC_CMAC_AES, NULL) != 0)
+		return -1;
+
+	for (i = 0; i < num_elem; i++)
+		if (wc_CmacUpdate(&cmac, addr[i], len[i]) != 0)
+			return -1;
+
+	sz = AES_BLOCK_SIZE;
+	if (wc_CmacFinal(&cmac, mac, &sz) != 0 || sz != AES_BLOCK_SIZE)
+		return -1;
+
+	return 0;
+}
+
+
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
+
+
+struct crypto_bignum * crypto_bignum_init(void)
+{
+	mp_int *a;
+
+	if (TEST_FAIL())
+		return NULL;
+
+	a = os_malloc(sizeof(*a));
+	if (!a || mp_init(a) != MP_OKAY) {
+		os_free(a);
+		a = NULL;
+	}
+
+	return (struct crypto_bignum *) a;
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+	mp_int *a;
+
+	if (TEST_FAIL())
+		return NULL;
+
+	a = (mp_int *) crypto_bignum_init();
+	if (!a)
+		return NULL;
+
+	if (mp_read_unsigned_bin(a, buf, len) != MP_OKAY) {
+		os_free(a);
+		a = NULL;
+	}
+
+	return (struct crypto_bignum *) a;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+	if (!n)
+		return;
+
+	if (clear)
+		mp_forcezero((mp_int *) n);
+	mp_clear((mp_int *) n);
+	os_free((mp_int *) n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+			 u8 *buf, size_t buflen, size_t padlen)
+{
+	int num_bytes, offset;
+
+	if (TEST_FAIL())
+		return -1;
+
+	if (padlen > buflen)
+		return -1;
+
+	num_bytes = (mp_count_bits((mp_int *) a) + 7) / 8;
+	if ((size_t) num_bytes > buflen)
+		return -1;
+	if (padlen > (size_t) num_bytes)
+		offset = padlen - num_bytes;
+	else
+		offset = 0;
+
+	os_memset(buf, 0, offset);
+	mp_to_unsigned_bin((mp_int *) a, buf + offset);
+
+	return num_bytes + offset;
+}
+
+
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+	int ret = 0;
+	WC_RNG rng;
+
+	if (wc_InitRng(&rng) != 0)
+		return -1;
+	if (mp_rand_prime((mp_int *) r,
+			  (mp_count_bits((mp_int *) m) + 7) / 8 * 2,
+			  &rng, NULL) != 0)
+		ret = -1;
+	if (ret == 0 &&
+	    mp_mod((mp_int *) r, (mp_int *) m, (mp_int *) r) != 0)
+		ret = -1;
+	wc_FreeRng(&rng);
+	return ret;
+}
+
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+		      const struct crypto_bignum *b,
+		      struct crypto_bignum *r)
+{
+	return mp_add((mp_int *) a, (mp_int *) b,
+		      (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+		      const struct crypto_bignum *m,
+		      struct crypto_bignum *r)
+{
+	return mp_mod((mp_int *) a, (mp_int *) m,
+		      (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *b,
+			  const struct crypto_bignum *e,
+			  const struct crypto_bignum *m,
+			  struct crypto_bignum *r)
+{
+	if (TEST_FAIL())
+		return -1;
+
+	return mp_exptmod((mp_int *) b, (mp_int *) e, (mp_int *) m,
+			  (mp_int *) r) == MP_OKAY ?  0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+			  const struct crypto_bignum *m,
+			  struct crypto_bignum *r)
+{
+	if (TEST_FAIL())
+		return -1;
+
+	return mp_invmod((mp_int *) a, (mp_int *) m,
+			 (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+		      const struct crypto_bignum *b,
+		      struct crypto_bignum *r)
+{
+	if (TEST_FAIL())
+		return -1;
+
+	return mp_add((mp_int *) a, (mp_int *) b,
+		      (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+		      const struct crypto_bignum *b,
+		      struct crypto_bignum *d)
+{
+	if (TEST_FAIL())
+		return -1;
+
+	return mp_div((mp_int *) a, (mp_int *) b, (mp_int *) d,
+		      NULL) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+			 const struct crypto_bignum *b,
+			 const struct crypto_bignum *m,
+			 struct crypto_bignum *d)
+{
+	if (TEST_FAIL())
+		return -1;
+
+	return mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) m,
+			 (mp_int *) d) == MP_OKAY ?  0 : -1;
+}
+
+
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+			 struct crypto_bignum *r)
+{
+	if (mp_copy((mp_int *) a, (mp_int *) r) != MP_OKAY)
+		return -1;
+	mp_rshb((mp_int *) r, n);
+	return 0;
+}
+
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+		      const struct crypto_bignum *b)
+{
+	return mp_cmp((mp_int *) a, (mp_int *) b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+	return mp_count_bits((mp_int *) a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+	return mp_iszero((mp_int *) a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+	return mp_isone((const mp_int *) a);
+}
+
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+	return mp_isodd((mp_int *) a);
+}
+
+
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+			   const struct crypto_bignum *p)
+{
+	mp_int t;
+	int ret;
+	int res = -2;
+
+	if (TEST_FAIL())
+		return -2;
+
+	if (mp_init(&t) != MP_OKAY)
+		return -2;
+
+	/* t = (p-1) / 2 */
+	ret = mp_sub_d((mp_int *) p, 1, &t);
+	if (ret == MP_OKAY)
+		mp_rshb(&t, 1);
+	if (ret == MP_OKAY)
+		ret = mp_exptmod((mp_int *) a, &t, (mp_int *) p, &t);
+	if (ret == MP_OKAY) {
+		if (mp_isone(&t))
+			res = 1;
+		else if (mp_iszero(&t))
+			res = 0;
+		else
+			res = -1;
+	}
+
+	mp_clear(&t);
+	return res;
+}
+
+
+#ifdef CONFIG_ECC
+
+int ecc_map(ecc_point *, mp_int *, mp_digit);
+int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
+			     mp_int *a, mp_int *modulus, mp_digit mp);
+
+struct crypto_ec {
+	ecc_key key;
+	mp_int a;
+	mp_int prime;
+	mp_int order;
+	mp_digit mont_b;
+	mp_int b;
+};
+
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+	int built = 0;
+	struct crypto_ec *e;
+	int curve_id;
+
+	/* Map from IANA registry for IKE D-H groups to OpenSSL NID */
+	switch (group) {
+	case 19:
+		curve_id = ECC_SECP256R1;
+		break;
+	case 20:
+		curve_id = ECC_SECP384R1;
+		break;
+	case 21:
+		curve_id = ECC_SECP521R1;
+		break;
+	case 25:
+		curve_id = ECC_SECP192R1;
+		break;
+	case 26:
+		curve_id = ECC_SECP224R1;
+		break;
+#ifdef HAVE_ECC_BRAINPOOL
+	case 27:
+		curve_id = ECC_BRAINPOOLP224R1;
+		break;
+	case 28:
+		curve_id = ECC_BRAINPOOLP256R1;
+		break;
+	case 29:
+		curve_id = ECC_BRAINPOOLP384R1;
+		break;
+	case 30:
+		curve_id = ECC_BRAINPOOLP512R1;
+		break;
+#endif /* HAVE_ECC_BRAINPOOL */
+	default:
+		return NULL;
+	}
+
+	e = os_zalloc(sizeof(*e));
+	if (!e)
+		return NULL;
+
+	if (wc_ecc_init(&e->key) != 0 ||
+	    wc_ecc_set_curve(&e->key, 0, curve_id) != 0 ||
+	    mp_init(&e->a) != MP_OKAY ||
+	    mp_init(&e->prime) != MP_OKAY ||
+	    mp_init(&e->order) != MP_OKAY ||
+	    mp_init(&e->b) != MP_OKAY ||
+	    mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY ||
+	    mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY ||
+	    mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY ||
+	    mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY ||
+	    mp_montgomery_setup(&e->prime, &e->mont_b) != MP_OKAY)
+		goto done;
+
+	built = 1;
+done:
+	if (!built) {
+		crypto_ec_deinit(e);
+		e = NULL;
+	}
+	return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec* e)
+{
+	if (!e)
+		return;
+
+	mp_clear(&e->b);
+	mp_clear(&e->order);
+	mp_clear(&e->prime);
+	mp_clear(&e->a);
+	wc_ecc_free(&e->key);
+	os_free(e);
+}
+
+
+int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor)
+{
+	if (!e || !cofactor)
+		return -1;
+
+	mp_set((mp_int *) cofactor, e->key.dp->cofactor);
+	return 0;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
+{
+	if (TEST_FAIL())
+		return NULL;
+	if (!e)
+		return NULL;
+	return (struct crypto_ec_point *) wc_ecc_new_point();
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+	return (mp_count_bits(&e->prime) + 7) / 8;
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+	return mp_count_bits(&e->prime);
+}
+
+
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+	return (mp_count_bits(&e->order) + 7) / 8;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+	return (const struct crypto_bignum *) &e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+	return (const struct crypto_bignum *) &e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+	ecc_point *point = (ecc_point *) p;
+
+	if (!p)
+		return;
+
+	if (clear) {
+		mp_forcezero(point->x);
+		mp_forcezero(point->y);
+		mp_forcezero(point->z);
+	}
+	wc_ecc_del_point(point);
+}
+
+
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+		      struct crypto_bignum *x)
+{
+	return mp_copy(((ecc_point *) p)->x, (mp_int *) x) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+			   const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+	ecc_point *p = (ecc_point *) point;
+
+	if (TEST_FAIL())
+		return -1;
+
+	if (!mp_isone(p->z)) {
+		if (ecc_map(p, &e->prime, e->mont_b) != MP_OKAY)
+			return -1;
+	}
+
+	if (x) {
+		if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x,
+					 e->key.dp->size,
+					 e->key.dp->size) <= 0)
+			return -1;
+	}
+
+	if (y) {
+		if (crypto_bignum_to_bin((struct crypto_bignum *) p->y, y,
+					 e->key.dp->size,
+					 e->key.dp->size) <= 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+						  const u8 *val)
+{
+	ecc_point *point = NULL;
+	int loaded = 0;
+
+	if (TEST_FAIL())
+		return NULL;
+
+	point = wc_ecc_new_point();
+	if (!point)
+		goto done;
+
+	if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY)
+		goto done;
+	val += e->key.dp->size;
+	if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY)
+		goto done;
+	mp_set(point->z, 1);
+
+	loaded = 1;
+done:
+	if (!loaded) {
+		wc_ecc_del_point(point);
+		point = NULL;
+	}
+	return (struct crypto_ec_point *) point;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+			const struct crypto_ec_point *b,
+			struct crypto_ec_point *c)
+{
+	mp_int mu;
+	ecc_point *ta = NULL, *tb = NULL;
+	ecc_point *pa = (ecc_point *) a, *pb = (ecc_point *) b;
+	mp_int *modulus = &e->prime;
+	int ret;
+
+	if (TEST_FAIL())
+		return -1;
+
+	ret = mp_init(&mu);
+	if (ret != MP_OKAY)
+		return -1;
+
+	ret = mp_montgomery_calc_normalization(&mu, modulus);
+	if (ret != MP_OKAY) {
+		mp_clear(&mu);
+		return -1;
+	}
+
+	if (!mp_isone(&mu)) {
+		ta = wc_ecc_new_point();
+		if (!ta) {
+			mp_clear(&mu);
+			return -1;
+		}
+		tb = wc_ecc_new_point();
+		if (!tb) {
+			wc_ecc_del_point(ta);
+			mp_clear(&mu);
+			return -1;
+		}
+
+		if (mp_mulmod(pa->x, &mu, modulus, ta->x) != MP_OKAY ||
+		    mp_mulmod(pa->y, &mu, modulus, ta->y) != MP_OKAY ||
+		    mp_mulmod(pa->z, &mu, modulus, ta->z) != MP_OKAY ||
+		    mp_mulmod(pb->x, &mu, modulus, tb->x) != MP_OKAY ||
+		    mp_mulmod(pb->y, &mu, modulus, tb->y) != MP_OKAY ||
+		    mp_mulmod(pb->z, &mu, modulus, tb->z) != MP_OKAY) {
+			ret = -1;
+			goto end;
+		}
+		pa = ta;
+		pb = tb;
+	}
+
+	ret = ecc_projective_add_point(pa, pb, (ecc_point *) c, &e->a,
+				       &e->prime, e->mont_b);
+	if (ret != 0) {
+		ret = -1;
+		goto end;
+	}
+
+	if (ecc_map((ecc_point *) c, &e->prime, e->mont_b) != MP_OKAY)
+		ret = -1;
+	else
+		ret = 0;
+end:
+	wc_ecc_del_point(tb);
+	wc_ecc_del_point(ta);
+	mp_clear(&mu);
+	return ret;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+			const struct crypto_bignum *b,
+			struct crypto_ec_point *res)
+{
+	int ret;
+
+	if (TEST_FAIL())
+		return -1;
+
+	ret = wc_ecc_mulmod((mp_int *) b, (ecc_point *) p, (ecc_point *) res,
+			    &e->a, &e->prime, 1);
+	return ret == 0 ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+	ecc_point *point = (ecc_point *) p;
+
+	if (TEST_FAIL())
+		return -1;
+
+	if (mp_sub(&e->prime, point->y, point->y) != MP_OKAY)
+		return -1;
+
+	return 0;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+				  struct crypto_ec_point *p,
+				  const struct crypto_bignum *x, int y_bit)
+{
+	byte buf[1 + 2 * MAX_ECC_BYTES];
+	int ret;
+	int prime_len = crypto_ec_prime_len(e);
+
+	if (TEST_FAIL())
+		return -1;
+
+	buf[0] = y_bit ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN;
+	ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len);
+	if (ret <= 0)
+		return -1;
+	ret = wc_ecc_import_point_der(buf, 1 + 2 * ret, e->key.idx,
+				      (ecc_point *) p);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+			      const struct crypto_bignum *x)
+{
+	mp_int *y2 = NULL;
+	mp_int t;
+	int calced = 0;
+
+	if (TEST_FAIL())
+		return NULL;
+
+	if (mp_init(&t) != MP_OKAY)
+		return NULL;
+
+	y2 = (mp_int *) crypto_bignum_init();
+	if (!y2)
+		goto done;
+
+	if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+	    mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
+	    mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
+	    mp_addmod(y2, &t, &e->prime, y2) != 0 ||
+	    mp_addmod(y2, &e->b, &e->prime, y2) != 0)
+		goto done;
+
+	calced = 1;
+done:
+	if (!calced) {
+		if (y2) {
+			mp_clear(y2);
+			os_free(y2);
+		}
+		mp_clear(&t);
+	}
+
+	return (struct crypto_bignum *) y2;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+				   const struct crypto_ec_point *p)
+{
+	return wc_ecc_point_is_at_infinity((ecc_point *) p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+				const struct crypto_ec_point *p)
+{
+	return wc_ecc_is_point((ecc_point *) p, &e->a, &e->b, &e->prime) ==
+		MP_OKAY;
+}
+
+
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+			const struct crypto_ec_point *a,
+			const struct crypto_ec_point *b)
+{
+	return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b);
+}
+
+
+struct crypto_ecdh {
+	struct crypto_ec *ec;
+};
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+	struct crypto_ecdh *ecdh = NULL;
+	WC_RNG rng;
+	int ret;
+
+	if (wc_InitRng(&rng) != 0)
+		goto fail;
+
+	ecdh = os_zalloc(sizeof(*ecdh));
+	if (!ecdh)
+		goto fail;
+
+	ecdh->ec = crypto_ec_init(group);
+	if (!ecdh->ec)
+		goto fail;
+
+	ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
+				 ecdh->ec->key.dp->id);
+	if (ret < 0)
+		goto fail;
+
+done:
+	wc_FreeRng(&rng);
+
+	return ecdh;
+fail:
+	crypto_ecdh_deinit(ecdh);
+	ecdh = NULL;
+	goto done;
+}
+
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+	if (ecdh) {
+		crypto_ec_deinit(ecdh->ec);
+		os_free(ecdh);
+	}
+}
+
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
+{
+	struct wpabuf *buf = NULL;
+	int ret;
+	int len = ecdh->ec->key.dp->size;
+
+	buf = wpabuf_alloc(inc_y ? 2 * len : len);
+	if (!buf)
+		goto fail;
+
+	ret = crypto_bignum_to_bin((struct crypto_bignum *)
+				   ecdh->ec->key.pubkey.x, wpabuf_put(buf, len),
+				   len, len);
+	if (ret < 0)
+		goto fail;
+	if (inc_y) {
+		ret = crypto_bignum_to_bin((struct crypto_bignum *)
+					   ecdh->ec->key.pubkey.y,
+					   wpabuf_put(buf, len), len, len);
+		if (ret < 0)
+			goto fail;
+	}
+
+done:
+	return buf;
+fail:
+	wpabuf_free(buf);
+	buf = NULL;
+	goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+					const u8 *key, size_t len)
+{
+	int ret;
+	struct wpabuf *pubkey = NULL;
+	struct wpabuf *secret = NULL;
+	word32 key_len = ecdh->ec->key.dp->size;
+	ecc_point *point = NULL;
+	size_t need_key_len = inc_y ? 2 * key_len : key_len;
+
+	if (len < need_key_len)
+		goto fail;
+	pubkey = wpabuf_alloc(1 + 2 * key_len);
+	if (!pubkey)
+		goto fail;
+	wpabuf_put_u8(pubkey, inc_y ? ECC_POINT_UNCOMP : ECC_POINT_COMP_EVEN);
+	wpabuf_put_data(pubkey, key, need_key_len);
+
+	point = wc_ecc_new_point();
+	if (!point)
+		goto fail;
+
+	ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len,
+				      ecdh->ec->key.idx, point);
+	if (ret != MP_OKAY)
+		goto fail;
+
+	secret = wpabuf_alloc(key_len);
+	if (!secret)
+		goto fail;
+
+	ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
+				      wpabuf_put(secret, key_len), &key_len);
+	if (ret != MP_OKAY)
+		goto fail;
+
+done:
+	wc_ecc_del_point(point);
+	wpabuf_free(pubkey);
+	return secret;
+fail:
+	wpabuf_free(secret);
+	secret = NULL;
+	goto done;
+}
+
+#endif /* CONFIG_ECC */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 7912361..a9b770e 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1151,7 +1151,7 @@
 { id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
 dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
 dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
-		
+
 
 static const struct dh_group dh_groups[] = {
 	DH_GROUP(5, 1),
@@ -1203,19 +1203,6 @@
 	if (*priv == NULL)
 		return NULL;
 
-	if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
-	{
-		wpabuf_clear_free(*priv);
-		*priv = NULL;
-		return NULL;
-	}
-
-	if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
-		/* Make sure private value is smaller than prime */
-		*(wpabuf_mhead_u8(*priv)) = 0;
-	}
-	wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
-
 	pv_len = dh->prime_len;
 	pv = wpabuf_alloc(pv_len);
 	if (pv == NULL) {
@@ -1223,17 +1210,17 @@
 		*priv = NULL;
 		return NULL;
 	}
-	if (crypto_mod_exp(dh->generator, dh->generator_len,
-			   wpabuf_head(*priv), wpabuf_len(*priv),
-			   dh->prime, dh->prime_len, wpabuf_mhead(pv),
-			   &pv_len) < 0) {
+	if (crypto_dh_init(*dh->generator, dh->prime, dh->prime_len,
+			   wpabuf_mhead(*priv), wpabuf_mhead(pv)) < 0) {
 		wpabuf_clear_free(pv);
-		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+		wpa_printf(MSG_INFO, "DH: crypto_dh_init failed");
 		wpabuf_clear_free(*priv);
 		*priv = NULL;
 		return NULL;
 	}
-	wpabuf_put(pv, pv_len);
+	wpabuf_put(*priv, dh->prime_len);
+	wpabuf_put(pv, dh->prime_len);
+	wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
 	wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
 
 	return pv;
@@ -1261,12 +1248,14 @@
 	shared = wpabuf_alloc(shared_len);
 	if (shared == NULL)
 		return NULL;
-	if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
-			   wpabuf_head(own_private), wpabuf_len(own_private),
-			   dh->prime, dh->prime_len,
-			   wpabuf_mhead(shared), &shared_len) < 0) {
+	if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+				    wpabuf_head(own_private),
+				    wpabuf_len(own_private),
+				    wpabuf_head(peer_public),
+				    wpabuf_len(peer_public),
+				    wpabuf_mhead(shared), &shared_len) < 0) {
 		wpabuf_clear_free(shared);
-		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+		wpa_printf(MSG_INFO, "DH: crypto_dh_derive_secret failed");
 		return NULL;
 	}
 	wpabuf_put(shared, shared_len);
diff --git a/src/crypto/fips_prf_wolfssl.c b/src/crypto/fips_prf_wolfssl.c
new file mode 100644
index 0000000..feb39db
--- /dev/null
+++ b/src/crypto/fips_prf_wolfssl.c
@@ -0,0 +1,87 @@
+/*
+ * FIPS 186-2 PRF for libcrypto
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static void sha1_transform(u32 *state, const u8 data[64])
+{
+	wc_Sha sha;
+
+	os_memset(&sha, 0, sizeof(sha));
+	sha.digest[0] = state[0];
+	sha.digest[1] = state[1];
+	sha.digest[2] = state[2];
+	sha.digest[3] = state[3];
+	sha.digest[4] = state[4];
+	wc_ShaUpdate(&sha, data, 64);
+	state[0] = sha.digest[0];
+	state[1] = sha.digest[1];
+	state[2] = sha.digest[2];
+	state[3] = sha.digest[3];
+	state[4] = sha.digest[4];
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	u8 xkey[64];
+	u32 t[5], _t[5];
+	int i, j, m, k;
+	u8 *xpos = x;
+	u32 carry;
+
+	if (seed_len < sizeof(xkey))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	t[0] = 0x67452301;
+	t[1] = 0xEFCDAB89;
+	t[2] = 0x98BADCFE;
+	t[3] = 0x10325476;
+	t[4] = 0xC3D2E1F0;
+
+	m = xlen / 40;
+	for (j = 0; j < m; j++) {
+		/* XSEED_j = 0 */
+		for (i = 0; i < 2; i++) {
+			/* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+			/* w_i = G(t, XVAL) */
+			os_memcpy(_t, t, 20);
+			sha1_transform(_t, xkey);
+			WPA_PUT_BE32(xpos, _t[0]);
+			WPA_PUT_BE32(xpos + 4, _t[1]);
+			WPA_PUT_BE32(xpos + 8, _t[2]);
+			WPA_PUT_BE32(xpos + 12, _t[3]);
+			WPA_PUT_BE32(xpos + 16, _t[4]);
+
+			/* XKEY = (1 + XKEY + w_i) mod 2^b */
+			carry = 1;
+			for (k = 19; k >= 0; k--) {
+				carry += xkey[k] + xpos[k];
+				xkey[k] = carry & 0xff;
+				carry >>= 8;
+			}
+
+			xpos += 20;
+		}
+		/* x_j = w_0|w_1 */
+	}
+
+	return 0;
+}
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 9774a69..6f4cf81 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -54,7 +54,6 @@
 static unsigned int own_pool_ready = 0;
 #define RANDOM_ENTROPY_SIZE 20
 static char *random_entropy_file = NULL;
-static int random_entropy_file_read = 0;
 
 #define MIN_COLLECT_ENTROPY 1000
 static unsigned int entropy = 0;
@@ -364,7 +363,6 @@
 
 	own_pool_ready = (u8) buf[0];
 	random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
-	random_entropy_file_read = 1;
 	os_free(buf);
 	wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
 		   "(own_pool_ready=%u)",
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index dc4117c..481b346 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -64,6 +64,7 @@
 		size_t hash_len;
 		const char *altsubject[TLS_MAX_ALT_SUBJECT];
 		int num_altsubject;
+		const char *serial_num;
 	} peer_cert;
 
 	struct {
@@ -101,6 +102,7 @@
 #define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
 #define TLS_CONN_SUITEB BIT(11)
 #define TLS_CONN_SUITEB_NO_ECDH BIT(12)
+#define TLS_CONN_DISABLE_TLSv1_3 BIT(13)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -252,6 +254,18 @@
 int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
 
 /**
+ * tls_connection_peer_serial_num - Fetch peer certificate serial number
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Allocated string buffer containing the peer certificate serial
+ * number or %NULL on error.
+ *
+ * The caller is responsible for freeing the returned buffer with os_free().
+ */
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn);
+
+/**
  * tls_connection_shutdown - Shutdown TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 8c76bfa..36dafd2 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -295,6 +295,14 @@
 }
 
 
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn)
+{
+	/* TODO */
+	return NULL;
+}
+
+
 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
 {
 	struct tls_global *global = ssl_ctx;
@@ -346,6 +354,9 @@
 			      const struct tls_connection_params *params)
 {
 	int ret;
+	const char *err;
+	char prio_buf[100];
+	const char *prio = NULL;
 
 	if (conn == NULL || params == NULL)
 		return -1;
@@ -397,9 +408,57 @@
 
 	conn->flags = params->flags;
 
+	if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
+			     TLS_CONN_DISABLE_TLSv1_1 |
+			     TLS_CONN_DISABLE_TLSv1_2)) {
+		os_snprintf(prio_buf, sizeof(prio_buf),
+			    "NORMAL:-VERS-SSL3.0%s%s%s",
+			    params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
+			    ":-VERS-TLS1.0" : "",
+			    params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
+			    ":-VERS-TLS1.1" : "",
+			    params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
+			    ":-VERS-TLS1.2" : "");
+		prio = prio_buf;
+	}
+
 	if (params->openssl_ciphers) {
-		wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
-		return -1;
+		if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
+			prio = "SUITEB128";
+		} else if (os_strcmp(params->openssl_ciphers,
+				     "SUITEB192") == 0) {
+			prio = "SUITEB192";
+		} else if ((params->flags & TLS_CONN_SUITEB) &&
+			   os_strcmp(params->openssl_ciphers,
+				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+		} else if (os_strcmp(params->openssl_ciphers,
+				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+		} else if (os_strcmp(params->openssl_ciphers,
+				     "DHE-RSA-AES256-GCM-SHA384") == 0) {
+			prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+		} else if (os_strcmp(params->openssl_ciphers,
+				     "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
+			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+		} else {
+			wpa_printf(MSG_INFO,
+				   "GnuTLS: openssl_ciphers not supported");
+			return -1;
+		}
+	} else if (params->flags & TLS_CONN_SUITEB) {
+		prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+	}
+
+	if (prio) {
+		wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
+		ret = gnutls_priority_set_direct(conn->session, prio, &err);
+		if (ret < 0) {
+			wpa_printf(MSG_ERROR,
+				   "GnuTLS: Priority string failure at '%s'",
+				   err);
+			return -1;
+		}
 	}
 
 	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
@@ -425,6 +484,13 @@
 					   gnutls_strerror(ret));
 				return -1;
 			}
+			wpa_printf(MSG_DEBUG,
+				   "GnuTLS: Successfully read CA cert '%s' in PEM format",
+				   params->ca_cert);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "GnuTLS: Successfully read CA cert '%s' in DER format",
+				   params->ca_cert);
 		}
 	} else if (params->ca_cert_blob) {
 		gnutls_datum_t ca;
@@ -472,6 +538,9 @@
 	}
 
 	if (params->client_cert && params->private_key) {
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
+			   params->client_cert, params->private_key);
 #if GNUTLS_VERSION_NUMBER >= 0x03010b
 		ret = gnutls_certificate_set_x509_key_file2(
 			conn->xcred, params->client_cert, params->private_key,
@@ -483,8 +552,9 @@
 			GNUTLS_X509_FMT_DER);
 #endif
 		if (ret < 0) {
-			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
-				   "in DER format: %s", gnutls_strerror(ret));
+			wpa_printf(MSG_DEBUG,
+				   "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
+				   gnutls_strerror(ret));
 #if GNUTLS_VERSION_NUMBER >= 0x03010b
 			ret = gnutls_certificate_set_x509_key_file2(
 				conn->xcred, params->client_cert,
@@ -501,11 +571,19 @@
 					   gnutls_strerror(ret));
 				return ret;
 			}
+			wpa_printf(MSG_DEBUG,
+				   "GnuTLS: Successfully read client cert/key in PEM format");
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "GnuTLS: Successfully read client cert/key in DER format");
 		}
 	} else if (params->private_key) {
 		int pkcs12_ok = 0;
 #ifdef PKCS12_FUNCS
 		/* Try to load in PKCS#12 format */
+		wpa_printf(MSG_DEBUG,
+			   "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
+			   params->private_key);
 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
 			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
 			params->private_key_passwd);
@@ -1333,6 +1411,7 @@
 	ret = gnutls_handshake(conn->session);
 	if (ret < 0) {
 		gnutls_alert_description_t alert;
+		union tls_event_data ev;
 
 		switch (ret) {
 		case GNUTLS_E_AGAIN:
@@ -1343,14 +1422,29 @@
 				conn->push_buf = wpabuf_alloc(0);
 			}
 			break;
+		case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
+			wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
+			if (conn->global->event_cb) {
+				os_memset(&ev, 0, sizeof(ev));
+				ev.alert.is_local = 1;
+				ev.alert.type = "fatal";
+				ev.alert.description = "insufficient security";
+				conn->global->event_cb(conn->global->cb_ctx,
+						       TLS_ALERT, &ev);
+			}
+			/*
+			 * Could send a TLS Alert to the server, but for now,
+			 * simply terminate handshake.
+			 */
+			conn->failed++;
+			conn->write_alerts++;
+			break;
 		case GNUTLS_E_FATAL_ALERT_RECEIVED:
 			alert = gnutls_alert_get(conn->session);
 			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
 				   __func__, gnutls_alert_get_name(alert));
 			conn->read_alerts++;
 			if (conn->global->event_cb != NULL) {
-				union tls_event_data ev;
-
 				os_memset(&ev, 0, sizeof(ev));
 				ev.alert.is_local = 0;
 				ev.alert.type = gnutls_alert_get_name(alert);
@@ -1501,16 +1595,53 @@
 int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
 		    char *buf, size_t buflen)
 {
-	/* TODO */
-	return -1;
+	gnutls_protocol_t ver;
+
+	ver = gnutls_protocol_get_version(conn->session);
+	if (ver == GNUTLS_TLS1_0)
+		os_strlcpy(buf, "TLSv1", buflen);
+	else if (ver == GNUTLS_TLS1_1)
+		os_strlcpy(buf, "TLSv1.1", buflen);
+	else if (ver == GNUTLS_TLS1_2)
+		os_strlcpy(buf, "TLSv1.2", buflen);
+	else
+		return -1;
+	return 0;
 }
 
 
 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
 		   char *buf, size_t buflen)
 {
-	/* TODO */
-	buf[0] = '\0';
+	gnutls_cipher_algorithm_t cipher;
+	gnutls_kx_algorithm_t kx;
+	gnutls_mac_algorithm_t mac;
+	const char *kx_str, *cipher_str, *mac_str;
+	int res;
+
+	cipher = gnutls_cipher_get(conn->session);
+	cipher_str = gnutls_cipher_get_name(cipher);
+	if (!cipher_str)
+		cipher_str = "";
+
+	kx = gnutls_kx_get(conn->session);
+	kx_str = gnutls_kx_get_name(kx);
+	if (!kx_str)
+		kx_str = "";
+
+	mac = gnutls_mac_get(conn->session);
+	mac_str = gnutls_mac_get_name(mac);
+	if (!mac_str)
+		mac_str = "";
+
+	if (kx == GNUTLS_KX_RSA)
+		res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
+	else
+		res = os_snprintf(buf, buflen, "%s-%s-%s",
+				  kx_str, cipher_str, mac_str);
+	if (os_snprintf_error(buflen, res))
+		return -1;
+
 	return 0;
 }
 
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index c7cb5de..d289c94 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -177,6 +177,14 @@
 }
 
 
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn)
+{
+	/* TODO */
+	return NULL;
+}
+
+
 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
 {
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index dd5681e..5d0c6bd 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -45,6 +45,13 @@
 }
 
 
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn)
+{
+	return NULL;
+}
+
+
 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
 {
 	return -1;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 7243d9f..5bb14e2 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -59,7 +59,8 @@
 #endif /* SSL_set_tlsext_status_type */
 
 #if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
-     defined(LIBRESSL_VERSION_NUMBER)) &&    \
+     (defined(LIBRESSL_VERSION_NUMBER) && \
+      LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
     !defined(BORINGSSL_API_VERSION)
 /*
  * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
@@ -110,6 +111,12 @@
 	return BN_num_bits(r->n);
 }
 #endif /* CONFIG_SUITEB */
+
+
+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+	return ASN1_STRING_data((ASN1_STRING *) x);
+}
 #endif
 
 #ifdef ANDROID
@@ -245,6 +252,8 @@
 	unsigned int server_cert_only:1;
 	unsigned int invalid_hb_used:1;
 	unsigned int success_data:1;
+	unsigned int client_hello_generated:1;
+	unsigned int server:1;
 
 	u8 srv_cert_hash[32];
 
@@ -945,7 +954,9 @@
 		}
 #endif /* OPENSSL_FIPS */
 #endif /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 		SSL_load_error_strings();
 		SSL_library_init();
 #ifndef OPENSSL_NO_SHA256
@@ -1033,8 +1044,10 @@
 
 #ifndef OPENSSL_NO_ENGINE
 	wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	ERR_load_ENGINE_strings();
 	ENGINE_load_dynamic();
+#endif /* OPENSSL_VERSION_NUMBER */
 
 	if (conf &&
 	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
@@ -1077,7 +1090,9 @@
 
 	tls_openssl_ref_count--;
 	if (tls_openssl_ref_count == 0) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 #ifndef OPENSSL_NO_ENGINE
 		ENGINE_cleanup();
 #endif /* OPENSSL_NO_ENGINE */
@@ -1545,6 +1560,31 @@
 }
 
 
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn)
+{
+	ASN1_INTEGER *ser;
+	char *serial_num;
+	size_t len;
+
+	if (!conn->peer_cert)
+		return NULL;
+
+	ser = X509_get_serialNumber(conn->peer_cert);
+	if (!ser)
+		return NULL;
+
+	len = ASN1_STRING_length(ser) * 2 + 1;
+	serial_num = os_malloc(len);
+	if (!serial_num)
+		return NULL;
+	wpa_snprintf_hex_uppercase(serial_num, len,
+				   ASN1_STRING_get0_data(ser),
+				   ASN1_STRING_length(ser));
+	return serial_num;
+}
+
+
 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
 {
 	if (conn == NULL)
@@ -1833,6 +1873,8 @@
 	GENERAL_NAME *gen;
 	void *ext;
 	stack_index_t i;
+	ASN1_INTEGER *ser;
+	char serial_num[128];
 #ifdef CONFIG_SHA256
 	u8 hash[32];
 #endif /* CONFIG_SHA256 */
@@ -1861,6 +1903,14 @@
 	ev.peer_cert.depth = depth;
 	ev.peer_cert.subject = subject;
 
+	ser = X509_get_serialNumber(err_cert);
+	if (ser) {
+		wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
+					   ASN1_STRING_get0_data(ser),
+					   ASN1_STRING_length(ser));
+		ev.peer_cert.serial_num = serial_num;
+	}
+
 	ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
 	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
 		char *pos;
@@ -2451,7 +2501,8 @@
 #endif /* CONFIG_SUITEB */
 
 
-static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags)
+static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
+			      const char *openssl_ciphers)
 {
 	SSL *ssl = conn->ssl;
 
@@ -2480,11 +2531,27 @@
 	else
 		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
 #endif /* SSL_OP_NO_TLSv1_2 */
+#ifdef SSL_OP_NO_TLSv1_3
+	if (flags & TLS_CONN_DISABLE_TLSv1_3)
+		SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
+	else
+		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
+#endif /* SSL_OP_NO_TLSv1_3 */
 #ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+	/* Start with defaults from BoringSSL */
+	SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0);
+#endif /* OPENSSL_IS_BORINGSSL */
 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
 	if (flags & TLS_CONN_SUITEB_NO_ECDH) {
 		const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
 
+		if (openssl_ciphers) {
+			wpa_printf(MSG_DEBUG,
+				   "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
+				   openssl_ciphers);
+			ciphers = openssl_ciphers;
+		}
 		if (SSL_set_cipher_list(ssl, ciphers) != 1) {
 			wpa_printf(MSG_INFO,
 				   "OpenSSL: Failed to set Suite B ciphers");
@@ -2494,14 +2561,21 @@
 		EC_KEY *ecdh;
 		const char *ciphers =
 			"ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
+		int nid[1] = { NID_secp384r1 };
 
+		if (openssl_ciphers) {
+			wpa_printf(MSG_DEBUG,
+				   "OpenSSL: Override ciphers for Suite B: %s",
+				   openssl_ciphers);
+			ciphers = openssl_ciphers;
+		}
 		if (SSL_set_cipher_list(ssl, ciphers) != 1) {
 			wpa_printf(MSG_INFO,
 				   "OpenSSL: Failed to set Suite B ciphers");
 			return -1;
 		}
 
-		if (SSL_set1_curves_list(ssl, "P-384") != 1) {
+		if (SSL_set1_curves(ssl, nid, 1) != 1) {
 			wpa_printf(MSG_INFO,
 				   "OpenSSL: Failed to set Suite B curves");
 			return -1;
@@ -2517,12 +2591,23 @@
 		EC_KEY_free(ecdh);
 	}
 	if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
+#ifdef OPENSSL_IS_BORINGSSL
+		uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 };
+
+		if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+						       1) != 1) {
+			wpa_printf(MSG_INFO,
+				   "OpenSSL: Failed to set Suite B sigalgs");
+			return -1;
+		}
+#else /* OPENSSL_IS_BORINGSSL */
 		/* ECDSA+SHA384 if need to add EC support here */
 		if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) {
 			wpa_printf(MSG_INFO,
 				   "OpenSSL: Failed to set Suite B sigalgs");
 			return -1;
 		}
+#endif /* OPENSSL_IS_BORINGSSL */
 
 		SSL_set_options(ssl, SSL_OP_NO_TLSv1);
 		SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
@@ -2535,6 +2620,26 @@
 		return -1;
 	}
 #endif /* OPENSSL_VERSION_NUMBER */
+
+#ifdef OPENSSL_IS_BORINGSSL
+	if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
+		uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
+		int nid[1] = { NID_secp384r1 };
+
+		if (SSL_set1_curves(ssl, nid, 1) != 1) {
+			wpa_printf(MSG_INFO,
+				   "OpenSSL: Failed to set Suite B curves");
+			return -1;
+		}
+
+		if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+						       1) != 1) {
+			wpa_printf(MSG_INFO,
+				   "OpenSSL: Failed to set Suite B sigalgs");
+			return -1;
+		}
+	}
+#endif /* OPENSSL_IS_BORINGSSL */
 #endif /* CONFIG_SUITEB */
 
 	return 0;
@@ -2561,7 +2666,7 @@
 		SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
 	}
 
-	if (tls_set_conn_flags(conn, flags) < 0)
+	if (tls_set_conn_flags(conn, flags, NULL) < 0)
 		return -1;
 	conn->flags = flags;
 
@@ -2702,16 +2807,6 @@
 }
 
 
-static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
-{
-	if (password == NULL) {
-		return 0;
-	}
-	os_strlcpy(buf, (char *) password, size);
-	return os_strlen(buf);
-}
-
-
 #ifdef PKCS12_FUNCS
 static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
 			    const char *passwd)
@@ -3030,16 +3125,61 @@
 }
 
 
-static void tls_clear_default_passwd_cb(SSL_CTX *ssl_ctx, SSL *ssl)
+#ifndef OPENSSL_NO_STDIO
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
-	if (ssl) {
-		SSL_set_default_passwd_cb(ssl, NULL);
-		SSL_set_default_passwd_cb_userdata(ssl, NULL);
+	if (!password)
+		return 0;
+	os_strlcpy(buf, (const char *) password, size);
+	return os_strlen(buf);
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
+				    const char *private_key,
+				    const char *private_key_passwd)
+{
+#ifndef OPENSSL_NO_STDIO
+	BIO *bio;
+	EVP_PKEY *pkey;
+	int ret;
+
+	/* First try ASN.1 (DER). */
+	bio = BIO_new_file(private_key, "r");
+	if (!bio)
+		return -1;
+	pkey = d2i_PrivateKey_bio(bio, NULL);
+	BIO_free(bio);
+
+	if (pkey) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
+	} else {
+		/* Try PEM with the provided password. */
+		bio = BIO_new_file(private_key, "r");
+		if (!bio)
+			return -1;
+		pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
+					       (void *) private_key_passwd);
+		BIO_free(bio);
+		if (!pkey)
+			return -1;
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
+		/* Clear errors from the previous failed load. */
+		ERR_clear_error();
 	}
-#endif /* >= 1.1.0f && !LibreSSL && !BoringSSL */
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL);
+
+	if (ssl)
+		ret = SSL_use_PrivateKey(ssl, pkey);
+	else
+		ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
+
+	EVP_PKEY_free(pkey);
+	return ret == 1 ? 0 : -1;
+#else /* OPENSSL_NO_STDIO */
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+	return -1;
+#endif /* OPENSSL_NO_STDIO */
 }
 
 
@@ -3050,32 +3190,11 @@
 				      const u8 *private_key_blob,
 				      size_t private_key_blob_len)
 {
-	SSL_CTX *ssl_ctx = data->ssl;
-	char *passwd;
 	int ok;
 
 	if (private_key == NULL && private_key_blob == NULL)
 		return 0;
 
-	if (private_key_passwd) {
-		passwd = os_strdup(private_key_passwd);
-		if (passwd == NULL)
-			return -1;
-	} else
-		passwd = NULL;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
-	/*
-	 * In OpenSSL >= 1.1.0f SSL_use_PrivateKey_file() uses the callback
-	 * from the SSL object. See OpenSSL commit d61461a75253.
-	 */
-	SSL_set_default_passwd_cb(conn->ssl, tls_passwd_cb);
-	SSL_set_default_passwd_cb_userdata(conn->ssl, passwd);
-#endif /* >= 1.1.0f && !LibreSSL && !BoringSSL */
-	/* Keep these for OpenSSL < 1.1.0f */
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
-
 	ok = 0;
 	while (private_key_blob) {
 		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
@@ -3106,7 +3225,8 @@
 		}
 
 		if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
-					 private_key_blob_len, passwd) == 0) {
+					 private_key_blob_len,
+					 private_key_passwd) == 0) {
 			wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
 				   "OK");
 			ok = 1;
@@ -3117,29 +3237,14 @@
 	}
 
 	while (!ok && private_key) {
-#ifndef OPENSSL_NO_STDIO
-		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
-					    SSL_FILETYPE_ASN1) == 1) {
-			wpa_printf(MSG_DEBUG, "OpenSSL: "
-				   "SSL_use_PrivateKey_File (DER) --> OK");
+		if (tls_use_private_key_file(data, conn->ssl, private_key,
+					     private_key_passwd) == 0) {
 			ok = 1;
 			break;
 		}
 
-		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
-					    SSL_FILETYPE_PEM) == 1) {
-			wpa_printf(MSG_DEBUG, "OpenSSL: "
-				   "SSL_use_PrivateKey_File (PEM) --> OK");
-			ok = 1;
-			break;
-		}
-#else /* OPENSSL_NO_STDIO */
-		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
-			   __func__);
-#endif /* OPENSSL_NO_STDIO */
-
-		if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
-		    == 0) {
+		if (tls_read_pkcs12(data, conn->ssl, private_key,
+				    private_key_passwd) == 0) {
 			wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
 				   "--> OK");
 			ok = 1;
@@ -3159,13 +3264,9 @@
 	if (!ok) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
-		tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
-		os_free(passwd);
 		return -1;
 	}
 	ERR_clear_error();
-	tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
-	os_free(passwd);
 
 	if (!SSL_check_private_key(conn->ssl)) {
 		tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -3183,37 +3284,18 @@
 				  const char *private_key_passwd)
 {
 	SSL_CTX *ssl_ctx = data->ssl;
-	char *passwd;
 
 	if (private_key == NULL)
 		return 0;
 
-	if (private_key_passwd) {
-		passwd = os_strdup(private_key_passwd);
-		if (passwd == NULL)
-			return -1;
-	} else
-		passwd = NULL;
-
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
-	if (
-#ifndef OPENSSL_NO_STDIO
-	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
-					SSL_FILETYPE_ASN1) != 1 &&
-	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
-					SSL_FILETYPE_PEM) != 1 &&
-#endif /* OPENSSL_NO_STDIO */
-	    tls_read_pkcs12(data, NULL, private_key, passwd)) {
+	if (tls_use_private_key_file(data, NULL, private_key,
+				     private_key_passwd) &&
+	    tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
-		tls_clear_default_passwd_cb(ssl_ctx, NULL);
-		os_free(passwd);
 		ERR_clear_error();
 		return -1;
 	}
-	tls_clear_default_passwd_cb(ssl_ctx, NULL);
-	os_free(passwd);
 	ERR_clear_error();
 
 	if (!SSL_CTX_check_private_key(ssl_ctx)) {
@@ -3401,7 +3483,9 @@
 #ifdef OPENSSL_NEED_EAP_FAST_PRF
 static int openssl_get_keyblock_size(SSL *ssl)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 	const EVP_CIPHER *c;
 	const EVP_MD *h;
 	int md_size;
@@ -3548,8 +3632,7 @@
 
 
 static struct wpabuf *
-openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
-		  int server)
+openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
 {
 	int res;
 	struct wpabuf *out_data;
@@ -3567,7 +3650,7 @@
 	}
 
 	/* Initiate TLS handshake or continue the existing handshake */
-	if (server)
+	if (conn->server)
 		res = SSL_accept(conn->ssl);
 	else
 		res = SSL_connect(conn->ssl);
@@ -3582,11 +3665,25 @@
 		else {
 			tls_show_errors(MSG_INFO, __func__, "SSL_connect");
 			conn->failed++;
+			if (!conn->server && !conn->client_hello_generated) {
+				/* The server would not understand TLS Alert
+				 * before ClientHello, so simply terminate
+				 * handshake on this type of error case caused
+				 * by a likely internal error like no ciphers
+				 * available. */
+				wpa_printf(MSG_DEBUG,
+					   "OpenSSL: Could not generate ClientHello");
+				conn->write_alerts++;
+				return NULL;
+			}
 		}
 	}
 
+	if (!conn->server && !conn->failed)
+		conn->client_hello_generated = 1;
+
 #ifdef CONFIG_SUITEB
-	if ((conn->flags & TLS_CONN_SUITEB) && !server &&
+	if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
 	    os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
 	    conn->server_dh_prime_len < 3072) {
 		struct tls_context *context = conn->context;
@@ -3689,14 +3786,14 @@
 static struct wpabuf *
 openssl_connection_handshake(struct tls_connection *conn,
 			     const struct wpabuf *in_data,
-			     struct wpabuf **appl_data, int server)
+			     struct wpabuf **appl_data)
 {
 	struct wpabuf *out_data;
 
 	if (appl_data)
 		*appl_data = NULL;
 
-	out_data = openssl_handshake(conn, in_data, server);
+	out_data = openssl_handshake(conn, in_data);
 	if (out_data == NULL)
 		return NULL;
 	if (conn->invalid_hb_used) {
@@ -3733,7 +3830,7 @@
 			 const struct wpabuf *in_data,
 			 struct wpabuf **appl_data)
 {
-	return openssl_connection_handshake(conn, in_data, appl_data, 0);
+	return openssl_connection_handshake(conn, in_data, appl_data);
 }
 
 
@@ -3742,7 +3839,8 @@
 						const struct wpabuf *in_data,
 						struct wpabuf **appl_data)
 {
-	return openssl_connection_handshake(conn, in_data, appl_data, 1);
+	conn->server = 1;
+	return openssl_connection_handshake(conn, in_data, appl_data);
 }
 
 
@@ -3837,7 +3935,7 @@
 
 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
 {
-	return conn ? SSL_cache_hit(conn->ssl) : 0;
+	return conn ? SSL_session_reused(conn->ssl) : 0;
 }
 
 
@@ -4283,6 +4381,7 @@
 	const char *cert_id = params->cert_id;
 	const char *ca_cert_id = params->ca_cert_id;
 	const char *engine_id = params->engine ? params->engine_id : NULL;
+	const char *ciphers;
 
 	if (conn == NULL)
 		return -1;
@@ -4335,6 +4434,17 @@
 		}
 	}
 #endif
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#ifdef SSL_OP_NO_TLSv1_3
+	if (params->flags & TLS_CONN_EAP_FAST) {
+		/* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
+		 * refuses to start the handshake with the modified ciphersuite
+		 * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
+		wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
+		SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
+	}
+#endif /* SSL_OP_NO_TLSv1_3 */
+#endif
 #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 
 	while ((err = ERR_get_error())) {
@@ -4393,15 +4503,26 @@
 		return -1;
 	}
 
-	if (params->openssl_ciphers &&
-	    SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+	ciphers = params->openssl_ciphers;
+#ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+	if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
+		/* BoringSSL removed support for SUITEB192, so need to handle
+		 * this with hardcoded ciphersuite and additional checks for
+		 * other parameters. */
+		ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
+	}
+#endif /* OPENSSL_IS_BORINGSSL */
+#endif /* CONFIG_SUITEB */
+	if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
 		wpa_printf(MSG_INFO,
 			   "OpenSSL: Failed to set cipher string '%s'",
-			   params->openssl_ciphers);
+			   ciphers);
 		return -1;
 	}
 
-	if (tls_set_conn_flags(conn, params->flags) < 0)
+	if (tls_set_conn_flags(conn, params->flags,
+			       params->openssl_ciphers) < 0)
 		return -1;
 
 #ifdef OPENSSL_IS_BORINGSSL
@@ -4506,7 +4627,9 @@
 	struct tls_connection *conn = arg;
 	int ret;
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+	(defined(LIBRESSL_VERSION_NUMBER) && \
+	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
 	if (conn == NULL || conn->session_ticket_cb == NULL)
 		return 0;
 
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
new file mode 100644
index 0000000..cc8c704
--- /dev/null
+++ b/src/crypto/tls_wolfssl.c
@@ -0,0 +1,2175 @@
+/*
+ * SSL/TLS interface functions for wolfSSL TLS case
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "tls.h"
+
+/* wolfSSL includes */
+#include <wolfssl/options.h>
+#include <wolfssl/ssl.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#define HAVE_AESGCM
+#include <wolfssl/wolfcrypt/aes.h>
+#endif
+
+#if !defined(CONFIG_FIPS) &&                             \
+    (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
+     defined(EAP_SERVER_FAST))
+#define WOLFSSL_NEED_EAP_FAST_PRF
+#endif
+
+#define SECRET_LEN          48
+#define RAN_LEN             32
+#define SESSION_TICKET_LEN  256
+
+static int tls_ref_count = 0;
+
+static int tls_ex_idx_session = 0;
+
+
+/* tls input data for wolfSSL Read Callback */
+struct tls_in_data {
+	const struct wpabuf *in_data;
+	size_t consumed; /* how many bytes have we used already */
+};
+
+/* tls output data for wolfSSL Write Callback */
+struct tls_out_data {
+	struct wpabuf *out_data;
+};
+
+struct tls_context {
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+	int cert_in_cb;
+	char *ocsp_stapling_response;
+};
+
+static struct tls_context *tls_global = NULL;
+
+/* wolfssl tls_connection */
+struct tls_connection {
+	struct tls_context *context;
+	WOLFSSL *ssl;
+	int read_alerts;
+	int write_alerts;
+	int failed;
+	struct tls_in_data input;
+	struct tls_out_data output;
+	char *subject_match;
+	char *alt_subject_match;
+	char *suffix_match;
+	char *domain_match;
+
+	u8 srv_cert_hash[32];
+
+	unsigned char client_random[RAN_LEN];
+	unsigned char server_random[RAN_LEN];
+	unsigned int flags;
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+	tls_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+	byte session_ticket[SESSION_TICKET_LEN];
+#endif
+	unsigned int ca_cert_verify:1;
+	unsigned int cert_probe:1;
+	unsigned int server_cert_only:1;
+	unsigned int success_data:1;
+
+	WOLFSSL_X509 *peer_cert;
+	WOLFSSL_X509 *peer_issuer;
+	WOLFSSL_X509 *peer_issuer_issuer;
+};
+
+
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+	struct tls_context *context = os_zalloc(sizeof(*context));
+
+	if (!context)
+		return NULL;
+
+	if (conf) {
+		context->event_cb = conf->event_cb;
+		context->cb_ctx = conf->cb_ctx;
+		context->cert_in_cb = conf->cert_in_cb;
+	}
+
+	return context;
+}
+
+
+static void wolfssl_reset_in_data(struct tls_in_data *in,
+				  const struct wpabuf *buf)
+{
+	/* old one not owned by us so don't free */
+	in->in_data = buf;
+	in->consumed = 0;
+}
+
+
+static void wolfssl_reset_out_data(struct tls_out_data *out)
+{
+	/* old one not owned by us so don't free */
+	out->out_data = wpabuf_alloc_copy("", 0);
+}
+
+
+/* wolfSSL I/O Receive CallBack */
+static int wolfssl_receive_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+	size_t get = sz;
+	struct tls_in_data *data = ctx;
+
+	if (!data)
+		return -1;
+
+	if (get > (wpabuf_len(data->in_data) - data->consumed))
+		get = wpabuf_len(data->in_data) - data->consumed;
+
+	os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
+	data->consumed += get;
+
+	if (get == 0)
+		return -2; /* WANT_READ */
+
+	return (int) get;
+}
+
+
+/* wolfSSL I/O Send CallBack */
+static int wolfssl_send_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+	struct wpabuf *tmp;
+	struct tls_out_data *data = ctx;
+
+	if (!data)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "SSL: adding %d bytes", sz);
+
+	tmp = wpabuf_alloc_copy(buf, sz);
+	if (!tmp)
+		return -1;
+	data->out_data = wpabuf_concat(data->out_data, tmp);
+	if (!data->out_data)
+		return -1;
+
+	return sz;
+}
+
+
+static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
+{
+	struct wpabuf *buf;
+
+	buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+	if (!buf)
+		return;
+	wpa_printf(MSG_DEBUG,
+		   "wolfSSL: Free application session data %p (sess %p)",
+		   buf, sess);
+	wpabuf_free(buf);
+
+	wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	WOLFSSL_CTX *ssl_ctx;
+	struct tls_context *context;
+	const char *ciphers;
+
+#ifdef DEBUG_WOLFSSL
+	wolfSSL_Debugging_ON();
+#endif /* DEBUG_WOLFSSL */
+
+	context = tls_context_new(conf);
+	if (!context)
+		return NULL;
+
+	if (tls_ref_count == 0) {
+		tls_global = context;
+
+		if (wolfSSL_Init() < 0)
+			return NULL;
+		/* wolfSSL_Debugging_ON(); */
+	}
+
+	tls_ref_count++;
+
+	/* start as client */
+	ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
+	if (!ssl_ctx) {
+		tls_ref_count--;
+		if (context != tls_global)
+			os_free(context);
+		if (tls_ref_count == 0) {
+			os_free(tls_global);
+			tls_global = NULL;
+		}
+	}
+	wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
+	wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
+	wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
+
+	if (conf->tls_session_lifetime > 0) {
+		wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
+		wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+						   SSL_SESS_CACHE_SERVER);
+		wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
+		wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
+	} else {
+		wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+						   SSL_SESS_CACHE_CLIENT);
+	}
+
+	if (conf && conf->openssl_ciphers)
+		ciphers = conf->openssl_ciphers;
+	else
+		ciphers = "ALL";
+	if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
+		wpa_printf(MSG_ERROR,
+			   "wolfSSL: Failed to set cipher string '%s'",
+			   ciphers);
+		tls_deinit(ssl_ctx);
+		return NULL;
+	}
+
+	return ssl_ctx;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+	if (context != tls_global)
+		os_free(context);
+
+	wolfSSL_CTX_free((WOLFSSL_CTX *) ssl_ctx);
+
+	tls_ref_count--;
+	if (tls_ref_count == 0) {
+		wolfSSL_Cleanup();
+		os_free(tls_global);
+		tls_global = NULL;
+	}
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+#ifdef DEBUG_WOLFSSL
+#if 0
+	unsigned long err;
+
+	err = wolfSSL_ERR_peek_last_error_line(NULL, NULL);
+	if (err != 0) {
+		wpa_printf(MSG_INFO, "TLS - SSL error: %s",
+			   wolfSSL_ERR_error_string(err, NULL));
+		return 1;
+	}
+#endif
+#endif /* DEBUG_WOLFSSL */
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	WOLFSSL_CTX *ssl_ctx = tls_ctx;
+	struct tls_connection *conn;
+
+	wpa_printf(MSG_DEBUG, "SSL: connection init");
+
+	conn = os_zalloc(sizeof(*conn));
+	if (!conn)
+		return NULL;
+	conn->ssl = wolfSSL_new(ssl_ctx);
+	if (!conn->ssl) {
+		os_free(conn);
+		return NULL;
+	}
+
+	wolfSSL_SetIOReadCtx(conn->ssl,  &conn->input);
+	wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output);
+	wolfSSL_set_ex_data(conn->ssl, 0, conn);
+	conn->context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+	/* Need randoms post-hanshake for EAP-FAST, export key and deriving
+	 * session ID in EAP methods. */
+	wolfSSL_KeepArrays(conn->ssl);
+	wolfSSL_KeepHandshakeResources(conn->ssl);
+	wolfSSL_UseClientSuites(conn->ssl);
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+	if (!conn)
+		return;
+
+	wpa_printf(MSG_DEBUG, "SSL: connection deinit");
+
+	/* parts */
+	wolfSSL_free(conn->ssl);
+	os_free(conn->subject_match);
+	os_free(conn->alt_subject_match);
+	os_free(conn->suffix_match);
+	os_free(conn->domain_match);
+
+	/* self */
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+	return conn ? wolfSSL_is_init_finished(conn->ssl) : 0;
+}
+
+
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn)
+{
+	/* TODO */
+	return NULL;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+	WOLFSSL_SESSION *session;
+
+	if (!conn)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "SSL: connection shutdown");
+
+	/* Set quiet as OpenSSL does */
+	wolfSSL_set_quiet_shutdown(conn->ssl, 1);
+	wolfSSL_shutdown(conn->ssl);
+
+	session = wolfSSL_get_session(conn->ssl);
+	if (wolfSSL_clear(conn->ssl) != 1)
+		return -1;
+	wolfSSL_set_session(conn->ssl, session);
+
+	return 0;
+}
+
+
+static int tls_connection_set_subject_match(struct tls_connection *conn,
+					    const char *subject_match,
+					    const char *alt_subject_match,
+					    const char *suffix_match,
+					    const char *domain_match)
+{
+	os_free(conn->subject_match);
+	conn->subject_match = NULL;
+	if (subject_match) {
+		conn->subject_match = os_strdup(subject_match);
+		if (!conn->subject_match)
+			return -1;
+	}
+
+	os_free(conn->alt_subject_match);
+	conn->alt_subject_match = NULL;
+	if (alt_subject_match) {
+		conn->alt_subject_match = os_strdup(alt_subject_match);
+		if (!conn->alt_subject_match)
+			return -1;
+	}
+
+	os_free(conn->suffix_match);
+	conn->suffix_match = NULL;
+	if (suffix_match) {
+		conn->suffix_match = os_strdup(suffix_match);
+		if (!conn->suffix_match)
+			return -1;
+	}
+
+	os_free(conn->domain_match);
+	conn->domain_match = NULL;
+	if (domain_match) {
+		conn->domain_match = os_strdup(domain_match);
+		if (!conn->domain_match)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file,
+			     const u8 *dh_blob, size_t blob_len)
+{
+	if (!dh_file && !dh_blob)
+		return 0;
+
+	wolfSSL_set_accept_state(conn->ssl);
+
+	if (dh_blob) {
+		if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
+					    SSL_FILETYPE_ASN1) < 0) {
+			wpa_printf(MSG_INFO, "SSL: use DH DER blob failed");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "SSL: use DH blob OK");
+		return 0;
+	}
+
+	if (dh_file) {
+		wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file);
+		if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+					  SSL_FILETYPE_PEM) < 0) {
+			wpa_printf(MSG_INFO, "SSL: use DH PEM file failed");
+			if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+						  SSL_FILETYPE_ASN1) < 0) {
+				wpa_printf(MSG_INFO,
+					   "SSL: use DH DER file failed");
+				return -1;
+			}
+		}
+		wpa_printf(MSG_DEBUG, "SSL: use DH file OK");
+		return 0;
+	}
+
+	return 0;
+}
+
+
+static int tls_connection_client_cert(struct tls_connection *conn,
+				      const char *client_cert,
+				      const u8 *client_cert_blob,
+				      size_t blob_len)
+{
+	if (!client_cert && !client_cert_blob)
+		return 0;
+
+	if (client_cert_blob) {
+		if (wolfSSL_use_certificate_chain_buffer_format(
+			    conn->ssl, client_cert_blob, blob_len,
+			    SSL_FILETYPE_ASN1) < 0) {
+			wpa_printf(MSG_INFO,
+				   "SSL: use client cert DER blob failed");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
+		return 0;
+	}
+
+	if (client_cert) {
+		if (wolfSSL_use_certificate_chain_file(conn->ssl,
+						       client_cert) < 0) {
+			wpa_printf(MSG_INFO,
+				   "SSL: use client cert PEM file failed");
+			if (wolfSSL_use_certificate_chain_file_format(
+				    conn->ssl, client_cert,
+				    SSL_FILETYPE_ASN1) < 0) {
+				wpa_printf(MSG_INFO,
+					   "SSL: use client cert DER file failed");
+				return -1;
+			}
+		}
+		wpa_printf(MSG_DEBUG, "SSL: use client cert file OK");
+		return 0;
+	}
+
+	return 0;
+}
+
+
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+	if (!password)
+		return 0;
+	os_strlcpy(buf, (char *) password, size);
+	return os_strlen(buf);
+}
+
+
+static int tls_connection_private_key(void *tls_ctx,
+				      struct tls_connection *conn,
+				      const char *private_key,
+				      const char *private_key_passwd,
+				      const u8 *private_key_blob,
+				      size_t blob_len)
+{
+	WOLFSSL_CTX *ctx = tls_ctx;
+	char *passwd = NULL;
+	int ok = 0;
+
+	if (!private_key && !private_key_blob)
+		return 0;
+
+	if (private_key_passwd) {
+		passwd = os_strdup(private_key_passwd);
+		if (!passwd)
+			return -1;
+	}
+
+	wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+	wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+	if (private_key_blob) {
+		if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
+						  private_key_blob, blob_len,
+						  SSL_FILETYPE_ASN1) < 0) {
+			wpa_printf(MSG_INFO,
+				   "SSL: use private DER blob failed");
+		} else {
+			wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
+			ok = 1;
+		}
+	}
+
+	if (!ok && private_key) {
+		if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+						SSL_FILETYPE_PEM) < 0) {
+			wpa_printf(MSG_INFO,
+				   "SSL: use private key PEM file failed");
+			if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+							SSL_FILETYPE_ASN1) < 0)
+			{
+				wpa_printf(MSG_INFO,
+					   "SSL: use private key DER file failed");
+			} else {
+				ok = 1;
+			}
+		} else {
+			ok = 1;
+		}
+
+		if (ok)
+			wpa_printf(MSG_DEBUG, "SSL: use private key file OK");
+	}
+
+	wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+	os_free(passwd);
+
+	if (!ok)
+		return -1;
+
+	return 0;
+}
+
+
+static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
+					   const char *value, size_t len)
+{
+	WOLFSSL_ASN1_OBJECT *gen;
+	void *ext;
+	int found = 0;
+	int i;
+
+	ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+	for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+		gen = wolfSSL_sk_value(ext, i);
+		if (gen->type != type)
+			continue;
+		if (os_strlen((char *) gen->obj) == len &&
+		    os_memcmp(value, gen->obj, len) == 0)
+			found++;
+	}
+
+	wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+	return found;
+}
+
+
+static int tls_match_alt_subject(WOLFSSL_X509 *cert, const char *match)
+{
+	int type;
+	const char *pos, *end;
+	size_t len;
+
+	pos = match;
+	do {
+		if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+			type = GEN_EMAIL;
+			pos += 6;
+		} else if (os_strncmp(pos, "DNS:", 4) == 0) {
+			type = GEN_DNS;
+			pos += 4;
+		} else if (os_strncmp(pos, "URI:", 4) == 0) {
+			type = GEN_URI;
+			pos += 4;
+		} else {
+			wpa_printf(MSG_INFO,
+				   "TLS: Invalid altSubjectName match '%s'",
+				   pos);
+			return 0;
+		}
+		end = os_strchr(pos, ';');
+		while (end) {
+			if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+			    os_strncmp(end + 1, "DNS:", 4) == 0 ||
+			    os_strncmp(end + 1, "URI:", 4) == 0)
+				break;
+			end = os_strchr(end + 1, ';');
+		}
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		if (tls_match_alt_subject_component(cert, type, pos, len) > 0)
+			return 1;
+		pos = end + 1;
+	} while (end);
+
+	return 0;
+}
+
+
+static int domain_suffix_match(const char *val, size_t len, const char *match,
+			       int full)
+{
+	size_t i, match_len;
+
+	/* Check for embedded nuls that could mess up suffix matching */
+	for (i = 0; i < len; i++) {
+		if (val[i] == '\0') {
+			wpa_printf(MSG_DEBUG,
+				   "TLS: Embedded null in a string - reject");
+			return 0;
+		}
+	}
+
+	match_len = os_strlen(match);
+	if (match_len > len || (full && match_len != len))
+		return 0;
+
+	if (os_strncasecmp(val + len - match_len, match, match_len) != 0)
+		return 0; /* no match */
+
+	if (match_len == len)
+		return 1; /* exact match */
+
+	if (val[len - match_len - 1] == '.')
+		return 1; /* full label match completes suffix match */
+
+	wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+	return 0;
+}
+
+
+static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
+{
+	WOLFSSL_ASN1_OBJECT *gen;
+	void *ext;
+	int i;
+	int j;
+	int dns_name = 0;
+	WOLFSSL_X509_NAME *name;
+
+	wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+		   full ? "" : "suffix ", match);
+
+	ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+	for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
+		gen = wolfSSL_sk_value(ext, j);
+		if (gen->type != ALT_NAMES_OID)
+			continue;
+		dns_name++;
+		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
+				  gen->obj, os_strlen((char *)gen->obj));
+		if (domain_suffix_match((const char *) gen->obj,
+					os_strlen((char *) gen->obj), match,
+					full) == 1) {
+			wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+				   full ? "Match" : "Suffix match");
+			wolfSSL_sk_ASN1_OBJECT_free(ext);
+			return 1;
+		}
+	}
+	wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+	if (dns_name) {
+		wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+		return 0;
+	}
+
+	name = wolfSSL_X509_get_subject_name(cert);
+	i = -1;
+	for (;;) {
+		WOLFSSL_X509_NAME_ENTRY *e;
+		WOLFSSL_ASN1_STRING *cn;
+
+		i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
+						       i);
+		if (i == -1)
+			break;
+		e = wolfSSL_X509_NAME_get_entry(name, i);
+		if (!e)
+			continue;
+		cn = wolfSSL_X509_NAME_ENTRY_get_data(e);
+		if (!cn)
+			continue;
+		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
+				  cn->data, cn->length);
+		if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
+		{
+			wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+				   full ? "Match" : "Suffix match");
+			return 1;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+		   full ? "" : "suffix ");
+	return 0;
+}
+
+
+static enum tls_fail_reason wolfssl_tls_fail_reason(int err)
+{
+	switch (err) {
+	case X509_V_ERR_CERT_REVOKED:
+		return TLS_FAIL_REVOKED;
+	case ASN_BEFORE_DATE_E:
+	case X509_V_ERR_CERT_NOT_YET_VALID:
+	case X509_V_ERR_CRL_NOT_YET_VALID:
+		return TLS_FAIL_NOT_YET_VALID;
+	case ASN_AFTER_DATE_E:
+	case X509_V_ERR_CERT_HAS_EXPIRED:
+	case X509_V_ERR_CRL_HAS_EXPIRED:
+		return TLS_FAIL_EXPIRED;
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+	case X509_V_ERR_UNABLE_TO_GET_CRL:
+	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+	case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+	case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+	case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+	case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+	case X509_V_ERR_INVALID_CA:
+		return TLS_FAIL_UNTRUSTED;
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+	case X509_V_ERR_CERT_UNTRUSTED:
+	case X509_V_ERR_CERT_REJECTED:
+		return TLS_FAIL_BAD_CERTIFICATE;
+	default:
+		return TLS_FAIL_UNSPECIFIED;
+	}
+}
+
+
+static const char * wolfssl_tls_err_string(int err, const char *err_str)
+{
+	switch (err) {
+	case ASN_BEFORE_DATE_E:
+		return "certificate is not yet valid";
+	case ASN_AFTER_DATE_E:
+		return "certificate has expired";
+	default:
+		return err_str;
+	}
+}
+
+
+static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert)
+{
+	struct wpabuf *buf = NULL;
+	const u8 *data;
+	int cert_len;
+
+	data = wolfSSL_X509_get_der(cert, &cert_len);
+	if (!data)
+		buf = wpabuf_alloc_copy(data, cert_len);
+
+	return buf;
+}
+
+
+static void wolfssl_tls_fail_event(struct tls_connection *conn,
+				   WOLFSSL_X509 *err_cert, int err, int depth,
+				   const char *subject, const char *err_str,
+				   enum tls_fail_reason reason)
+{
+	union tls_event_data ev;
+	struct wpabuf *cert = NULL;
+	struct tls_context *context = conn->context;
+
+	if (!context->event_cb)
+		return;
+
+	cert = get_x509_cert(err_cert);
+	os_memset(&ev, 0, sizeof(ev));
+	ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+		reason : wolfssl_tls_fail_reason(err);
+	ev.cert_fail.depth = depth;
+	ev.cert_fail.subject = subject;
+	ev.cert_fail.reason_txt = wolfssl_tls_err_string(err, err_str);
+	ev.cert_fail.cert = cert;
+	context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+	wpabuf_free(cert);
+}
+
+
+static void wolfssl_tls_cert_event(struct tls_connection *conn,
+				   WOLFSSL_X509 *err_cert, int depth,
+				   const char *subject)
+{
+	struct wpabuf *cert = NULL;
+	union tls_event_data ev;
+	struct tls_context *context = conn->context;
+	char *alt_subject[TLS_MAX_ALT_SUBJECT];
+	int alt, num_alt_subject = 0;
+	WOLFSSL_ASN1_OBJECT *gen;
+	void *ext;
+	int i;
+#ifdef CONFIG_SHA256
+	u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+	if (!context->event_cb)
+		return;
+
+	os_memset(&ev, 0, sizeof(ev));
+	if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+	    context->cert_in_cb) {
+		cert = get_x509_cert(err_cert);
+		ev.peer_cert.cert = cert;
+	}
+
+#ifdef CONFIG_SHA256
+	if (cert) {
+		const u8 *addr[1];
+		size_t len[1];
+
+		addr[0] = wpabuf_head(cert);
+		len[0] = wpabuf_len(cert);
+		if (sha256_vector(1, addr, len, hash) == 0) {
+			ev.peer_cert.hash = hash;
+			ev.peer_cert.hash_len = sizeof(hash);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+
+	ev.peer_cert.depth = depth;
+	ev.peer_cert.subject = subject;
+
+	ext = wolfSSL_X509_get_ext_d2i(err_cert, ALT_NAMES_OID, NULL, NULL);
+	for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+		char *pos;
+
+		if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
+			break;
+		gen = wolfSSL_sk_value((void *) ext, i);
+		if (gen->type != GEN_EMAIL &&
+		    gen->type != GEN_DNS &&
+		    gen->type != GEN_URI)
+			continue;
+
+		pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
+		if (!pos)
+			break;
+		alt_subject[num_alt_subject++] = pos;
+
+		switch (gen->type) {
+		case GEN_EMAIL:
+			os_memcpy(pos, "EMAIL:", 6);
+			pos += 6;
+			break;
+		case GEN_DNS:
+			os_memcpy(pos, "DNS:", 4);
+			pos += 4;
+			break;
+		case GEN_URI:
+			os_memcpy(pos, "URI:", 4);
+			pos += 4;
+			break;
+		}
+
+		os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
+		pos += os_strlen((char *)gen->obj);
+		*pos = '\0';
+	}
+	wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+	for (alt = 0; alt < num_alt_subject; alt++)
+		ev.peer_cert.altsubject[alt] = alt_subject[alt];
+	ev.peer_cert.num_altsubject = num_alt_subject;
+
+	context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+	wpabuf_free(cert);
+	for (alt = 0; alt < num_alt_subject; alt++)
+		os_free(alt_subject[alt]);
+}
+
+
+static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
+{
+	char buf[256];
+	WOLFSSL_X509 *err_cert;
+	int err, depth;
+	WOLFSSL *ssl;
+	struct tls_connection *conn;
+	struct tls_context *context;
+	char *match, *altmatch, *suffix_match, *domain_match;
+	const char *err_str;
+
+	err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
+	if (!err_cert) {
+		wpa_printf(MSG_DEBUG, "wolfSSL: No Cert");
+		return 0;
+	}
+
+	err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
+	depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx);
+	ssl = wolfSSL_X509_STORE_CTX_get_ex_data(
+		x509_ctx, wolfSSL_get_ex_data_X509_STORE_CTX_idx());
+	wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf,
+				  sizeof(buf));
+
+	conn = wolfSSL_get_ex_data(ssl, 0);
+	if (!conn) {
+		wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data");
+		return 0;
+	}
+
+	if (depth == 0)
+		conn->peer_cert = err_cert;
+	else if (depth == 1)
+		conn->peer_issuer = err_cert;
+	else if (depth == 2)
+		conn->peer_issuer_issuer = err_cert;
+
+	context = conn->context;
+	match = conn->subject_match;
+	altmatch = conn->alt_subject_match;
+	suffix_match = conn->suffix_match;
+	domain_match = conn->domain_match;
+
+	if (!preverify_ok && !conn->ca_cert_verify)
+		preverify_ok = 1;
+	if (!preverify_ok && depth > 0 && conn->server_cert_only)
+		preverify_ok = 1;
+	if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+	    (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+	     err == ASN_AFTER_DATE_E || err == ASN_BEFORE_DATE_E ||
+	     err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: Ignore certificate validity time mismatch");
+		preverify_ok = 1;
+	}
+
+	err_str = wolfSSL_X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+	/*
+	 * Do not require preverify_ok so we can explicity allow otherwise
+	 * invalid pinned server certificates.
+	 */
+	if (depth == 0 && conn->server_cert_only) {
+		struct wpabuf *cert;
+
+		cert = get_x509_cert(err_cert);
+		if (!cert) {
+			wpa_printf(MSG_DEBUG,
+				   "wolfSSL: Could not fetch server certificate data");
+			preverify_ok = 0;
+		} else {
+			u8 hash[32];
+			const u8 *addr[1];
+			size_t len[1];
+
+			addr[0] = wpabuf_head(cert);
+			len[0] = wpabuf_len(cert);
+			if (sha256_vector(1, addr, len, hash) < 0 ||
+			    os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
+				err_str = "Server certificate mismatch";
+				err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+				preverify_ok = 0;
+			} else if (!preverify_ok) {
+				/*
+				 * Certificate matches pinned certificate, allow
+				 * regardless of other problems.
+				 */
+				wpa_printf(MSG_DEBUG,
+					   "wolfSSL: Ignore validation issues for a pinned server certificate");
+				preverify_ok = 1;
+			}
+			wpabuf_free(cert);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+
+	if (!preverify_ok) {
+		wpa_printf(MSG_WARNING,
+			   "TLS: Certificate verification failed, error %d (%s) depth %d for '%s'",
+			   err, err_str, depth, buf);
+		wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       err_str, TLS_FAIL_UNSPECIFIED);
+		return preverify_ok;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "TLS: %s - preverify_ok=%d err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+		   __func__, preverify_ok, err, err_str,
+		   conn->ca_cert_verify, depth, buf);
+	if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+		wpa_printf(MSG_WARNING,
+			   "TLS: Subject '%s' did not match with '%s'",
+			   buf, match);
+		preverify_ok = 0;
+		wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Subject mismatch",
+				       TLS_FAIL_SUBJECT_MISMATCH);
+	} else if (depth == 0 && altmatch &&
+		   !tls_match_alt_subject(err_cert, altmatch)) {
+		wpa_printf(MSG_WARNING,
+			   "TLS: altSubjectName match '%s' not found",
+			   altmatch);
+		preverify_ok = 0;
+		wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "AltSubject mismatch",
+				       TLS_FAIL_ALTSUBJECT_MISMATCH);
+	} else if (depth == 0 && suffix_match &&
+		   !tls_match_suffix(err_cert, suffix_match, 0)) {
+		wpa_printf(MSG_WARNING,
+			   "TLS: Domain suffix match '%s' not found",
+			   suffix_match);
+		preverify_ok = 0;
+		wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Domain suffix mismatch",
+				       TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+	} else if (depth == 0 && domain_match &&
+		   !tls_match_suffix(err_cert, domain_match, 1)) {
+		wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+			   domain_match);
+		preverify_ok = 0;
+		wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Domain mismatch",
+				       TLS_FAIL_DOMAIN_MISMATCH);
+	} else {
+		wolfssl_tls_cert_event(conn, err_cert, depth, buf);
+	}
+
+	if (conn->cert_probe && preverify_ok && depth == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: Reject server certificate on probe-only run");
+		preverify_ok = 0;
+		wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Server certificate chain probe",
+				       TLS_FAIL_SERVER_CHAIN_PROBE);
+	}
+
+#ifdef HAVE_OCSP_WOLFSSL
+	if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+	    preverify_ok) {
+		enum ocsp_result res;
+
+		res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+				      conn->peer_issuer,
+				      conn->peer_issuer_issuer);
+		if (res == OCSP_REVOKED) {
+			preverify_ok = 0;
+			wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+					       "certificate revoked",
+					       TLS_FAIL_REVOKED);
+			if (err == X509_V_OK)
+				X509_STORE_CTX_set_error(
+					x509_ctx, X509_V_ERR_CERT_REVOKED);
+		} else if (res != OCSP_GOOD &&
+			   (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+			preverify_ok = 0;
+			wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+					       "bad certificate status response",
+					       TLS_FAIL_UNSPECIFIED);
+		}
+	}
+#endif /* HAVE_OCSP_WOLFSSL */
+	if (depth == 0 && preverify_ok && context->event_cb != NULL)
+		context->event_cb(context->cb_ctx,
+				  TLS_CERT_CHAIN_SUCCESS, NULL);
+
+	return preverify_ok;
+}
+
+
+static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
+				  const char *ca_cert,
+				  const u8 *ca_cert_blob, size_t blob_len,
+				  const char *ca_path)
+{
+	WOLFSSL_CTX *ctx = tls_ctx;
+
+	wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+	conn->ca_cert_verify = 1;
+
+	if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: Probe for server certificate chain");
+		conn->cert_probe = 1;
+		conn->ca_cert_verify = 0;
+		return 0;
+	}
+
+	if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
+#ifdef CONFIG_SHA256
+		const char *pos = ca_cert + 7;
+
+		if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "wolfSSL: Unsupported ca_cert hash value '%s'",
+				   ca_cert);
+			return -1;
+		}
+		pos += 14;
+		if (os_strlen(pos) != 32 * 2) {
+			wpa_printf(MSG_DEBUG,
+				   "wolfSSL: Unexpected SHA256 hash length in ca_cert '%s'",
+				   ca_cert);
+			return -1;
+		}
+		if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "wolfSSL: Invalid SHA256 hash value in ca_cert '%s'",
+				   ca_cert);
+			return -1;
+		}
+		conn->server_cert_only = 1;
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: Checking only server certificate match");
+		return 0;
+#else /* CONFIG_SHA256 */
+		wpa_printf(MSG_INFO,
+			   "No SHA256 included in the build - cannot validate server certificate hash");
+		return -1;
+#endif /* CONFIG_SHA256 */
+	}
+
+	if (ca_cert_blob) {
+		if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
+						   SSL_FILETYPE_ASN1) !=
+		    SSL_SUCCESS) {
+			wpa_printf(MSG_INFO, "SSL: failed to load CA blob");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
+		return 0;
+	}
+
+	if (ca_cert || ca_path) {
+		WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new();
+
+		if (!cm) {
+			wpa_printf(MSG_INFO,
+				   "SSL: failed to create certificate store");
+			return -1;
+		}
+		wolfSSL_CTX_set_cert_store(ctx, cm);
+
+		if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
+		    SSL_SUCCESS) {
+			wpa_printf(MSG_INFO,
+				   "SSL: failed to load ca_cert as PEM");
+
+			if (!ca_cert)
+				return -1;
+
+			if (wolfSSL_CTX_der_load_verify_locations(
+				    ctx, ca_cert, SSL_FILETYPE_ASN1) !=
+			    SSL_SUCCESS) {
+				wpa_printf(MSG_INFO,
+					   "SSL: failed to load ca_cert as DER");
+				return -1;
+			}
+		}
+		return 0;
+	}
+
+	conn->ca_cert_verify = 0;
+	return 0;
+}
+
+
+static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
+{
+#ifdef HAVE_SESSION_TICKET
+#if 0
+	if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
+		wolfSSL_UseSessionTicket(ssl);
+#endif
+#endif /* HAVE_SESSION_TICKET */
+
+	if (flags & TLS_CONN_DISABLE_TLSv1_0)
+		wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1);
+	if (flags & TLS_CONN_DISABLE_TLSv1_1)
+		wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+	if (flags & TLS_CONN_DISABLE_TLSv1_2)
+		wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	wpa_printf(MSG_DEBUG, "SSL: set params");
+
+	if (tls_connection_set_subject_match(conn, params->subject_match,
+					     params->altsubject_match,
+					     params->suffix_match,
+					     params->domain_match) < 0) {
+		wpa_printf(MSG_INFO, "Error setting subject match");
+		return -1;
+	}
+
+	if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+				   params->ca_cert_blob,
+				   params->ca_cert_blob_len,
+				   params->ca_path) < 0) {
+		wpa_printf(MSG_INFO, "Error setting CA cert");
+		return -1;
+	}
+
+	if (tls_connection_client_cert(conn, params->client_cert,
+				       params->client_cert_blob,
+				       params->client_cert_blob_len) < 0) {
+		wpa_printf(MSG_INFO, "Error setting client cert");
+		return -1;
+	}
+
+	if (tls_connection_private_key(tls_ctx, conn, params->private_key,
+				       params->private_key_passwd,
+				       params->private_key_blob,
+				       params->private_key_blob_len) < 0) {
+		wpa_printf(MSG_INFO, "Error setting private key");
+		return -1;
+	}
+
+	if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
+			      params->dh_blob_len) < 0) {
+		wpa_printf(MSG_INFO, "Error setting DH");
+		return -1;
+	}
+
+	if (params->openssl_ciphers &&
+	    wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+		wpa_printf(MSG_INFO,
+			   "wolfSSL: Failed to set cipher string '%s'",
+			   params->openssl_ciphers);
+		return -1;
+	}
+
+	tls_set_conn_flags(conn->ssl, params->flags);
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+	if (params->flags & TLS_CONN_REQUEST_OCSP) {
+		if (wolfSSL_UseOCSPStapling(conn->ssl, WOLFSSL_CSR_OCSP,
+					    WOLFSSL_CSR_OCSP_USE_NONCE) !=
+		    SSL_SUCCESS)
+			return -1;
+		wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+	}
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+	if (params->flags & TLS_CONN_REQUEST_OCSP) {
+		if (wolfSSL_UseOCSPStaplingV2(conn->ssl,
+					      WOLFSSL_CSR2_OCSP_MULTI, 0) !=
+		    SSL_SUCCESS)
+			return -1;
+		wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+	}
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
+    !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+#ifdef HAVE_OCSP
+	if (params->flags & TLS_CONN_REQUEST_OCSP)
+		wolfSSL_CTX_EnableOCSP(ctx, 0);
+#else /* HAVE_OCSP */
+	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+		wpa_printf(MSG_INFO,
+			   "wolfSSL: No OCSP support included - reject configuration");
+		return -1;
+	}
+	if (params->flags & TLS_CONN_REQUEST_OCSP) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: No OCSP support included - allow optional OCSP case to continue");
+	}
+#endif /* HAVE_OCSP */
+#endif /* !HAVE_CERTIFICATE_STATUS_REQUEST &&
+	* !HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+	conn->flags = params->flags;
+
+	return 0;
+}
+
+
+static int tls_global_ca_cert(void *ssl_ctx, const char *ca_cert)
+{
+	WOLFSSL_CTX *ctx = ssl_ctx;
+
+	if (ca_cert) {
+		if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1)
+		{
+			wpa_printf(MSG_WARNING,
+				   "Failed to load root certificates");
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "TLS: Trusted root certificate(s) loaded");
+	}
+
+	return 0;
+}
+
+
+static int tls_global_client_cert(void *ssl_ctx, const char *client_cert)
+{
+	WOLFSSL_CTX *ctx = ssl_ctx;
+
+	if (!client_cert)
+		return 0;
+
+	if (wolfSSL_CTX_use_certificate_chain_file_format(ctx, client_cert,
+							  SSL_FILETYPE_ASN1) !=
+	    SSL_SUCCESS &&
+	    wolfSSL_CTX_use_certificate_chain_file(ctx, client_cert) !=
+	    SSL_SUCCESS) {
+		wpa_printf(MSG_INFO, "Failed to load client certificate");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "SSL: Loaded global client certificate: %s",
+		   client_cert);
+
+	return 0;
+}
+
+
+static int tls_global_private_key(void *ssl_ctx, const char *private_key,
+				  const char *private_key_passwd)
+{
+	WOLFSSL_CTX *ctx = ssl_ctx;
+	char *passwd = NULL;
+	int ret = 0;
+
+	if (!private_key)
+		return 0;
+
+	if (private_key_passwd) {
+		passwd = os_strdup(private_key_passwd);
+		if (!passwd)
+			return -1;
+	}
+
+	wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+	wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+	if (wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+					    SSL_FILETYPE_ASN1) != 1 &&
+	    wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+					    SSL_FILETYPE_PEM) != 1) {
+		wpa_printf(MSG_INFO, "Failed to load private key");
+		ret = -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "SSL: Loaded global private key");
+
+	os_free(passwd);
+	wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+
+	return ret;
+}
+
+
+static int tls_global_dh(void *ssl_ctx, const char *dh_file,
+			 const u8 *dh_blob, size_t blob_len)
+{
+	WOLFSSL_CTX *ctx = ssl_ctx;
+
+	if (!dh_file && !dh_blob)
+		return 0;
+
+	if (dh_blob) {
+		if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
+						SSL_FILETYPE_ASN1) < 0) {
+			wpa_printf(MSG_INFO,
+				   "SSL: global use DH DER blob failed");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK");
+		return 0;
+	}
+
+	if (dh_file) {
+		if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
+		    0) {
+			wpa_printf(MSG_INFO,
+				   "SSL: global use DH PEM file failed");
+			if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file,
+						      SSL_FILETYPE_ASN1) < 0) {
+				wpa_printf(MSG_INFO,
+					   "SSL: global use DH DER file failed");
+				return -1;
+			}
+		}
+		wpa_printf(MSG_DEBUG, "SSL: global use DH file OK");
+		return 0;
+	}
+
+	return 0;
+}
+
+
+#ifdef HAVE_OCSP
+
+int ocsp_status_cb(void *unused, const char *url, int url_sz,
+		   unsigned char *request, int request_sz,
+		   unsigned char **response)
+{
+	size_t len;
+
+	(void) unused;
+
+	if (!url) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: OCSP status callback - no response configured");
+		*response = NULL;
+		return 0;
+	}
+
+	*response = (unsigned char *) os_readfile(url, &len);
+	if (!*response) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: OCSP status callback - could not read response file");
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG,
+		   "wolfSSL: OCSP status callback - send cached response");
+	return len;
+}
+
+
+void ocsp_resp_free_cb(void *ocsp_stapling_response, unsigned char *response)
+{
+	os_free(response);
+}
+
+#endif /* HAVE_OCSP */
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	wpa_printf(MSG_DEBUG, "SSL: global set params");
+
+	if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
+		wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
+			   params->ca_cert);
+		return -1;
+	}
+
+	if (tls_global_client_cert(tls_ctx, params->client_cert) < 0) {
+		wpa_printf(MSG_INFO,
+			   "SSL: Failed to load client cert file '%s'",
+			   params->client_cert);
+		return -1;
+	}
+
+	if (tls_global_private_key(tls_ctx, params->private_key,
+				   params->private_key_passwd) < 0) {
+		wpa_printf(MSG_INFO,
+			   "SSL: Failed to load private key file '%s'",
+			   params->private_key);
+		return -1;
+	}
+
+	if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
+			  params->dh_blob_len) < 0) {
+		wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
+			   params->dh_file);
+		return -1;
+	}
+
+	if (params->openssl_ciphers &&
+	    wolfSSL_CTX_set_cipher_list(tls_ctx,
+					params->openssl_ciphers) != 1) {
+		wpa_printf(MSG_INFO,
+			   "wolfSSL: Failed to set cipher string '%s'",
+			   params->openssl_ciphers);
+		return -1;
+	}
+
+#ifdef HAVE_SESSION_TICKET
+	/* Session ticket is off by default - can't disable once on. */
+	if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
+		wolfSSL_CTX_UseSessionTicket(tls_ctx);
+#endif /* HAVE_SESSION_TICKET */
+
+#ifdef HAVE_OCSP
+	if (params->ocsp_stapling_response) {
+		wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx,
+						params->ocsp_stapling_response);
+		wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb,
+				       ocsp_resp_free_cb, NULL);
+	}
+#endif /* HAVE_OCSP */
+
+	return 0;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
+
+	if (check_crl) {
+		/* Hack to Enable CRLs. */
+		wolfSSL_CTX_LoadCRLBuffer(tls_ctx, NULL, 0, SSL_FILETYPE_PEM);
+	}
+
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer, unsigned int flags,
+			      const u8 *session_ctx, size_t session_ctx_len)
+{
+	if (!conn)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer);
+
+	if (verify_peer) {
+		conn->ca_cert_verify = 1;
+		wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+				   SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+				   tls_verify_cb);
+	} else {
+		conn->ca_cert_verify = 0;
+		wolfSSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+	}
+
+	wolfSSL_set_accept_state(conn->ssl);
+
+	/* TODO: do we need to fake a session like OpenSSL does here? */
+
+	return 0;
+}
+
+
+static struct wpabuf * wolfssl_handshake(struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 int server)
+{
+	int res;
+
+	wolfssl_reset_out_data(&conn->output);
+
+	/* Initiate TLS handshake or continue the existing handshake */
+	if (server) {
+		wolfSSL_set_accept_state(conn->ssl);
+		res = wolfSSL_accept(conn->ssl);
+		wpa_printf(MSG_DEBUG, "SSL: wolfSSL_accept: %d", res);
+	} else {
+		wolfSSL_set_connect_state(conn->ssl);
+		res = wolfSSL_connect(conn->ssl);
+		wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res);
+	}
+
+	if (res != 1) {
+		int err = wolfSSL_get_error(conn->ssl, res);
+
+		if (err == SSL_ERROR_WANT_READ) {
+			wpa_printf(MSG_DEBUG,
+				   "SSL: wolfSSL_connect - want more data");
+		} else if (err == SSL_ERROR_WANT_WRITE) {
+			wpa_printf(MSG_DEBUG,
+				   "SSL: wolfSSL_connect - want to write");
+		} else {
+			char msg[80];
+
+			wpa_printf(MSG_DEBUG,
+				   "SSL: wolfSSL_connect - failed %s",
+				   wolfSSL_ERR_error_string(err, msg));
+			conn->failed++;
+		}
+	}
+
+	return conn->output.out_data;
+}
+
+
+static struct wpabuf * wolfssl_get_appl_data(struct tls_connection *conn,
+					     size_t max_len)
+{
+	int res;
+	struct wpabuf *appl_data = wpabuf_alloc(max_len + 100);
+
+	if (!appl_data)
+		return NULL;
+
+	res = wolfSSL_read(conn->ssl, wpabuf_mhead(appl_data),
+			   wpabuf_size(appl_data));
+	if (res < 0) {
+		int err = wolfSSL_get_error(conn->ssl, res);
+
+		if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
+			wpa_printf(MSG_DEBUG,
+				   "SSL: No Application Data included");
+		} else {
+			char msg[80];
+
+			wpa_printf(MSG_DEBUG,
+				   "Failed to read possible Application Data %s",
+				   wolfSSL_ERR_error_string(err, msg));
+		}
+
+		wpabuf_free(appl_data);
+		return NULL;
+	}
+
+	wpabuf_put(appl_data, res);
+	wpa_hexdump_buf_key(MSG_MSGDUMP,
+			    "SSL: Application Data in Finished message",
+			    appl_data);
+	return appl_data;
+}
+
+
+static struct wpabuf *
+wolfssl_connection_handshake(struct tls_connection *conn,
+			     const struct wpabuf *in_data,
+			     struct wpabuf **appl_data, int server)
+{
+	struct wpabuf *out_data;
+
+	wolfssl_reset_in_data(&conn->input, in_data);
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	out_data = wolfssl_handshake(conn, in_data, server);
+	if (!out_data)
+		return NULL;
+
+	if (wolfSSL_is_init_finished(conn->ssl)) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: Handshake finished - resumed=%d",
+			   tls_connection_resumed(NULL, conn));
+		if (appl_data && in_data)
+			*appl_data = wolfssl_get_appl_data(conn,
+							   wpabuf_len(in_data));
+	}
+
+	return out_data;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	return wolfssl_connection_handshake(conn, in_data, appl_data, 0);
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return wolfssl_connection_handshake(conn, in_data, appl_data, 1);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	int res;
+
+	if (!conn)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "SSL: encrypt: %ld bytes", wpabuf_len(in_data));
+
+	wolfssl_reset_out_data(&conn->output);
+
+	res = wolfSSL_write(conn->ssl, wpabuf_head(in_data),
+			    wpabuf_len(in_data));
+	if (res < 0) {
+		int  err = wolfSSL_get_error(conn->ssl, res);
+		char msg[80];
+
+		wpa_printf(MSG_INFO, "Encryption failed - SSL_write: %s",
+			   wolfSSL_ERR_error_string(err, msg));
+		return NULL;
+	}
+
+	return conn->output.out_data;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	int res;
+	struct wpabuf *buf;
+
+	if (!conn)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "SSL: decrypt");
+
+	wolfssl_reset_in_data(&conn->input, in_data);
+
+	/* Read decrypted data for further processing */
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+	if (!buf)
+		return NULL;
+	res = wolfSSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "Decryption failed - SSL_read");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	wpabuf_put(buf, res);
+
+	wpa_printf(MSG_DEBUG, "SSL: decrypt: %ld bytes", wpabuf_len(buf));
+
+	return buf;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+	return conn ? wolfSSL_session_reused(conn->ssl) : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	char buf[128], *pos, *end;
+	u8 *c;
+	int ret;
+
+	if (!conn || !conn->ssl || !ciphers)
+		return -1;
+
+	buf[0] = '\0';
+	pos = buf;
+	end = pos + sizeof(buf);
+
+	c = ciphers;
+	while (*c != TLS_CIPHER_NONE) {
+		const char *suite;
+
+		switch (*c) {
+		case TLS_CIPHER_RC4_SHA:
+			suite = "RC4-SHA";
+			break;
+		case TLS_CIPHER_AES128_SHA:
+			suite = "AES128-SHA";
+			break;
+		case TLS_CIPHER_RSA_DHE_AES128_SHA:
+			suite = "DHE-RSA-AES128-SHA";
+			break;
+		case TLS_CIPHER_ANON_DH_AES128_SHA:
+			suite = "ADH-AES128-SHA";
+			break;
+		case TLS_CIPHER_RSA_DHE_AES256_SHA:
+			suite = "DHE-RSA-AES256-SHA";
+			break;
+		case TLS_CIPHER_AES256_SHA:
+			suite = "AES256-SHA";
+			break;
+		default:
+			wpa_printf(MSG_DEBUG,
+				   "TLS: Unsupported cipher selection: %d", *c);
+			return -1;
+		}
+		ret = os_snprintf(pos, end - pos, ":%s", suite);
+		if (os_snprintf_error(end - pos, ret))
+			break;
+		pos += ret;
+
+		c++;
+	}
+
+	wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1);
+
+	if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
+		wpa_printf(MSG_DEBUG, "Cipher suite configuration failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	WOLFSSL_CIPHER *cipher;
+	const char *name;
+
+	if (!conn || !conn->ssl)
+		return -1;
+
+	cipher = wolfSSL_get_current_cipher(conn->ssl);
+	if (!cipher)
+		return -1;
+
+	name = wolfSSL_CIPHER_get_name(cipher);
+	if (!name)
+		return -1;
+
+	if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0)
+		os_strlcpy(buf, "RC4-SHA", buflen);
+	else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0)
+		os_strlcpy(buf, "AES128-SHA", buflen);
+	else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0)
+		os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen);
+	else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0)
+		os_strlcpy(buf, "ADH-AES128-SHA", buflen);
+	else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0)
+		os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen);
+	else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0)
+		os_strlcpy(buf, "AES256-SHA", buflen);
+	else
+		os_strlcpy(buf, name, buflen);
+
+	return 0;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	/* no empty fragments in wolfSSL for now */
+	return 0;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	if (!conn)
+		return -1;
+
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	if (!conn)
+		return -1;
+
+	/* TODO: this is not incremented anywhere */
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	if (!conn)
+		return -1;
+
+	/* TODO: this is not incremented anywhere */
+	return conn->write_alerts;
+}
+
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+	return os_snprintf(buf, buf_len, "wolfSSL build=%s run=%s",
+			   WOLFSSL_VERSION, wolfSSL_lib_version());
+}
+
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+		    char *buf, size_t buflen)
+{
+	const char *name;
+
+	if (!conn || !conn->ssl)
+		return -1;
+
+	name = wolfSSL_get_version(conn->ssl);
+	if (!name)
+		return -1;
+
+	os_strlcpy(buf, name, buflen);
+	return 0;
+}
+
+
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+			      struct tls_random *keys)
+{
+	WOLFSSL *ssl;
+
+	if (!conn || !keys)
+		return -1;
+	ssl = conn->ssl;
+	if (!ssl)
+		return -1;
+
+	os_memset(keys, 0, sizeof(*keys));
+	keys->client_random = conn->client_random;
+	keys->client_random_len = wolfSSL_get_client_random(
+		ssl, conn->client_random, sizeof(conn->client_random));
+	keys->server_random = conn->server_random;
+	keys->server_random_len = wolfSSL_get_server_random(
+		ssl, conn->server_random, sizeof(conn->server_random));
+
+	return 0;
+}
+
+
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+			      const char *label, u8 *out, size_t out_len)
+{
+	if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+		return -1;
+	return 0;
+}
+
+
+#define SEED_LEN	(RAN_LEN + RAN_LEN)
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+				    u8 *out, size_t out_len)
+{
+	byte seed[SEED_LEN];
+	int ret = -1;
+	WOLFSSL *ssl;
+	byte *tmp_out;
+	byte *_out;
+	int skip = 0;
+	byte *master_key;
+	unsigned int master_key_len;
+	byte *server_random;
+	unsigned int server_len;
+	byte *client_random;
+	unsigned int client_len;
+
+	if (!conn || !conn->ssl)
+		return -1;
+	ssl = conn->ssl;
+
+	skip = 2 * (wolfSSL_GetKeySize(ssl) + wolfSSL_GetHmacSize(ssl) +
+		    wolfSSL_GetIVSize(ssl));
+
+	tmp_out = os_malloc(skip + out_len);
+	if (!tmp_out)
+		return -1;
+	_out = tmp_out;
+
+	wolfSSL_get_keys(ssl, &master_key, &master_key_len, &server_random,
+			 &server_len, &client_random, &client_len);
+	os_memcpy(seed, server_random, RAN_LEN);
+	os_memcpy(seed + RAN_LEN, client_random, RAN_LEN);
+
+	if (wolfSSL_GetVersion(ssl) == WOLFSSL_TLSV1_2) {
+		tls_prf_sha256(master_key, master_key_len,
+			       "key expansion", seed, sizeof(seed),
+			       _out, skip + out_len);
+		ret = 0;
+	} else {
+		ret = tls_prf_sha1_md5(master_key, master_key_len,
+				       "key expansion", seed, sizeof(seed),
+				       _out, skip + out_len);
+	}
+
+	os_memset(master_key, 0, master_key_len);
+	if (ret == 0)
+		os_memcpy(out, _out + skip, out_len);
+	bin_clear_free(tmp_out, skip + out_len);
+
+	return ret;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	(void) ssl_ctx;
+
+	if (!conn || !conn->ssl || ext_type != 35)
+		return -1;
+
+	if (wolfSSL_set_SessionTicket(conn->ssl, data,
+				      (unsigned int) data_len) != 1)
+		return -1;
+
+	return 0;
+}
+
+
+static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
+{
+	struct tls_connection *conn = arg;
+	int ret;
+	unsigned char client_random[RAN_LEN];
+	unsigned char server_random[RAN_LEN];
+	word32 ticket_len = sizeof(conn->session_ticket);
+
+	if (!conn || !conn->session_ticket_cb)
+		return 1;
+
+	if (wolfSSL_get_client_random(s, client_random,
+				      sizeof(client_random)) == 0 ||
+	    wolfSSL_get_server_random(s, server_random,
+				      sizeof(server_random)) == 0 ||
+	    wolfSSL_get_SessionTicket(s, conn->session_ticket,
+				      &ticket_len) != 1)
+		return 1;
+
+	if (ticket_len == 0)
+		return 0;
+
+	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+				      conn->session_ticket, ticket_len,
+				      client_random, server_random, secret);
+	if (ret <= 0)
+		return 1;
+
+	*secret_len = SECRET_LEN;
+	return 0;
+}
+
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+
+	if (cb) {
+		if (wolfSSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+						  conn) != 1)
+			return -1;
+	} else {
+		if (wolfSSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+	}
+
+	return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+	return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+	wpa_printf(MSG_DEBUG,
+		   "wolfSSL: Success data accepted for resumed session");
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+	WOLFSSL_SESSION *sess;
+
+	sess = wolfSSL_get_session(conn->ssl);
+	if (!sess)
+		return;
+
+	wolfSSL_SSL_SESSION_set_timeout(sess, 0);
+	wpa_printf(MSG_DEBUG,
+		   "wolfSSL: Removed cached session to disable session resumption");
+}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+				     struct wpabuf *data)
+{
+	WOLFSSL_SESSION *sess;
+	struct wpabuf *old;
+
+	wpa_printf(MSG_DEBUG, "wolfSSL: Set success data");
+
+	sess = wolfSSL_get_session(conn->ssl);
+	if (!sess) {
+		wpa_printf(MSG_DEBUG,
+			   "wolfSSL: No session found for success data");
+		goto fail;
+	}
+
+	old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+	if (old) {
+		wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p",
+			   old);
+		wpabuf_free(old);
+	}
+	if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+		goto fail;
+
+	wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data);
+	conn->success_data = 1;
+	return;
+
+fail:
+	wpa_printf(MSG_INFO, "wolfSSL: Failed to store success data");
+	wpabuf_free(data);
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+	WOLFSSL_SESSION *sess;
+
+	wpa_printf(MSG_DEBUG, "wolfSSL: Get success data");
+
+	sess = wolfSSL_get_session(conn->ssl);
+	if (!sess)
+		return NULL;
+	return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a6307e3..d34c679 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -567,6 +567,18 @@
 	 */
 	s8 relative_adjust_rssi;
 
+	/**
+	 * oce_scan
+	 *
+	 * Enable the following OCE scan features: (WFA OCE TechSpec v1.0)
+	 * - Accept broadcast Probe Response frame.
+	 * - Probe Request frame deferral and suppression.
+	 * - Max Channel Time - driver fills FILS request params IE with
+	 *   Maximum Channel Time.
+	 * - Send 1st Probe Request frame in rate of minimum 5.5 Mbps.
+	 */
+	unsigned int oce_scan:1;
+
 	/*
 	 * NOTE: Whenever adding new parameters here, please make sure
 	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -1563,6 +1575,10 @@
  * functionality but can support only OCE STA-CFON functionality.
  */
 #define WPA_DRIVER_FLAGS_OCE_STA_CFON		0x0020000000000000ULL
+/** Driver supports MFP-optional in the connect command */
+#define WPA_DRIVER_FLAGS_MFP_OPTIONAL		0x0040000000000000ULL
+/** Driver is a self-managed regulatory device */
+#define WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY       0x0080000000000000ULL
 	u64 flags;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -1692,6 +1708,7 @@
 #define STA_DRV_DATA_RX_VHT_NSS BIT(5)
 #define STA_DRV_DATA_TX_SHORT_GI BIT(6)
 #define STA_DRV_DATA_RX_SHORT_GI BIT(7)
+#define STA_DRV_DATA_LAST_ACK_RSSI BIT(8)
 
 struct hostap_sta_driver_data {
 	unsigned long rx_packets, tx_packets;
@@ -1704,8 +1721,7 @@
 	unsigned long num_ps_buf_frames;
 	unsigned long tx_retry_failed;
 	unsigned long tx_retry_count;
-	int last_rssi;
-	int last_ack_rssi;
+	s8 last_ack_rssi;
 	s8 signal;
 	u8 rx_vhtmcs;
 	u8 tx_vhtmcs;
@@ -1875,6 +1891,17 @@
 	WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
 };
 
+/* enum smps_mode - SMPS mode definitions */
+enum smps_mode {
+	SMPS_AUTOMATIC,
+	SMPS_OFF,
+	SMPS_DYNAMIC,
+	SMPS_STATIC,
+
+	/* Keep last */
+	SMPS_INVALID,
+};
+
 /* enum chan_width - Channel width definitions */
 enum chan_width {
 	CHAN_WIDTH_20_NOHT,
@@ -2052,6 +2079,36 @@
 };
 
 /**
+ * struct external_auth - External authentication trigger parameters
+ *
+ * These are used across the external authentication request and event
+ * interfaces.
+ * @action: Action type / trigger for external authentication. Only significant
+ *	for the event interface.
+ * @bssid: BSSID of the peer with which the authentication has to happen. Used
+ *	by both the request and event interface.
+ * @ssid: SSID of the AP. Used by both the request and event interface.
+ * @ssid_len: SSID length in octets.
+ * @key_mgmt_suite: AKM suite of the respective authentication. Optional for
+ *	the request interface.
+ * @status: Status code, %WLAN_STATUS_SUCCESS for successful authentication,
+ *	use %WLAN_STATUS_UNSPECIFIED_FAILURE if wpa_supplicant cannot give
+ *	the real status code for failures. Used only for the request interface
+ *	from user space to the driver.
+ */
+struct external_auth {
+	enum {
+		EXT_AUTH_START,
+		EXT_AUTH_ABORT,
+	} action;
+	u8 bssid[ETH_ALEN];
+	u8 ssid[SSID_MAX_LEN];
+	size_t ssid_len;
+	unsigned int key_mgmt_suite;
+	u16 status;
+};
+
+/**
  * struct wpa_driver_ops - Driver interface API definition
  *
  * This structure defines the API that each driver interface needs to implement
@@ -3611,6 +3668,17 @@
 	int (*roaming)(void *priv, int allowed, const u8 *bssid);
 
 	/**
+	 * disable_fils - Enable/disable FILS feature
+	 * @priv: Private driver interface data
+	 * @disable: 0-enable and 1-disable FILS feature
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback can be used to configure driver and below layers to
+	 * enable/disable all FILS features.
+	 */
+	int (*disable_fils)(void *priv, int disable);
+
+	/**
 	 * set_mac_addr - Set MAC address
 	 * @priv: Private driver interface data
 	 * @addr: MAC address to use or %NULL for setting back to permanent
@@ -4001,6 +4069,16 @@
 	int (*update_connect_params)(
 		void *priv, struct wpa_driver_associate_params *params,
 		enum wpa_drv_update_connect_params_mask mask);
+
+	/**
+	 * send_external_auth_status - Indicate the status of external
+	 * authentication processing to the host driver.
+	 * @priv: Private driver interface data
+	 * @params: Status of authentication processing.
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*send_external_auth_status)(void *priv,
+					 struct external_auth *params);
 };
 
 /**
@@ -4496,6 +4574,47 @@
 	 * performed before start operating on this channel.
 	 */
 	EVENT_DFS_PRE_CAC_EXPIRED,
+
+	/**
+	 * EVENT_EXTERNAL_AUTH - This event interface is used by host drivers
+	 * that do not define separate commands for authentication and
+	 * association (~WPA_DRIVER_FLAGS_SME) but offload the 802.11
+	 * authentication to wpa_supplicant. This event carries all the
+	 * necessary information from the host driver for the authentication to
+	 * happen.
+	 */
+	EVENT_EXTERNAL_AUTH,
+
+	/**
+	 * EVENT_PORT_AUTHORIZED - Notification that a connection is authorized
+	 *
+	 * This event should be indicated when the driver completes the 4-way
+	 * handshake. This event should be preceded by an EVENT_ASSOC that
+	 * indicates the completion of IEEE 802.11 association.
+	 */
+	EVENT_PORT_AUTHORIZED,
+
+	/**
+	 * EVENT_STATION_OPMODE_CHANGED - Notify STA's HT/VHT operation mode
+	 * change event.
+	 */
+	EVENT_STATION_OPMODE_CHANGED,
+
+	/**
+	 * EVENT_INTERFACE_MAC_CHANGED - Notify that interface MAC changed
+	 *
+	 * This event is emitted when the MAC changes while the interface is
+	 * enabled. When an interface was disabled and becomes enabled, it
+	 * must be always assumed that the MAC possibly changed.
+	 */
+	EVENT_INTERFACE_MAC_CHANGED,
+
+	/**
+	 * EVENT_WDS_STA_INTERFACE_STATUS - Notify WDS STA interface status
+	 *
+	 * This event is emitted when an interface is added/removed for WDS STA.
+	 */
+	EVENT_WDS_STA_INTERFACE_STATUS,
 };
 
 
@@ -5298,6 +5417,37 @@
 			P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
 		} reason_code;
 	} p2p_lo_stop;
+
+	/* For EVENT_EXTERNAL_AUTH */
+	struct external_auth external_auth;
+
+	/**
+	 * struct sta_opmode - Station's operation mode change event
+	 * @addr: The station MAC address
+	 * @smps_mode: SMPS mode of the station
+	 * @chan_width: Channel width of the station
+	 * @rx_nss: RX_NSS of the station
+	 *
+	 * This is used as data with EVENT_STATION_OPMODE_CHANGED.
+	 */
+	struct sta_opmode {
+		const u8 *addr;
+		enum smps_mode smps_mode;
+		enum chan_width chan_width;
+		u8 rx_nss;
+	} sta_opmode;
+
+	/**
+	 * struct wds_sta_interface - Data for EVENT_WDS_STA_INTERFACE_STATUS.
+	 */
+	struct wds_sta_interface {
+		const u8 *sta_addr;
+		const char *ifname;
+		enum {
+			INTERFACE_ADDED,
+			INTERFACE_REMOVED
+		} istatus;
+	} wds_sta_interface;
 };
 
 /**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index d2b355c..16c2ae9 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -931,6 +931,12 @@
 		if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
 			break;
 		os_memset(&event, 0, sizeof(event));
+		if (le_to_host16(mgmt->u.auth.auth_alg) == WLAN_AUTH_SAE) {
+			event.rx_mgmt.frame = buf;
+			event.rx_mgmt.frame_len = len;
+			wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+			break;
+		}
 		os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
 		os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
 		event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
@@ -1352,6 +1358,40 @@
 	}
 }
 
+
+static void send_action_cb_event(struct atheros_driver_data *drv,
+				 char *data, size_t data_len)
+{
+	union wpa_event_data event;
+	struct ieee80211_send_action_cb *sa;
+	const struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	if (data_len < sizeof(*sa) + 24) {
+		wpa_printf(MSG_DEBUG,
+			   "athr: Too short event message (data_len=%d sizeof(*sa)=%d)",
+			   (int) data_len, (int) sizeof(*sa));
+		wpa_hexdump(MSG_DEBUG, "athr: Short event message",
+			    data, data_len);
+		return;
+	}
+
+	sa = (struct ieee80211_send_action_cb *) data;
+
+	hdr = (const struct ieee80211_hdr *) (sa + 1);
+	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);
+	event.tx_status.dst = sa->dst_addr;
+	event.tx_status.data = (const u8 *) hdr;
+	event.tx_status.data_len = data_len - sizeof(*sa);
+	event.tx_status.ack = sa->ack;
+	wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event);
+}
+
+
 /*
 * Handle size of data problem. WEXT only allows data of 256 bytes for custom
 * events, and p2p data can be much bigger. So the athr driver sends a small
@@ -1416,6 +1456,11 @@
 						     &event);
 				continue;
 			}
+		} else if (frame_type == IEEE80211_EV_P2P_SEND_ACTION_CB) {
+			wpa_printf(MSG_DEBUG,
+				   "%s: ACTION_CB frame_type=%u len=%zu",
+				   __func__, frame_type, data_len);
+			send_action_cb_event(drv, (void *) mgmt, data_len);
 		} else {
 			wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
 				   __func__, frame_type);
@@ -1429,6 +1474,10 @@
 				      int opcode, char *buf, int len)
 {
 	switch (opcode) {
+	case IEEE80211_EV_P2P_SEND_ACTION_CB:
+		wpa_printf(MSG_DEBUG, "WEXT: EV_P2P_SEND_ACTION_CB");
+		fetch_pending_big_events(drv);
+		break;
 	case IEEE80211_EV_RX_MGMT:
 		wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
 		fetch_pending_big_events(drv);
@@ -1812,7 +1861,7 @@
 	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
 	iwr.u.essid.flags = 1; /* SSID active */
 	iwr.u.essid.pointer = (caddr_t) buf;
-	iwr.u.essid.length = len + 1;
+	iwr.u.essid.length = len;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
 		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
@@ -1925,7 +1974,7 @@
 }
 
 
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
 
 static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
 			     int noack, unsigned int freq,
@@ -1951,7 +2000,7 @@
 	return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
 			    sizeof(struct ieee80211req_mgmtbuf) + data_len);
 }
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
 
 
 #ifdef CONFIG_IEEE80211R
@@ -2239,7 +2288,7 @@
 	.sta_assoc              = atheros_sta_assoc,
 	.sta_auth               = atheros_sta_auth,
 	.send_mlme       	= atheros_send_mgmt,
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R
 	.add_tspec      	= atheros_add_tspec,
 	.add_sta_node    	= atheros_add_sta_node,
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 0464304..ac0916e 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -82,6 +82,11 @@
 	E2S(P2P_LO_STOP);
 	E2S(BEACON_LOSS);
 	E2S(DFS_PRE_CAC_EXPIRED);
+	E2S(EXTERNAL_AUTH);
+	E2S(PORT_AUTHORIZED);
+	E2S(STATION_OPMODE_CHANGED);
+	E2S(INTERFACE_MAC_CHANGED);
+	E2S(WDS_STA_INTERFACE_STATUS);
 	}
 
 	return "UNKNOWN";
@@ -268,6 +273,19 @@
 	DF2S(OFFCHANNEL_SIMULTANEOUS);
 	DF2S(FULL_AP_CLIENT_STATE);
 	DF2S(P2P_LISTEN_OFFLOAD);
+	DF2S(SUPPORT_FILS);
+	DF2S(BEACON_RATE_LEGACY);
+	DF2S(BEACON_RATE_HT);
+	DF2S(BEACON_RATE_VHT);
+	DF2S(MGMT_TX_RANDOM_TA);
+	DF2S(MGMT_TX_RANDOM_TA_CONNECTED);
+	DF2S(SCHED_SCAN_RELATIVE_RSSI);
+	DF2S(HE_CAPABILITIES);
+	DF2S(FILS_SK_OFFLOAD);
+	DF2S(OCE_STA);
+	DF2S(OCE_AP);
+	DF2S(OCE_STA_CFON);
+	DF2S(MFP_OPTIONAL);
 	}
 	return "UNKNOWN";
 #undef DF2S
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index d3be19c..e397950 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -39,6 +39,9 @@
 
 #define MAXSC 16
 
+#define SAK_128_LEN	16
+#define SAK_256_LEN	32
+
 /* TCI field definition */
 #define TCI_ES                0x40
 #define TCI_SC                0x20
@@ -226,19 +229,32 @@
 }
 
 
+static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs)
+{
+	if (cs == CS_ID_GCM_AES_128)
+		return FAL_CIPHER_SUITE_AES_GCM_128;
+	if (cs == CS_ID_GCM_AES_256)
+		return FAL_CIPHER_SUITE_AES_GCM_256;
+	return FAL_CIPHER_SUITE_MAX;
+}
+
+
 static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
 {
-	if (cs != CS_ID_GCM_AES_128) {
+	struct macsec_qca_data *drv = priv;
+	fal_cipher_suite_e cs_type;
+
+	if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
 		wpa_printf(MSG_ERROR,
 			   "%s: NOT supported CipherSuite: %016" PRIx64,
 			   __func__, cs);
 		return -1;
 	}
 
-	/* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
-	wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
+	wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs);
 
-	return 0;
+	cs_type = macsec_qca_cs_type_get(cs);
+	return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type);
 }
 
 
@@ -436,8 +452,8 @@
 	os_memset(&entry, 0, sizeof(entry));
 
 	os_memcpy(entry.sci, sci_addr, ETH_ALEN);
-	entry.sci[6] = (sci_port >> 8) & 0xf;
-	entry.sci[7] = sci_port & 0xf;
+	entry.sci[6] = (sci_port >> 8) & 0xff;
+	entry.sci[7] = sci_port & 0xff;
 	entry.sci_mask = 0xf;
 
 	entry.valid = 1;
@@ -499,6 +515,8 @@
 	fal_rx_sak_t rx_sak;
 	int i = 0;
 	u32 channel;
+	fal_rx_prc_lut_t entry;
+	u32 offset;
 
 	ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
 	if (ret != 0)
@@ -508,9 +526,30 @@
 		   __func__, channel, sa->an, sa->lowest_pn);
 
 	os_memset(&rx_sak, 0, sizeof(rx_sak));
-	for (i = 0; i < 16; i++)
-		rx_sak.sak[i] = sa->pkey->key[15 - i];
+	rx_sak.sak_len = sa->pkey->key_len;
+	if (sa->pkey->key_len == SAK_128_LEN) {
+		for (i = 0; i < 16; i++)
+			rx_sak.sak[i] = sa->pkey->key[15 - i];
+	} else if (sa->pkey->key_len == SAK_256_LEN) {
+		for (i = 0; i < 16; i++) {
+			rx_sak.sak1[i] = sa->pkey->key[15 - i];
+			rx_sak.sak[i] = sa->pkey->key[31 - i];
+		}
+	} else {
+		return -1;
+	}
 
+	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
+		offset = 0;
+	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
+		offset = 30;
+	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
+		offset = 50;
+	else
+		return -1;
+	ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry);
+	entry.offset = offset;
+	ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
 	ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
 	ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
 					  &rx_sak);
@@ -592,6 +631,7 @@
 	fal_tx_class_lut_t entry;
 	u8 psci[ETH_ALEN + 2];
 	u32 channel;
+	u16 sci_port = be_to_host16(sc->sci.port);
 
 	ret = macsec_qca_get_available_transmit_sc(priv, &channel);
 	if (ret != 0)
@@ -607,8 +647,8 @@
 	entry.channel = channel;
 
 	os_memcpy(psci, sc->sci.addr, ETH_ALEN);
-	psci[6] = (sc->sci.port >> 8) & 0xf;
-	psci[7] = sc->sci.port & 0xf;
+	psci[6] = (sci_port >> 8) & 0xff;
+	psci[7] = sci_port & 0xff;
 
 	ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
 	ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
@@ -655,6 +695,7 @@
 	fal_tx_sak_t tx_sak;
 	int i;
 	u32 channel;
+	u32 offset;
 
 	ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
 	if (ret != 0)
@@ -675,9 +716,30 @@
 		tci |= TCI_E | TCI_C;
 
 	os_memset(&tx_sak, 0, sizeof(tx_sak));
-	for (i = 0; i < 16; i++)
-		tx_sak.sak[i] = sa->pkey->key[15 - i];
+	tx_sak.sak_len = sa->pkey->key_len;
+	if (sa->pkey->key_len == SAK_128_LEN) {
+		for (i = 0; i < 16; i++)
+			tx_sak.sak[i] = sa->pkey->key[15 - i];
+	} else if (sa->pkey->key_len == SAK_256_LEN) {
+		for (i = 0; i < 16; i++) {
+			tx_sak.sak1[i] = sa->pkey->key[15 - i];
+			tx_sak.sak[i] = sa->pkey->key[31 - i];
+		}
+	} else {
+		return -1;
+	}
 
+	if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
+		offset = 0;
+	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
+		offset = 30;
+	else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
+		offset = 50;
+	else
+		return -1;
+	ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
+								channel,
+								offset);
 	ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
 						 sa->next_pn);
 	ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 2ce03ed..771e766 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -40,6 +40,29 @@
 #include "driver_nl80211.h"
 
 
+/* support for extack if compilation headers are too old */
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+enum nlmsgerr_attrs {
+	NLMSGERR_ATTR_UNUSED,
+	NLMSGERR_ATTR_MSG,
+	NLMSGERR_ATTR_OFFS,
+	NLMSGERR_ATTR_COOKIE,
+
+	__NLMSGERR_ATTR_MAX,
+	NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#endif
+#ifndef NLM_F_CAPPED
+#define NLM_F_CAPPED 0x100
+#endif
+#ifndef NLM_F_ACK_TLVS
+#define NLM_F_ACK_TLVS 0x200
+#endif
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
 #ifndef CONFIG_LIBNL20
 /*
  * libnl 1.1 has a bug, it tries to allocate socket numbers densely
@@ -130,7 +153,7 @@
 
 static void nl80211_register_eloop_read(struct nl_handle **handle,
 					eloop_sock_handler handler,
-					void *eloop_data)
+					void *eloop_data, int persist)
 {
 #ifdef CONFIG_LIBNL20
 	/*
@@ -151,13 +174,17 @@
 	nl_socket_set_nonblocking(*handle);
 	eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
 				 eloop_data, *handle);
-	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+	if (!persist)
+		*handle = (void *) (((intptr_t) *handle) ^
+				    ELOOP_SOCKET_INVALID);
 }
 
 
-static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist)
 {
-	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+	if (!persist)
+		*handle = (void *) (((intptr_t) *handle) ^
+				    ELOOP_SOCKET_INVALID);
 	eloop_unregister_read_sock(nl_socket_get_fd(*handle));
 	nl_destroy_handles(handle);
 }
@@ -298,8 +325,35 @@
 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
 			 void *arg)
 {
+	struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
+	int len = nlh->nlmsg_len;
+	struct nlattr *attrs;
+	struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
 	int *ret = arg;
+	int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
+
 	*ret = err->error;
+
+	if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+		return NL_SKIP;
+
+	if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+		ack_len += err->msg.nlmsg_len - sizeof(*nlh);
+
+	if (len <= ack_len)
+		return NL_STOP;
+
+	attrs = (void *) ((unsigned char *) nlh + ack_len);
+	len -= ack_len;
+
+	nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
+	if (tb[NLMSGERR_ATTR_MSG]) {
+		len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
+			      nla_len(tb[NLMSGERR_ATTR_MSG]));
+		wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
+			   len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
+	}
+
 	return NL_SKIP;
 }
 
@@ -338,7 +392,7 @@
 			 void *valid_data)
 {
 	struct nl_cb *cb;
-	int err = -ENOMEM;
+	int err = -ENOMEM, opt;
 
 	if (!msg)
 		return -ENOMEM;
@@ -347,6 +401,11 @@
 	if (!cb)
 		goto out;
 
+	/* try to set NETLINK_EXT_ACK to 1, ignoring errors */
+	opt = 1;
+	setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+		   NETLINK_EXT_ACK, &opt, sizeof(opt));
+
 	err = nl_send_auto_complete(nl_handle, msg);
 	if (err < 0)
 		goto out;
@@ -723,7 +782,7 @@
 		}
 
 		nl80211_register_eloop_read(&w->nl_beacons,
-					    nl80211_recv_beacons, w);
+					    nl80211_recv_beacons, w, 0);
 	}
 
 	dl_list_add(&nl80211_wiphys, &w->list);
@@ -772,7 +831,7 @@
 		return;
 
 	if (w->nl_beacons)
-		nl80211_destroy_eloop_handle(&w->nl_beacons);
+		nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
 
 	nl_cb_put(w->nl_cb);
 	dl_list_del(&w->list);
@@ -947,7 +1006,7 @@
 
 
 static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
-				int ifindex)
+				int ifindex, int notify)
 {
 	struct i802_bss *bss;
 	u8 addr[ETH_ALEN];
@@ -966,6 +1025,9 @@
 			   ifindex, bss->ifname,
 			   MAC2STR(bss->addr), MAC2STR(addr));
 		os_memcpy(bss->addr, addr, ETH_ALEN);
+		if (notify)
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_INTERFACE_MAC_CHANGED, NULL);
 	}
 }
 
@@ -1037,11 +1099,11 @@
 		namebuf[0] = '\0';
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
 		    linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
-			/* Re-read MAC address as it may have changed */
-			nl80211_refresh_mac(drv, ifi->ifi_index);
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
 				   "event since interface %s is up", namebuf);
 			drv->ignore_if_down_event = 0;
+			/* Re-read MAC address as it may have changed */
+			nl80211_refresh_mac(drv, ifi->ifi_index, 1);
 			return;
 		}
 		wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
@@ -1072,11 +1134,20 @@
 	}
 
 	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+		namebuf[0] = '\0';
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
 		    linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s is down",
 				   namebuf);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
+			   namebuf, ifname);
+		if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Not the main interface (%s) - do not indicate interface up",
+				   drv->first_bss->ifname);
 		} else if (if_nametoindex(drv->first_bss->ifname) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
 				   "event since interface %s does not exist",
@@ -1087,9 +1158,8 @@
 				   "removed", drv->first_bss->ifname);
 		} else {
 			/* Re-read MAC address as it may have changed */
-			nl80211_refresh_mac(drv, ifi->ifi_index);
+			nl80211_refresh_mac(drv, ifi->ifi_index, 0);
 
-			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
 			drv->if_disabled = 0;
 			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
 					     NULL);
@@ -1631,7 +1701,7 @@
 
 	nl80211_register_eloop_read(&global->nl_event,
 				    wpa_driver_nl80211_event_receive,
-				    global->nl_cb);
+				    global->nl_cb, 0);
 
 	return 0;
 
@@ -1997,7 +2067,7 @@
 {
 	nl80211_register_eloop_read(&bss->nl_mgmt,
 				    wpa_driver_nl80211_event_receive,
-				    bss->nl_cb);
+				    bss->nl_cb, 0);
 }
 
 
@@ -2010,6 +2080,25 @@
 }
 
 
+static int nl80211_init_connect_handle(struct i802_bss *bss)
+{
+	if (bss->nl_connect) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Connect handle already created (nl_connect=%p)",
+			   bss->nl_connect);
+		return -1;
+	}
+
+	bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
+	if (!bss->nl_connect)
+		return -1;
+	nl80211_register_eloop_read(&bss->nl_connect,
+				    wpa_driver_nl80211_event_receive,
+				    bss->nl_cb, 1);
+	return 0;
+}
+
+
 static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2020,7 +2109,9 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
 		   "handle %p", bss->nl_mgmt);
 
-	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+	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);
 
 		/* register for any AUTH message */
@@ -2109,6 +2200,11 @@
 	/* WNM-Sleep Mode Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
 		ret = -1;
+#ifdef CONFIG_WNM
+	/* WNM - Collocated Interference Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
+		ret = -1;
+#endif /* CONFIG_WNM */
 
 #ifdef CONFIG_HS20
 	/* WNM-Notification */
@@ -2311,7 +2407,7 @@
 		return;
 	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
 		   "(%s)", bss->nl_mgmt, reason);
-	nl80211_destroy_eloop_handle(&bss->nl_mgmt);
+	nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
 
 	nl80211_put_wiphy_data_ap(bss);
 }
@@ -2527,6 +2623,8 @@
 	if (drv->vendor_cmd_test_avail)
 		qca_vendor_test(drv);
 
+	nl80211_init_connect_handle(bss);
+
 	return 0;
 }
 
@@ -2573,9 +2671,11 @@
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "interface %s from bridge %s: %s",
 				   bss->ifname, bss->brname, strerror(errno));
-		if (drv->rtnl_sk)
-			nl80211_handle_destroy(drv->rtnl_sk);
 	}
+
+	if (drv->rtnl_sk)
+		nl80211_handle_destroy(drv->rtnl_sk);
+
 	if (bss->added_bridge) {
 		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
 					  0) < 0)
@@ -2640,6 +2740,9 @@
 		nl80211_del_p2pdev(bss);
 	}
 
+	if (bss->nl_connect)
+		nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
+
 	nl80211_destroy_bss(drv->first_bss);
 
 	os_free(drv->filter_ssids);
@@ -2782,6 +2885,44 @@
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
+static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
+			   const u8 *key, size_t key_len,
+			   const u8 *addr)
+{
+	struct nl_msg *msg = NULL;
+	int ret;
+
+	/*
+	 * If the authenticator address is not set, assume it is
+	 * the current BSSID.
+	 */
+	if (!addr && drv->associated)
+		addr = drv->bssid;
+	else if (!addr)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
+		   MAC2STR(addr));
+	wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
+	if (!msg ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+	    nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
+		nl80211_nlmsg_clear(msg);
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+	}
+
+	return ret;
+}
+
+
 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,
@@ -2820,6 +2961,10 @@
 	}
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
+	if (alg == WPA_ALG_PMK &&
+	    (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+		return nl80211_set_pmk(drv, key, key_len, addr);
+
 	if (alg == WPA_ALG_NONE) {
 		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
 		if (!msg)
@@ -3048,6 +3193,7 @@
 					 int reason_code)
 {
 	int ret;
+	int drv_associated = drv->associated;
 
 	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
 	nl80211_mark_disconnected(drv);
@@ -3058,7 +3204,7 @@
 	 * For locally generated disconnect, supplicant already generates a
 	 * DEAUTH event, so ignore the event from NL80211.
 	 */
-	drv->ignore_next_local_disconnect = ret == 0;
+	drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
 
 	return ret;
 }
@@ -3069,6 +3215,7 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret;
+	int drv_associated = drv->associated;
 
 	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
 		nl80211_mark_disconnected(drv);
@@ -3085,7 +3232,8 @@
 	 * For locally generated deauthenticate, supplicant already generates a
 	 * DEAUTH event, so ignore the event from NL80211.
 	 */
-	drv->ignore_next_local_deauth = ret == 0;
+	drv->ignore_next_local_deauth = drv_associated && (ret == 0);
+
 	return ret;
 }
 
@@ -3273,11 +3421,11 @@
 	msg = NULL;
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
-			"nl80211: MLME command failed (auth): ret=%d (%s)",
-			ret, strerror(-ret));
+			"nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
+			count, ret, strerror(-ret));
 		count++;
-		if (ret == -EALREADY && count == 1 && params->bssid &&
-		    !params->local_state_change) {
+		if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
+		    params->bssid && !params->local_state_change) {
 			/*
 			 * mac80211 does not currently accept new
 			 * authentication if we are already authenticated. As a
@@ -3957,7 +4105,7 @@
 			smps_mode = NL80211_SMPS_OFF;
 			break;
 		}
-		if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+		if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
 			goto fail;
 	}
 
@@ -5256,7 +5404,9 @@
 	    params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
-	    params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384) {
+	    params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
 		int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
 
 		switch (params->key_mgmt_suite) {
@@ -5299,6 +5449,12 @@
 		case WPA_KEY_MGMT_FT_FILS_SHA384:
 			mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
 			break;
+		case WPA_KEY_MGMT_OWE:
+			mgmt = RSN_AUTH_KEY_MGMT_OWE;
+			break;
+		case WPA_KEY_MGMT_DPP:
+			mgmt = RSN_AUTH_KEY_MGMT_DPP;
+			break;
 		case WPA_KEY_MGMT_PSK:
 		default:
 			mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
@@ -5309,6 +5465,14 @@
 			return -1;
 	}
 
+	/* Add PSK in case of 4-way handshake offload */
+	if (params->psk &&
+	    (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) {
+		wpa_hexdump_key(MSG_DEBUG, "  * PSK", params->psk, 32);
+		if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
+			return -1;
+	}
+
 	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
 		return -1;
 
@@ -5320,10 +5484,6 @@
 	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
 		return -1;
 
-	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
-	    nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
-		return -1;
-
 	if (params->rrm_used) {
 		u32 drv_rrm_flags = drv->capa.rrm_flags;
 		if ((!((drv_rrm_flags &
@@ -5360,13 +5520,19 @@
 	    nl80211_put_fils_connect_params(drv, params, msg) != 0)
 		return -1;
 
+	if ((params->auth_alg & WPA_AUTH_ALG_SAE) &&
+	    (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
+	    nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+		return -1;
+
 	return 0;
 }
 
 
 static int wpa_driver_nl80211_try_connect(
 	struct wpa_driver_nl80211_data *drv,
-	struct wpa_driver_associate_params *params)
+	struct wpa_driver_associate_params *params,
+	struct nl_handle *nl_connect)
 {
 	struct nl_msg *msg;
 	enum nl80211_auth_type type;
@@ -5394,6 +5560,15 @@
 	if (ret)
 		goto fail;
 
+	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+	    nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+		goto fail;
+
+	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
+	    (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
+	    nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
+		goto fail;
+
 	algs = 0;
 	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
 		algs++;
@@ -5403,6 +5578,8 @@
 		algs++;
 	if (params->auth_alg & WPA_AUTH_ALG_FILS)
 		algs++;
+	if (params->auth_alg & WPA_AUTH_ALG_FT)
+		algs++;
 	if (algs > 1) {
 		wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
 			   "selection");
@@ -5420,7 +5597,11 @@
 	if (ret)
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (nl_connect)
+		ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+	else
+		ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -5439,7 +5620,8 @@
 
 static int wpa_driver_nl80211_connect(
 	struct wpa_driver_nl80211_data *drv,
-	struct wpa_driver_associate_params *params)
+	struct wpa_driver_associate_params *params,
+	struct nl_handle *nl_connect)
 {
 	int ret;
 
@@ -5449,7 +5631,7 @@
 	else
 		os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
 
-	ret = wpa_driver_nl80211_try_connect(drv, params);
+	ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
 	if (ret == -EALREADY) {
 		/*
 		 * cfg80211 does not currently accept new connections if
@@ -5462,7 +5644,7 @@
 		if (wpa_driver_nl80211_disconnect(
 			    drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
 			return -1;
-		ret = wpa_driver_nl80211_try_connect(drv, params);
+		ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
 	}
 	return ret;
 }
@@ -5487,10 +5669,13 @@
 	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;
 
 		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 			return -1;
-		return wpa_driver_nl80211_connect(drv, params);
+		if (params->auth_alg & WPA_AUTH_ALG_SAE)
+			nl_connect = bss->nl_connect;
+		return wpa_driver_nl80211_connect(drv, params, nl_connect);
 	}
 
 	nl80211_mark_disconnected(drv);
@@ -5505,6 +5690,10 @@
 	if (ret)
 		goto fail;
 
+	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+	    nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+		goto fail;
+
 	if (params->fils_kek) {
 		wpa_printf(MSG_DEBUG, "  * FILS KEK (len=%u)",
 			   (unsigned int) params->fils_kek_len);
@@ -5938,6 +6127,7 @@
 		[NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
 		[NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
 		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+		[NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
 	};
 	struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
 	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -6000,6 +6190,11 @@
 			nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
 	if (stats[NL80211_STA_INFO_SIGNAL])
 		data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
+	if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
+		data->last_ack_rssi =
+			nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
+		data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
+	}
 
 	if (stats[NL80211_STA_INFO_TX_BITRATE] &&
 	    nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
@@ -6389,8 +6584,16 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	char name[IFNAMSIZ + 1];
+	union wpa_event_data event;
+	int ret;
 
-	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+	ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+	if (ret >= (int) sizeof(name))
+		wpa_printf(MSG_WARNING,
+			   "nl80211: WDS interface name was truncated");
+	else if (ret < 0)
+		return ret;
+
 	if (ifname_wds)
 		os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
 
@@ -6407,6 +6610,14 @@
 			    linux_br_add_if(drv->global->ioctl_sock,
 					    bridge_ifname, name) < 0)
 				return -1;
+
+			os_memset(&event, 0, sizeof(event));
+			event.wds_sta_interface.sta_addr = addr;
+			event.wds_sta_interface.ifname = name;
+			event.wds_sta_interface.istatus = INTERFACE_ADDED;
+			wpa_supplicant_event(bss->ctx,
+					     EVENT_WDS_STA_INTERFACE_STATUS,
+					     &event);
 		}
 		if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
@@ -6420,6 +6631,12 @@
 
 		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
 		nl80211_remove_iface(drv, if_nametoindex(name));
+		os_memset(&event, 0, sizeof(event));
+		event.wds_sta_interface.sta_addr = addr;
+		event.wds_sta_interface.ifname = name;
+		event.wds_sta_interface.istatus = INTERFACE_REMOVED;
+		wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
+				     &event);
 		return 0;
 	}
 }
@@ -6473,8 +6690,10 @@
 	bss->br_ifindex = br_ifindex;
 
 	if (linux_br_get(in_br, ifname) == 0) {
-		if (os_strcmp(in_br, brname) == 0)
+		if (os_strcmp(in_br, brname) == 0) {
+			bss->already_in_bridge = 1;
 			return 0; /* already in the bridge */
+		}
 
 		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
 			   "bridge %s", ifname, in_br);
@@ -6571,7 +6790,7 @@
 		add_ifidx(drv, br_ifindex, drv->ifindex);
 
 #ifdef CONFIG_LIBNL3_ROUTE
-	if (bss->added_if_into_bridge) {
+	if (bss->added_if_into_bridge || bss->already_in_bridge) {
 		drv->rtnl_sk = nl_socket_alloc();
 		if (drv->rtnl_sk == NULL) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
@@ -7200,7 +7419,7 @@
 		} else if (bss->nl_preq) {
 			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
 				   "reporting nl_preq=%p", bss->nl_preq);
-			nl80211_destroy_eloop_handle(&bss->nl_preq);
+			nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
 		}
 		return 0;
 	}
@@ -7225,7 +7444,7 @@
 
 	nl80211_register_eloop_read(&bss->nl_preq,
 				    wpa_driver_nl80211_event_receive,
-				    bss->nl_cb);
+				    bss->nl_cb, 0);
 
 	return 0;
 
@@ -7540,7 +7759,7 @@
 	nl_destroy_handles(&global->nl);
 
 	if (global->nl_event)
-		nl80211_destroy_eloop_handle(&global->nl_event);
+		nl80211_destroy_eloop_handle(&global->nl_event, 0);
 
 	nl_cb_put(global->nl_cb);
 
@@ -7563,6 +7782,7 @@
 			 struct wpa_pmkid_params *params)
 {
 	struct nl_msg *msg;
+	const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
 
 	if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
 	    (params->pmkid &&
@@ -7574,7 +7794,7 @@
 	    (params->fils_cache_id &&
 	     nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
 		     params->fils_cache_id)) ||
-	    (params->pmk_len &&
+	    (params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
 	     nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
@@ -7587,6 +7807,7 @@
 static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
 {
 	struct i802_bss *bss = priv;
+	int ret;
 
 	if (params->bssid)
 		wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
@@ -7598,13 +7819,21 @@
 			   wpa_ssid_txt(params->ssid, params->ssid_len));
 	}
 
-	return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+	ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
+			   ret, strerror(-ret));
+	}
+
+	return ret;
 }
 
 
 static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
 {
 	struct i802_bss *bss = priv;
+	int ret;
 
 	if (params->bssid)
 		wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
@@ -7616,7 +7845,14 @@
 			   wpa_ssid_txt(params->ssid, params->ssid_len));
 	}
 
-	return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+	ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
+			   ret, strerror(-ret));
+	}
+
+	return ret;
 }
 
 
@@ -7912,6 +8148,7 @@
 static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
 {
 	struct nl_msg *msg;
+	int ret;
 
 	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
 	    nla_put_u32(msg, NL80211_ATTR_PS_STATE,
@@ -7919,7 +8156,15 @@
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
-	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+
+	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Setting PS state %s failed: %d (%s)",
+			   enabled ? "enabled" : "disabled",
+			   ret, strerror(-ret));
+	}
+	return ret;
 }
 
 
@@ -8337,7 +8582,7 @@
 			  "brname=%s\n"
 			  "addr=" MACSTR "\n"
 			  "freq=%d\n"
-			  "%s%s%s%s%s",
+			  "%s%s%s%s%s%s",
 			  bss->ifindex,
 			  bss->ifname,
 			  bss->brname,
@@ -8346,6 +8591,7 @@
 			  bss->beacon_set ? "beacon_set=1\n" : "",
 			  bss->added_if_into_bridge ?
 			  "added_if_into_bridge=1\n" : "",
+			  bss->already_in_bridge ? "already_in_bridge=1\n" : "",
 			  bss->added_bridge ? "added_bridge=1\n" : "",
 			  bss->in_deinit ? "in_deinit=1\n" : "",
 			  bss->if_dynamic ? "if_dynamic=1\n" : "");
@@ -8521,8 +8767,9 @@
 		return -EOPNOTSUPP;
 	}
 
-	if ((drv->nlmode != NL80211_IFTYPE_AP) &&
-	    (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+	if (drv->nlmode != NL80211_IFTYPE_AP &&
+	    drv->nlmode != NL80211_IFTYPE_P2P_GO &&
+	    drv->nlmode != NL80211_IFTYPE_MESH_POINT)
 		return -EOPNOTSUPP;
 
 	/*
@@ -8885,6 +9132,34 @@
 }
 
 
+static int nl80211_disable_fils(void *priv, int disable)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nlattr *params;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
+
+	if (!drv->set_wifi_conf_vendor_cmd_avail)
+		return -1;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
+	    !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+	    nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
+		       disable)) {
+		nlmsg_free(msg);
+		return -1;
+	}
+	nla_nest_end(msg, params);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
 /* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
 #define WPA_SUPPLICANT_CLIENT_ID 1
 
@@ -9026,8 +9301,8 @@
 		return -1;
 
 	if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
-	     nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
-			 params->auto_plinks)) ||
+	     nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+			params->auto_plinks)) ||
 	    ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
 	     nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
 			 params->max_peer_links)) ||
@@ -10341,6 +10616,38 @@
 }
 
 
+static int nl80211_send_external_auth_status(void *priv,
+					     struct external_auth *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg = NULL;
+	int ret = -1;
+
+	wpa_dbg(drv->ctx, MSG_DEBUG,
+		"nl80211: External auth status: %u", params->status);
+
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
+	if (!msg ||
+	    nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
+	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+		    params->ssid) ||
+	    nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid))
+		goto fail;
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: External Auth status update failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto fail;
+	}
+fail:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -10450,6 +10757,7 @@
 	.get_ifindex = nl80211_get_ifindex,
 #ifdef CONFIG_DRIVER_NL80211_QCA
 	.roaming = nl80211_roaming,
+	.disable_fils = nl80211_disable_fils,
 	.do_acs = wpa_driver_do_acs,
 	.set_band = nl80211_set_band,
 	.get_pref_freq_list = nl80211_get_pref_freq_list,
@@ -10467,4 +10775,5 @@
 	.configure_data_frame_filters = nl80211_configure_data_frame_filters,
 	.get_ext_capab = nl80211_get_ext_capab,
 	.update_connect_params = nl80211_update_connection_params,
+	.send_external_auth_status = nl80211_send_external_auth_status,
 };
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 23cf9db..5ac0c7d 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -60,6 +60,7 @@
 	char brname[IFNAMSIZ];
 	unsigned int beacon_set:1;
 	unsigned int added_if_into_bridge:1;
+	unsigned int already_in_bridge:1;
 	unsigned int added_bridge:1;
 	unsigned int in_deinit:1;
 	unsigned int wdev_id_set:1;
@@ -73,7 +74,7 @@
 	int if_dynamic;
 
 	void *ctx;
-	struct nl_handle *nl_preq, *nl_mgmt;
+	struct nl_handle *nl_preq, *nl_mgmt, *nl_connect;
 	struct nl_cb *nl_cb;
 
 	struct nl80211_wiphy_data *wiphy_data;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index f11a1d7..7b360d2 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -401,6 +401,33 @@
 	if (ext_feature_isset(ext_features, len,
 			      NL80211_EXT_FEATURE_FILS_SK_OFFLOAD))
 		capa->flags |= WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK) &&
+	    ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+		capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_MFP_OPTIONAL))
+		capa->flags |= WPA_DRIVER_FLAGS_MFP_OPTIONAL;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_DFS_OFFLOAD))
+		capa->flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
+
+#ifdef CONFIG_MBO
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) &&
+	    ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) &&
+	    ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) &&
+	    ext_feature_isset(
+		    ext_features, len,
+		    NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
+		capa->flags |= WPA_DRIVER_FLAGS_OCE_STA;
+#endif /* CONFIG_MBO */
 }
 
 
@@ -791,6 +818,9 @@
 		capa->max_csa_counters =
 			nla_get_u8(tb[NL80211_ATTR_MAX_CSA_COUNTERS]);
 
+	if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG])
+		capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY;
+
 	return NL_SKIP;
 }
 
@@ -1205,7 +1235,8 @@
 		drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
 #ifdef CONFIG_DRIVER_NL80211_QCA
-	qca_nl80211_check_dfs_capa(drv);
+	if (!(info.capa->flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD))
+		qca_nl80211_check_dfs_capa(drv);
 	qca_nl80211_get_features(drv);
 	qca_nl80211_check_he_capab(drv);
 
@@ -1890,6 +1921,13 @@
 		return -ENOMEM;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY) {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx)) {
+			nlmsg_free(msg);
+			return -1;
+		}
+	}
+
 	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
 }
 
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index e6bc254..5b8efbc 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -131,6 +131,11 @@
 	C2S(NL80211_CMD_SET_QOS_MAP)
 	C2S(NL80211_CMD_ADD_TX_TS)
 	C2S(NL80211_CMD_DEL_TX_TS)
+	C2S(NL80211_CMD_WIPHY_REG_CHANGE)
+	C2S(NL80211_CMD_PORT_AUTHORIZED)
+	C2S(NL80211_CMD_EXTERNAL_AUTH)
+	C2S(NL80211_CMD_STA_OPMODE_CHANGED)
+	C2S(NL80211_CMD_CONTROL_PORT_FRAME)
 	default:
 		return "NL80211_CMD_UNKNOWN";
 	}
@@ -673,7 +678,7 @@
 
 		cookie_val = nla_get_u64(cookie);
 		wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
-			   " cookie=0%llx%s (ack=%d)",
+			   " cookie=0x%llx%s (ack=%d)",
 			   (long long unsigned int) cookie_val,
 			   cookie_val == drv->send_action_cookie ?
 			   " (match)" : " (unknown)", ack != NULL);
@@ -1590,6 +1595,9 @@
 		wpa_supplicant_event(drv->ctx, EVENT_DFS_PRE_CAC_EXPIRED,
 				     &data);
 		break;
+	case NL80211_RADAR_CAC_STARTED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
 			   "received", event_type);
@@ -2175,6 +2183,146 @@
 }
 
 
+static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv,
+				  struct nlattr **tb)
+{
+	union wpa_event_data event;
+	enum nl80211_external_auth_action act;
+
+	if (!tb[NL80211_ATTR_AKM_SUITES] ||
+	    !tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] ||
+	    !tb[NL80211_ATTR_BSSID] ||
+	    !tb[NL80211_ATTR_SSID])
+		return;
+
+	os_memset(&event, 0, sizeof(event));
+	act = nla_get_u32(tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION]);
+	switch (act) {
+	case NL80211_EXTERNAL_AUTH_START:
+		event.external_auth.action = EXT_AUTH_START;
+		break;
+	case NL80211_EXTERNAL_AUTH_ABORT:
+		event.external_auth.action = EXT_AUTH_ABORT;
+		break;
+	default:
+		return;
+	}
+
+	event.external_auth.key_mgmt_suite =
+		nla_get_u32(tb[NL80211_ATTR_AKM_SUITES]);
+
+	event.external_auth.ssid_len = nla_len(tb[NL80211_ATTR_SSID]);
+	if (event.external_auth.ssid_len > SSID_MAX_LEN)
+		return;
+	os_memcpy(event.external_auth.ssid, nla_data(tb[NL80211_ATTR_SSID]),
+		  event.external_auth.ssid_len);
+
+	os_memcpy(event.external_auth.bssid, nla_data(tb[NL80211_ATTR_BSSID]),
+		  ETH_ALEN);
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: External auth action: %u, AKM: 0x%x",
+		   event.external_auth.action,
+		   event.external_auth.key_mgmt_suite);
+	wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event);
+}
+
+
+static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv,
+				    struct nlattr **tb)
+{
+	const u8 *addr;
+
+	if (!tb[NL80211_ATTR_MAC] ||
+	    nla_len(tb[NL80211_ATTR_MAC]) != ETH_ALEN) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignore port authorized event without BSSID");
+		return;
+	}
+
+	addr = nla_data(tb[NL80211_ATTR_MAC]);
+	if (os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignore port authorized event for " MACSTR
+			   " (not the currently connected BSSID " MACSTR ")",
+			   MAC2STR(addr), MAC2STR(drv->bssid));
+		return;
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_PORT_AUTHORIZED, NULL);
+}
+
+
+static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv,
+					    struct nlattr **tb)
+{
+	union wpa_event_data ed;
+	u8 smps_mode, max_bw;
+
+	if (!tb[NL80211_ATTR_MAC] ||
+	    (!tb[NL80211_ATTR_CHANNEL_WIDTH] &&
+	     !tb[NL80211_ATTR_SMPS_MODE] &&
+	     !tb[NL80211_ATTR_NSS]))
+		return;
+
+	ed.sta_opmode.smps_mode = SMPS_INVALID;
+	ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+	ed.sta_opmode.rx_nss = 0xff;
+	ed.sta_opmode.addr = nla_data(tb[NL80211_ATTR_MAC]);
+
+	if (tb[NL80211_ATTR_SMPS_MODE]) {
+		smps_mode = nla_get_u32(tb[NL80211_ATTR_SMPS_MODE]);
+		switch (smps_mode) {
+		case NL80211_SMPS_OFF:
+			ed.sta_opmode.smps_mode = SMPS_OFF;
+			break;
+		case NL80211_SMPS_STATIC:
+			ed.sta_opmode.smps_mode = SMPS_STATIC;
+			break;
+		case NL80211_SMPS_DYNAMIC:
+			ed.sta_opmode.smps_mode = SMPS_DYNAMIC;
+			break;
+		default:
+			ed.sta_opmode.smps_mode = SMPS_INVALID;
+			break;
+		}
+	}
+
+	if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+		max_bw = nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]);
+		switch (max_bw) {
+		case NL80211_CHAN_WIDTH_20_NOHT:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_20_NOHT;
+			break;
+		case NL80211_CHAN_WIDTH_20:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_20;
+			break;
+		case NL80211_CHAN_WIDTH_40:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_40;
+			break;
+		case NL80211_CHAN_WIDTH_80:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_80;
+			break;
+		case NL80211_CHAN_WIDTH_80P80:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_80P80;
+			break;
+		case NL80211_CHAN_WIDTH_160:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_160;
+			break;
+		default:
+			ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+			break;
+
+		}
+	}
+
+	if (tb[NL80211_ATTR_NSS])
+		ed.sta_opmode.rx_nss = nla_get_u8(tb[NL80211_ATTR_NSS]);
+
+	wpa_supplicant_event(drv->ctx, EVENT_STATION_OPMODE_CHANGED, &ed);
+}
+
+
 static void do_process_drv_event(struct i802_bss *bss, int cmd,
 				 struct nlattr **tb)
 {
@@ -2328,6 +2476,7 @@
 		nl80211_cqm_event(drv, tb);
 		break;
 	case NL80211_CMD_REG_CHANGE:
+	case NL80211_CMD_WIPHY_REG_CHANGE:
 		nl80211_reg_change_event(drv, tb);
 		break;
 	case NL80211_CMD_REG_BEACON_HINT:
@@ -2373,6 +2522,12 @@
 	case NL80211_CMD_NEW_PEER_CANDIDATE:
 		nl80211_new_peer_candidate(drv, tb);
 		break;
+	case NL80211_CMD_PORT_AUTHORIZED:
+		nl80211_port_authorized(drv, tb);
+		break;
+	case NL80211_CMD_STA_OPMODE_CHANGED:
+		nl80211_sta_opmode_change_event(drv, tb);
+		break;
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);
@@ -2387,10 +2542,11 @@
 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
 	struct wpa_driver_nl80211_data *drv, *tmp;
-	int ifidx = -1;
+	int ifidx = -1, wiphy_idx = -1, wiphy_idx_rx = -1;
 	struct i802_bss *bss;
 	u64 wdev_id = 0;
 	int wdev_id_set = 0;
+	int wiphy_idx_set = 0;
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
@@ -2400,13 +2556,19 @@
 	else if (tb[NL80211_ATTR_WDEV]) {
 		wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
 		wdev_id_set = 1;
+	} else if (tb[NL80211_ATTR_WIPHY]) {
+		wiphy_idx_rx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+		wiphy_idx_set = 1;
 	}
 
 	dl_list_for_each_safe(drv, tmp, &global->interfaces,
 			      struct wpa_driver_nl80211_data, list) {
 		for (bss = drv->first_bss; bss; bss = bss->next) {
-			if ((ifidx == -1 && !wdev_id_set) ||
+			if (wiphy_idx_set)
+				wiphy_idx = nl80211_get_wiphy_index(bss);
+			if ((ifidx == -1 && !wiphy_idx_set && !wdev_id_set) ||
 			    ifidx == bss->ifindex ||
+			    (wiphy_idx_set && wiphy_idx == wiphy_idx_rx) ||
 			    (wdev_id_set && bss->wdev_id_set &&
 			     wdev_id == bss->wdev_id)) {
 				do_process_drv_event(bss, gnlh->cmd, tb);
@@ -2451,6 +2613,9 @@
 	case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
 		nl80211_spurious_frame(bss, tb, 1);
 		break;
+	case NL80211_CMD_EXTERNAL_AUTH:
+		nl80211_external_auth(bss->drv, tb);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
 			   "(cmd=%d)", gnlh->cmd);
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
index 9376d11..f25cd79 100644
--- a/src/drivers/driver_nl80211_monitor.c
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -361,8 +361,17 @@
 		 */
 		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
 	} else {
+		int ret;
+
 		/* Non-P2P interface with AP functionality. */
-		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
+		ret = os_snprintf(buf, IFNAMSIZ, "mon.%s",
+				  drv->first_bss->ifname);
+		if (ret >= (int) sizeof(buf))
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Monitor interface name has been truncated to %s",
+				   buf);
+		else if (ret < 0)
+			return ret;
 	}
 
 	buf[IFNAMSIZ - 1] = '\0';
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 984485b..86501f4 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -282,6 +282,21 @@
 			goto fail;
 	}
 
+	if (params->oce_scan) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Add NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME");
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Add NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP");
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_MIN_TX_RATE");
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION");
+		scan_flags |= NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME |
+			NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP |
+			NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE |
+			NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION;
+	}
+
 	if (scan_flags &&
 	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
 		goto fail;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 659eda2..933b8d9 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -922,7 +922,7 @@
 
 static void wext_check_hostap(struct wpa_driver_wext_data *drv)
 {
-	char buf[200], *pos;
+	char path[200], buf[200], *pos;
 	ssize_t res;
 
 	/*
@@ -937,9 +937,9 @@
 	 */
 
 	/* First, try to see if driver information is available from sysfs */
-	snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
+	snprintf(path, sizeof(path), "/sys/class/net/%s/device/driver",
 		 drv->ifname);
-	res = readlink(buf, buf, sizeof(buf) - 1);
+	res = readlink(path, buf, sizeof(buf) - 1);
 	if (res > 0) {
 		buf[res] = '\0';
 		pos = strrchr(buf, '/');
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 6095a6c..1766a12 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,6 +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 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
@@ -173,6 +174,29 @@
  */
 
 /**
+ * DOC: WPA/WPA2 EAPOL handshake offload
+ *
+ * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag drivers
+ * can indicate they support offloading EAPOL handshakes for WPA/WPA2
+ * preshared key authentication. In %NL80211_CMD_CONNECT the preshared
+ * key should be specified using %NL80211_ATTR_PMK. Drivers supporting
+ * this offload may reject the %NL80211_CMD_CONNECT when no preshared
+ * key material is provided, for example when that driver does not
+ * support setting the temporal keys through %CMD_NEW_KEY.
+ *
+ * Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be
+ * set by drivers indicating offload support of the PTK/GTK EAPOL
+ * handshakes during 802.1X authentication. In order to use the offload
+ * the %NL80211_CMD_CONNECT should have %NL80211_ATTR_WANT_1X_4WAY_HS
+ * attribute flag. Drivers supporting this offload may reject the
+ * %NL80211_CMD_CONNECT when the attribute flag is not present.
+ *
+ * For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK
+ * using %NL80211_CMD_SET_PMK. For offloaded FT support also
+ * %NL80211_ATTR_PMKR0_NAME must be provided.
+ */
+
+/**
  * DOC: FILS shared key authentication offload
  *
  * FILS shared key authentication offload can be advertized by drivers by
@@ -180,7 +204,8 @@
  * FILS shared key authentication offload should be able to construct the
  * authentication and association frames for FILS shared key authentication and
  * eventually do a key derivation as per IEEE 802.11ai. The below additional
- * parameters should be given to driver in %NL80211_CMD_CONNECT.
+ * parameters should be given to driver in %NL80211_CMD_CONNECT and/or in
+ * %NL80211_CMD_UPDATE_CONNECT_PARAMS.
  *	%NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai
  *	%NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai
  *	%NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message
@@ -191,7 +216,8 @@
  * as specified in IETF RFC 6696.
  *
  * When FILS shared key authentication is completed, driver needs to provide the
- * below additional parameters to userspace.
+ * below additional parameters to userspace, which can be either after setting
+ * up a connection or after roaming.
  *	%NL80211_ATTR_FILS_KEK - used for key renewal
  *	%NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges
  *	%NL80211_ATTR_PMKID - used to identify the PMKSA used/generated
@@ -387,7 +413,9 @@
  *	are used.  Extra IEs can also be passed from the userspace by
  *	using the %NL80211_ATTR_IE attribute.  The first cycle of the
  *	scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY
- *	is supplied.
+ *	is supplied. If the device supports multiple concurrent scheduled
+ *	scans, it will allow such when the caller provides the flag attribute
+ *	%NL80211_ATTR_SCHED_SCAN_MULTI to indicate user-space support for it.
  * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if
  *	scheduled scan is not running. The caller may assume that as soon
  *	as the call returns, it is safe to start a new scheduled scan again.
@@ -517,7 +545,8 @@
  *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
  *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
  *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
- *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+ *	%NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
  *	%NL80211_ATTR_WIPHY_FREQ_HINT.
  *	If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
  *	restrictions on BSS selection, i.e., they effectively prevent roaming
@@ -544,8 +573,14 @@
  *	authentication/association or not receiving a response from the AP.
  *	Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
  *	well to remain backwards compatible.
- * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
- *	sent as an event when the card/driver roamed by itself.
+ *	When establishing a security association, drivers that support 4 way
+ *	handshake offload should send %NL80211_CMD_PORT_AUTHORIZED event when
+ *	the 4 way handshake is completed successfully.
+ * @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself.
+ *	When a security association was established with the new AP (e.g. if
+ *	the FT protocol was used for roaming or the driver completed the 4 way
+ *	handshake), this event should be followed by an
+ *	%NL80211_CMD_PORT_AUTHORIZED event.
  * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
  *	userspace that a connection was dropped by the AP or due to other
  *	reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
@@ -945,6 +980,59 @@
  *	does not result in a change for the current association. Currently,
  *	only the %NL80211_ATTR_IE data is used and updated with this command.
  *
+ * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
+ *	for the given authenticator address (specified with %NL80211_ATTR_MAC).
+ *	When %NL80211_ATTR_PMKR0_NAME is set, %NL80211_ATTR_PMK specifies the
+ *	PMK-R0, otherwise it specifies the PMK.
+ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
+ *	configured PMK for the authenticator address identified by
+ *	%NL80211_ATTR_MAC.
+ * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
+ *	handshake was completed successfully by the driver. The BSSID is
+ *	specified with %NL80211_ATTR_MAC. Drivers that support 4 way handshake
+ *	offload should send this event after indicating 802.11 association with
+ *	%NL80211_CMD_CONNECT or %NL80211_CMD_ROAM. If the 4 way handshake failed
+ *	%NL80211_CMD_DISCONNECT should be indicated instead.
+ *
+ * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
+ *	and RX notification.  This command is used both as a request to transmit
+ *	a control port frame and as a notification that a control port frame
+ *	has been received. %NL80211_ATTR_FRAME is used to specify the
+ *	frame contents.  The frame is the raw EAPoL data, without ethernet or
+ *	802.11 headers.
+ *	When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
+ *	indicating the protocol type of the received frame; whether the frame
+ *	was received unencrypted and the MAC address of the peer respectively.
+ *
+ * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
+ *
+ * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
+ *	drivers that do not define separate commands for authentication and
+ *	association, but rely on user space for the authentication to happen.
+ *	This interface acts both as the event request (driver to user space)
+ *	to trigger the authentication and command response (userspace to
+ *	driver) to indicate the authentication status.
+ *
+ *	User space uses the %NL80211_CMD_CONNECT command to the host driver to
+ *	trigger a connection. The host driver selects a BSS and further uses
+ *	this interface to offload only the authentication part to the user
+ *	space. Authentication frames are passed between the driver and user
+ *	space through the %NL80211_CMD_FRAME interface. Host driver proceeds
+ *	further with the association after getting successful authentication
+ *	status. User space indicates the authentication status through
+ *	%NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH
+ *	command interface.
+ *
+ *	Host driver reports this status on an authentication failure to the
+ *	user space through the connect result as the user space would have
+ *	initiated the connection through the connect request.
+ *
+ * @NL80211_CMD_STA_OPMODE_CHANGED: An event that notify station's
+ *	ht opmode or vht opmode changes using any of %NL80211_ATTR_SMPS_MODE,
+ *	%NL80211_ATTR_CHANNEL_WIDTH,%NL80211_ATTR_NSS attributes with its
+ *	address(specified in %NL80211_ATTR_MAC).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1144,6 +1232,19 @@
 
 	NL80211_CMD_UPDATE_CONNECT_PARAMS,
 
+	NL80211_CMD_SET_PMK,
+	NL80211_CMD_DEL_PMK,
+
+	NL80211_CMD_PORT_AUTHORIZED,
+
+	NL80211_CMD_RELOAD_REGDB,
+
+	NL80211_CMD_EXTERNAL_AUTH,
+
+	NL80211_CMD_STA_OPMODE_CHANGED,
+
+	NL80211_CMD_CONTROL_PORT_FRAME,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1366,8 +1467,12 @@
  *
  * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
  *	used for the association (&enum nl80211_mfp, represented as a u32);
- *	this attribute can be used
- *	with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
+ *	this attribute can be used with %NL80211_CMD_ASSOCIATE and
+ *	%NL80211_CMD_CONNECT requests. %NL80211_MFP_OPTIONAL is not allowed for
+ *	%NL80211_CMD_ASSOCIATE since user space SME is expected and hence, it
+ *	must have decided whether to use management frame protection or not.
+ *	Setting %NL80211_MFP_OPTIONAL with a %NL80211_CMD_CONNECT request will
+ *	let the driver (or the firmware) decide whether to use MFP or not.
  *
  * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
  *	&struct nl80211_sta_flag_update.
@@ -1387,6 +1492,15 @@
  * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
  *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
  *	ethertype frames used for key negotiation must not be encrypted.
+ * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control
+ *	port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+ *	will be sent directly to the network interface or sent via the NL80211
+ *	socket.  If this attribute is missing, then legacy behavior of sending
+ *	control port frames directly to the network interface is used.  If the
+ *	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.
  *
  * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
  *	We recommend using nested, driver-specific attributes within this.
@@ -1868,13 +1982,18 @@
  *	that configured the indoor setting, and the indoor operation would be
  *	cleared when the socket is closed.
  *	If set during NAN interface creation, the interface will be destroyed
- *	if the socket is closed just like any other interface. Moreover, only
- *	the netlink socket that created the interface will be allowed to add
- *	and remove functions. NAN notifications will be sent in unicast to that
- *	socket. Without this attribute, any socket can add functions and the
- *	notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
+ *	if the socket is closed just like any other interface. Moreover, NAN
+ *	notifications will be sent in unicast to that socket. Without this
+ *	attribute, the notifications will be sent to the %NL80211_MCGRP_NAN
+ *	multicast group.
  *	If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
  *	station will deauthenticate when the socket is closed.
+ *	If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically
+ *	torn down when the socket is closed.
+ *	If set during %NL80211_CMD_JOIN_MESH the mesh setup will be
+ *	automatically torn down when the socket is closed.
+ *	If set during %NL80211_CMD_START_AP the AP will be automatically
+ *	disabled when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
@@ -2078,8 +2197,49 @@
  *	identifying the scope of PMKSAs. This is used with
  *	@NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
  *
- * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
- *	This is used with @NL80211_CMD_SET_PMKSA.
+ * @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with
+ *	%NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID.
+ *	For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way
+ *	handshake for WPA/WPA2-PSK networks. For 802.1X authentication it is
+ *	used with %NL80211_CMD_SET_PMK. For offloaded FT support this attribute
+ *	specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME is included as well.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
+ *	indicate that it supports multiple active scheduled scan requests.
+ * @NL80211_ATTR_SCHED_SCAN_MAX_REQS: indicates maximum number of scheduled
+ *	scan request that may be active for the device (u32).
+ *
+ * @NL80211_ATTR_WANT_1X_4WAY_HS: flag attribute which user-space can include
+ *	in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it
+ *	wants to use the supported offload of the 4-way handshake.
+ * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
+ * @NL80211_ATTR_PORT_AUTHORIZED: (reserved)
+ *
+ * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
+ *     authentication operation (u32 attribute with an
+ *     &enum nl80211_external_auth_action value). This is used with the
+ *     %NL80211_CMD_EXTERNAL_AUTH request event.
+ * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
+ *     space supports external authentication. This attribute shall be used
+ *     only with %NL80211_CMD_CONNECT request. The driver may offload
+ *     authentication processing to user space if this capability is indicated
+ *     in NL80211_CMD_CONNECT requests from the user space.
+ *
+ * @NL80211_ATTR_NSS: Station's New/updated  RX_NSS value notified using this
+ *	u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
+ *
+ * @NL80211_ATTR_TXQ_STATS: TXQ statistics (nested attribute, see &enum
+ *      nl80211_txq_stats)
+ * @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy.
+ *      The smaller of this and the memory limit is enforced.
+ * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the
+ *      TXQ queues for this phy. The smaller of this and the packet limit is
+ *      enforced.
+ * @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
+ *      a flow is assigned on each round of the DRR scheduler.
+ * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from
+ *	association request when used with NL80211_CMD_NEW_STATION). Can be set
+ *	only if %NL80211_STA_FLAG_WME is set.
  *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2500,6 +2660,28 @@
 
 	NL80211_ATTR_PMK,
 
+	NL80211_ATTR_SCHED_SCAN_MULTI,
+	NL80211_ATTR_SCHED_SCAN_MAX_REQS,
+
+	NL80211_ATTR_WANT_1X_4WAY_HS,
+	NL80211_ATTR_PMKR0_NAME,
+	NL80211_ATTR_PORT_AUTHORIZED,
+
+	NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+	NL80211_ATTR_EXTERNAL_AUTH_SUPPORT,
+
+	NL80211_ATTR_NSS,
+	NL80211_ATTR_ACK_SIGNAL,
+
+	NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
+
+	NL80211_ATTR_TXQ_STATS,
+	NL80211_ATTR_TXQ_LIMIT,
+	NL80211_ATTR_TXQ_MEMORY_LIMIT,
+	NL80211_ATTR_TXQ_QUANTUM,
+
+	NL80211_ATTR_HE_CAPABILITY,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2539,6 +2721,8 @@
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
 #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
+#define NL80211_WIPHY_NAME_MAXLEN		64
+
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_HT_RATES		77
 #define NL80211_MAX_SUPP_REG_RULES		64
@@ -2547,7 +2731,8 @@
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY	24
 #define NL80211_HT_CAPABILITY_LEN		26
 #define NL80211_VHT_CAPABILITY_LEN		12
-
+#define NL80211_HE_MIN_CAPABILITY_LEN           16
+#define NL80211_HE_MAX_CAPABILITY_LEN           51
 #define NL80211_MAX_NR_CIPHER_SUITES		5
 #define NL80211_MAX_NR_AKM_SUITES		2
 
@@ -2675,6 +2860,38 @@
 } __attribute__((packed));
 
 /**
+ * enum nl80211_he_gi - HE guard interval
+ * @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec
+ */
+enum nl80211_he_gi {
+	NL80211_RATE_INFO_HE_GI_0_8,
+	NL80211_RATE_INFO_HE_GI_1_6,
+	NL80211_RATE_INFO_HE_GI_3_2,
+};
+
+/**
+ * enum nl80211_he_ru_alloc - HE RU allocation values
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_996: 996-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_2x996: 2x996-tone RU allocation
+ */
+enum nl80211_he_ru_alloc {
+	NL80211_RATE_INFO_HE_RU_ALLOC_26,
+	NL80211_RATE_INFO_HE_RU_ALLOC_52,
+	NL80211_RATE_INFO_HE_RU_ALLOC_106,
+	NL80211_RATE_INFO_HE_RU_ALLOC_242,
+	NL80211_RATE_INFO_HE_RU_ALLOC_484,
+	NL80211_RATE_INFO_HE_RU_ALLOC_996,
+	NL80211_RATE_INFO_HE_RU_ALLOC_2x996,
+};
+
+/**
  * enum nl80211_rate_info - bitrate information
  *
  * These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -2706,6 +2923,13 @@
  * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
  *	a legacy rate and will be reported as the actual bitrate, i.e.
  *	a quarter of the base (20 MHz) rate
+ * @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11)
+ * @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_HE_GI: HE guard interval identifier
+ *	(u8, see &enum nl80211_he_gi)
+ * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
+ * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
+ *	non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -2722,6 +2946,11 @@
 	NL80211_RATE_INFO_160_MHZ_WIDTH,
 	NL80211_RATE_INFO_10_MHZ_WIDTH,
 	NL80211_RATE_INFO_5_MHZ_WIDTH,
+	NL80211_RATE_INFO_HE_MCS,
+	NL80211_RATE_INFO_HE_NSS,
+	NL80211_RATE_INFO_HE_GI,
+	NL80211_RATE_INFO_HE_DCM,
+	NL80211_RATE_INFO_HE_RU_ALLOC,
 
 	/* keep last */
 	__NL80211_RATE_INFO_AFTER_LAST,
@@ -2820,6 +3049,8 @@
  * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
  *	received from the station (u64, usec)
  * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
+ * @NL80211_STA_INFO_ACK_SIGNAL_AVG: avg signal strength of ACK frames (s8, dBm)
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -2858,12 +3089,18 @@
 	NL80211_STA_INFO_TID_STATS,
 	NL80211_STA_INFO_RX_DURATION,
 	NL80211_STA_INFO_PAD,
+	NL80211_STA_INFO_ACK_SIGNAL,
+	NL80211_STA_INFO_ACK_SIGNAL_AVG,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
 	NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
 };
 
+/* we renamed this - stay compatible */
+#define NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG NL80211_STA_INFO_ACK_SIGNAL_AVG
+
+
 /**
  * enum nl80211_tid_stats - per TID statistics attributes
  * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved
@@ -2875,6 +3112,7 @@
  * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
  *	MSDUs (u64)
  * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_TID_STATS_TXQ_STATS: TXQ stats (nested attribute)
  * @NUM_NL80211_TID_STATS: number of attributes here
  * @NL80211_TID_STATS_MAX: highest numbered attribute here
  */
@@ -2885,6 +3123,7 @@
 	NL80211_TID_STATS_TX_MSDU_RETRIES,
 	NL80211_TID_STATS_TX_MSDU_FAILED,
 	NL80211_TID_STATS_PAD,
+	NL80211_TID_STATS_TXQ_STATS,
 
 	/* keep last */
 	NUM_NL80211_TID_STATS,
@@ -2892,6 +3131,44 @@
 };
 
 /**
+ * enum nl80211_txq_stats - per TXQ statistics attributes
+ * @__NL80211_TXQ_STATS_INVALID: attribute number 0 is reserved
+ * @NUM_NL80211_TXQ_STATS: number of attributes here
+ * @NL80211_TXQ_STATS_BACKLOG_BYTES: number of bytes currently backlogged
+ * @NL80211_TXQ_STATS_BACKLOG_PACKETS: number of packets currently
+ *      backlogged
+ * @NL80211_TXQ_STATS_FLOWS: total number of new flows seen
+ * @NL80211_TXQ_STATS_DROPS: total number of packet drops
+ * @NL80211_TXQ_STATS_ECN_MARKS: total number of packet ECN marks
+ * @NL80211_TXQ_STATS_OVERLIMIT: number of drops due to queue space overflow
+ * @NL80211_TXQ_STATS_OVERMEMORY: number of drops due to memory limit overflow
+ *      (only for per-phy stats)
+ * @NL80211_TXQ_STATS_COLLISIONS: number of hash collisions
+ * @NL80211_TXQ_STATS_TX_BYTES: total number of bytes dequeued from TXQ
+ * @NL80211_TXQ_STATS_TX_PACKETS: total number of packets dequeued from TXQ
+ * @NL80211_TXQ_STATS_MAX_FLOWS: number of flow buckets for PHY
+ * @NL80211_TXQ_STATS_MAX: highest numbered attribute here
+ */
+enum nl80211_txq_stats {
+	__NL80211_TXQ_STATS_INVALID,
+	NL80211_TXQ_STATS_BACKLOG_BYTES,
+	NL80211_TXQ_STATS_BACKLOG_PACKETS,
+	NL80211_TXQ_STATS_FLOWS,
+	NL80211_TXQ_STATS_DROPS,
+	NL80211_TXQ_STATS_ECN_MARKS,
+	NL80211_TXQ_STATS_OVERLIMIT,
+	NL80211_TXQ_STATS_OVERMEMORY,
+	NL80211_TXQ_STATS_COLLISIONS,
+	NL80211_TXQ_STATS_TX_BYTES,
+	NL80211_TXQ_STATS_TX_PACKETS,
+	NL80211_TXQ_STATS_MAX_FLOWS,
+
+	/* keep last */
+	NUM_NL80211_TXQ_STATS,
+	NL80211_TXQ_STATS_MAX = NUM_NL80211_TXQ_STATS - 1
+};
+
+/**
  * enum nl80211_mpath_flags - nl80211 mesh path flags
  *
  * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
@@ -2943,6 +3220,38 @@
 };
 
 /**
+ * enum nl80211_band_iftype_attr - Interface type data attributes
+ *
+ * @__NL80211_BAND_IFTYPE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_IFTYPE_ATTR_IFTYPES: nested attribute containing a flag attribute
+ *     for each interface type that supports the band data
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE
+ *     capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE
+ *     capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE
+ *     capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as
+ *     defined in HE capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
+ *     defined
+ * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_band_iftype_attr {
+	__NL80211_BAND_IFTYPE_ATTR_INVALID,
+
+	NL80211_BAND_IFTYPE_ATTR_IFTYPES,
+	NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
+	NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
+	NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
+	NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+
+	/* keep last */
+	__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
+	NL80211_BAND_IFTYPE_ATTR_MAX = __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_band_attr - band attributes
  * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
@@ -2957,6 +3266,8 @@
  * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
  *	defined in 802.11ac
  * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
+ *	attributes from &enum nl80211_band_iftype_attr
  * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
  * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
  */
@@ -2972,6 +3283,7 @@
 
 	NL80211_BAND_ATTR_VHT_MCS_SET,
 	NL80211_BAND_ATTR_VHT_CAPA,
+	NL80211_BAND_ATTR_IFTYPE_DATA,
 
 	/* keep last */
 	__NL80211_BAND_ATTR_AFTER_LAST,
@@ -2981,6 +3293,29 @@
 #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
 
 /**
+ * enum nl80211_wmm_rule - regulatory wmm rule
+ *
+ * @__NL80211_WMMR_INVALID: attribute number 0 is reserved
+ * @NL80211_WMMR_CW_MIN: Minimum contention window slot.
+ * @NL80211_WMMR_CW_MAX: Maximum contention window slot.
+ * @NL80211_WMMR_AIFSN: Arbitration Inter Frame Space.
+ * @NL80211_WMMR_TXOP: Maximum allowed tx operation time.
+ * @nl80211_WMMR_MAX: highest possible wmm rule.
+ * @__NL80211_WMMR_LAST: Internal use.
+ */
+enum nl80211_wmm_rule {
+	__NL80211_WMMR_INVALID,
+	NL80211_WMMR_CW_MIN,
+	NL80211_WMMR_CW_MAX,
+	NL80211_WMMR_AIFSN,
+	NL80211_WMMR_TXOP,
+
+	/* keep last */
+	__NL80211_WMMR_LAST,
+	NL80211_WMMR_MAX = __NL80211_WMMR_LAST - 1
+};
+
+/**
  * enum nl80211_frequency_attr - frequency attributes
  * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
@@ -3029,6 +3364,9 @@
  *	on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
  *	on this channel in current regulatory domain.
+ * @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_MAX: highest frequency attribute number
  *	currently defined
  * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3057,6 +3395,7 @@
 	NL80211_FREQUENCY_ATTR_IR_CONCURRENT,
 	NL80211_FREQUENCY_ATTR_NO_20MHZ,
 	NL80211_FREQUENCY_ATTR_NO_10MHZ,
+	NL80211_FREQUENCY_ATTR_WMM,
 
 	/* keep last */
 	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3184,6 +3523,7 @@
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
  *	only report BSS with matching SSID.
+ *	(This cannot be used together with BSSID.)
  * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
  *	BSS in scan results. Filtering is turned off if not specified. Note that
  *	if this attribute is in a match set of its own, then it is treated as
@@ -3199,6 +3539,8 @@
  *	BSS-es in the specified band is to be adjusted before doing
  *	RSSI-based BSS selection. The attribute value is a packed structure
  *	value as specified by &struct nl80211_bss_select_rssi_adjust.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching
+ *	(this cannot be used together with SSID).
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *	attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3210,6 +3552,7 @@
 	NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 	NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
 	NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
+	NL80211_SCHED_SCAN_MATCH_ATTR_BSSID,
 
 	/* keep last */
 	__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -3236,7 +3579,7 @@
  * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
  *	base on contiguous rules and wider channels will be allowed to cross
  *	multiple contiguous/overlapping frequency ranges.
- * @NL80211_RRF_IR_CONCURRENT: See &NL80211_FREQUENCY_ATTR_IR_CONCURRENT
+ * @NL80211_RRF_IR_CONCURRENT: See %NL80211_FREQUENCY_ATTR_IR_CONCURRENT
  * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
  * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
  * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
@@ -3779,6 +4122,9 @@
  *	@NL80211_BSS_PARENT_BSSID. (u64).
  * @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
  *	is set.
+ * @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update.
+ *	Contains a nested array of signal strength attributes (u8, dBm),
+ *	using the nesting index as the antenna number.
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -3802,6 +4148,7 @@
 	NL80211_BSS_PAD,
 	NL80211_BSS_PARENT_TSF,
 	NL80211_BSS_PARENT_BSSID,
+	NL80211_BSS_CHAIN_SIGNAL,
 
 	/* keep last */
 	__NL80211_BSS_AFTER_LAST,
@@ -3878,10 +4225,12 @@
  * enum nl80211_mfp - Management frame protection state
  * @NL80211_MFP_NO: Management frame protection not used
  * @NL80211_MFP_REQUIRED: Management frame protection required
+ * @NL80211_MFP_OPTIONAL: Management frame protection is optional
  */
 enum nl80211_mfp {
 	NL80211_MFP_NO,
 	NL80211_MFP_REQUIRED,
+	NL80211_MFP_OPTIONAL,
 };
 
 enum nl80211_wpa_versions {
@@ -3992,7 +4341,7 @@
  * enum nl80211_band - Frequency band
  * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
  * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
- * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
+ * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
  * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
  *	since newer kernel versions may support more bands
  */
@@ -4838,6 +5187,44 @@
  *	RSSI threshold values to monitor rather than exactly one threshold.
  * @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
  *	authentication with %NL80211_CMD_CONNECT.
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK: Device wants to do 4-way
+ *	handshake with PSK in station mode (PSK is passed as part of the connect
+ *	and associate commands), doing it in the host might not be supported.
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X: Device wants to do doing 4-way
+ *	handshake with 802.1X in station mode (will pass EAP frames to the host
+ *	and accept the set_pmk/del_pmk commands), doing it in the host might not
+ *	be supported.
+ * @NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME: Driver is capable of overriding
+ *	the max channel attribute in the FILS request params IE with the
+ *	actual dwell time.
+ * @NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP: Driver accepts broadcast probe
+ *	response
+ * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE: Driver supports sending
+ *	the first probe request in each channel at rate of at least 5.5Mbps.
+ * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: Driver supports
+ *	probe request tx deferral and suppression
+ * @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL
+ *	value in %NL80211_ATTR_USE_MFP.
+ * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
+ * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
+ * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
+ * @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions.
+ *	Device or driver will do all DFS-related actions by itself,
+ *	informing user-space about CAC progress, radar detection event,
+ *	channel change triggered by radar detection event.
+ *	No need to start CAC from user-space, no need to react to
+ *	"radar detected" event.
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
+ *	receiving control port frames over nl80211 instead of the netdevice.
+ * @NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT: This driver/device supports
+ *	(average) ACK signal strength reporting.
+ * @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
+ *      TXQs.
+ * @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the
+ *	SN in probe request frames if requested by %NL80211_SCAN_FLAG_RANDOM_SN.
+ * @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data
+ *	except for supported rates from the probe request content if requested
+ *	by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4858,6 +5245,24 @@
 	NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
 	NL80211_EXT_FEATURE_CQM_RSSI_LIST,
 	NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
+	NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
+	NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,
+	NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME,
+	NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP,
+	NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
+	NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
+	NL80211_EXT_FEATURE_MFP_OPTIONAL,
+	NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
+	NL80211_EXT_FEATURE_LOW_POWER_SCAN,
+	NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
+	NL80211_EXT_FEATURE_DFS_OFFLOAD,
+	NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
+	NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
+	/* we renamed this - stay compatible */
+	NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
+	NL80211_EXT_FEATURE_TXQS,
+	NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
+	NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
@@ -4918,6 +5323,10 @@
  * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
  * requests.
  *
+ * NL80211_SCAN_FLAG_LOW_SPAN, NL80211_SCAN_FLAG_LOW_POWER, and
+ * NL80211_SCAN_FLAG_HIGH_ACCURACY flags are exclusive of each other, i.e., only
+ * one of them can be used in the request.
+ *
  * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
  * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
  * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
@@ -4934,12 +5343,52 @@
  *	locally administered 1, multicast 0) is assumed.
  *	This flag must not be requested when the feature isn't supported, check
  *	the nl80211 feature flags for the device.
+ * @NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME: fill the dwell time in the FILS
+ *	request parameters IE in the probe request
+ * @NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe responses
+ * @NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE: send probe request frames at
+ *	rate of at least 5.5M. In case non OCE AP is dicovered in the channel,
+ *	only the first probe req in the channel will be sent in high rate.
+ * @NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: allow probe request
+ *	tx deferral (dot11FILSProbeDelay shall be set to 15ms)
+ *	and suppression (if it has received a broadcast Probe Response frame,
+ *	Beacon frame or FILS Discovery frame from an AP that the STA considers
+ *	a suitable candidate for (re-)association - suitable in terms of
+ *	SSID and/or RSSI.
+ * @NL80211_SCAN_FLAG_LOW_SPAN: Span corresponds to the total time taken to
+ *	accomplish the scan. Thus, this flag intends the driver to perform the
+ *	scan request with lesser span/duration. It is specific to the driver
+ *	implementations on how this is accomplished. Scan accuracy may get
+ *	impacted with this flag.
+ * @NL80211_SCAN_FLAG_LOW_POWER: This flag intends the scan attempts to consume
+ *	optimal possible power. Drivers can resort to their specific means to
+ *	optimize the power. Scan accuracy may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_HIGH_ACCURACY: Accuracy here intends to the extent of scan
+ *	results obtained. Thus HIGH_ACCURACY scan flag aims to get maximum
+ *	possible scan results. This flag hints the driver to use the best
+ *	possible scan configuration to improve the accuracy in scanning.
+ *	Latency and power use may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_RANDOM_SN: randomize the sequence number in probe
+ *	request frames from this scan to avoid correlation/tracking being
+ *	possible.
+ * @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to
+ *	only have supported rates and no additional capabilities (unless
+ *	added by userspace explicitly.)
  */
 enum nl80211_scan_flags {
-	NL80211_SCAN_FLAG_LOW_PRIORITY			= 1<<0,
-	NL80211_SCAN_FLAG_FLUSH				= 1<<1,
-	NL80211_SCAN_FLAG_AP				= 1<<2,
-	NL80211_SCAN_FLAG_RANDOM_ADDR			= 1<<3,
+	NL80211_SCAN_FLAG_LOW_PRIORITY				= 1<<0,
+	NL80211_SCAN_FLAG_FLUSH					= 1<<1,
+	NL80211_SCAN_FLAG_AP					= 1<<2,
+	NL80211_SCAN_FLAG_RANDOM_ADDR				= 1<<3,
+	NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME			= 1<<4,
+	NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP		= 1<<5,
+	NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE		= 1<<6,
+	NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION	= 1<<7,
+	NL80211_SCAN_FLAG_LOW_SPAN				= 1<<8,
+	NL80211_SCAN_FLAG_LOW_POWER				= 1<<9,
+	NL80211_SCAN_FLAG_HIGH_ACCURACY				= 1<<10,
+	NL80211_SCAN_FLAG_RANDOM_SN				= 1<<11,
+	NL80211_SCAN_FLAG_MIN_PREQ_CONTENT			= 1<<12,
 };
 
 /**
@@ -4997,6 +5446,8 @@
  *	non-operating channel is expired and no longer valid. New CAC must
  *	be done on this channel before starting the operation. This is not
  *	applicable for ETSI dfs domain where pre-CAC is valid for ever.
+ * @NL80211_RADAR_CAC_STARTED: Channel Availability Check has been started,
+ *	should be generated by HW if NL80211_EXT_FEATURE_DFS_OFFLOAD is enabled.
  */
 enum nl80211_radar_event {
 	NL80211_RADAR_DETECTED,
@@ -5004,6 +5455,7 @@
 	NL80211_RADAR_CAC_ABORTED,
 	NL80211_RADAR_NOP_FINISHED,
 	NL80211_RADAR_PRE_CAC_EXPIRED,
+	NL80211_RADAR_CAC_STARTED,
 };
 
 /**
@@ -5295,11 +5747,11 @@
  * @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set.
  *	This is a flag.
  * @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if
- *	&NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
+ *	%NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
  * @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if
- *	&NL80211_NAN_SRF_BF is present. This is a u8.
+ *	%NL80211_NAN_SRF_BF is present. This is a u8.
  * @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if
- *	and only if &NL80211_NAN_SRF_BF isn't present. This is a nested
+ *	and only if %NL80211_NAN_SRF_BF isn't present. This is a nested
  *	attribute. Each nested attribute is a MAC address.
  * @NUM_NL80211_NAN_SRF_ATTR: internal
  * @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute
@@ -5339,4 +5791,15 @@
 	NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
 };
 
+/**
+ * nl80211_external_auth_action - Action to perform with external
+ *     authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION.
+ * @NL80211_EXTERNAL_AUTH_START: Start the authentication.
+ * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication.
+ */
+enum nl80211_external_auth_action {
+	NL80211_EXTERNAL_AUTH_START,
+	NL80211_EXTERNAL_AUTH_ABORT,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
index 6217468..bfe8811 100644
--- a/src/eap_common/eap_eke_common.c
+++ b/src/eap_common/eap_eke_common.c
@@ -161,7 +161,6 @@
 	int generator;
 	u8 gen;
 	const struct dh_group *dh;
-	size_t pub_len, i;
 
 	generator = eap_eke_dh_generator(group);
 	dh = eap_eke_dh_group(group);
@@ -169,33 +168,11 @@
 		return -1;
 	gen = generator;
 
-	/* x = random number 2 .. p-1 */
-	if (random_get_bytes(ret_priv, dh->prime_len))
-		return -1;
-	if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
-		/* Make sure private value is smaller than prime */
-		ret_priv[0] = 0;
-	}
-	for (i = 0; i < dh->prime_len - 1; i++) {
-		if (ret_priv[i])
-			break;
-	}
-	if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
+	if (crypto_dh_init(gen, dh->prime, dh->prime_len, ret_priv,
+			   ret_pub) < 0)
 		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
 			ret_priv, dh->prime_len);
-
-	/* y = g ^ x (mod p) */
-	pub_len = dh->prime_len;
-	if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
-			   dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
-		return -1;
-	if (pub_len < dh->prime_len) {
-		size_t pad = dh->prime_len - pub_len;
-		os_memmove(ret_pub + pad, ret_pub, pub_len);
-		os_memset(ret_pub, 0, pad);
-	}
-
 	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
 		    ret_pub, dh->prime_len);
 
@@ -421,8 +398,9 @@
 
 	/* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
 	len = dh->prime_len;
-	if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
-			   dh->prime, dh->prime_len, modexp, &len) < 0)
+	if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+				    dhpriv, dh->prime_len, peer_pub,
+				    dh->prime_len, modexp, &len) < 0)
 		return -1;
 	if (len < dh->prime_len) {
 		size_t pad = dh->prime_len - len;
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 67f8f70..88c6595 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -81,6 +81,27 @@
 }
 
 
+EAP_PWD_group * get_eap_pwd_group(u16 num)
+{
+	EAP_PWD_group *grp;
+
+	grp = os_zalloc(sizeof(EAP_PWD_group));
+	if (!grp)
+		return NULL;
+	grp->group = crypto_ec_init(num);
+	if (!grp->group) {
+		wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC group");
+		os_free(grp);
+		return NULL;
+	}
+
+	grp->group_num = num;
+	wpa_printf(MSG_INFO, "EAP-pwd: provisioned group %d", num);
+
+	return grp;
+}
+
+
 /*
  * compute a "random" secret point on an elliptic curve based
  * on the password and identities.
@@ -91,105 +112,71 @@
 			     const u8 *id_peer, size_t id_peer_len,
 			     const u8 *token)
 {
-	BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
+	struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL;
+	struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
 	struct crypto_hash *hash;
 	unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
-	int nid, is_odd, ret = 0;
+	int is_odd, ret = 0, check, found = 0;
 	size_t primebytelen, primebitlen;
+	struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
+	const struct crypto_bignum *prime;
 
-	switch (num) { /* from IANA registry for IKE D-H groups */
-        case 19:
-		nid = NID_X9_62_prime256v1;
-		break;
-        case 20:
-		nid = NID_secp384r1;
-		break;
-        case 21:
-		nid = NID_secp521r1;
-		break;
-#ifndef OPENSSL_IS_BORINGSSL
-        case 25:
-		nid = NID_X9_62_prime192v1;
-		break;
-#endif /* OPENSSL_IS_BORINGSSL */
-        case 26:
-		nid = NID_secp224r1;
-		break;
-#ifdef NID_brainpoolP224r1
-	case 27:
-		nid = NID_brainpoolP224r1;
-		break;
-#endif /* NID_brainpoolP224r1 */
-#ifdef NID_brainpoolP256r1
-	case 28:
-		nid = NID_brainpoolP256r1;
-		break;
-#endif /* NID_brainpoolP256r1 */
-#ifdef NID_brainpoolP384r1
-	case 29:
-		nid = NID_brainpoolP384r1;
-		break;
-#endif /* NID_brainpoolP384r1 */
-#ifdef NID_brainpoolP512r1
-	case 30:
-		nid = NID_brainpoolP512r1;
-		break;
-#endif /* NID_brainpoolP512r1 */
-        default:
-		wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
+	if (grp->pwe)
 		return -1;
-	}
 
-	grp->pwe = NULL;
-	grp->order = NULL;
-	grp->prime = NULL;
-
-	if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
-		wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
-		goto fail;
-	}
-
-	if (((rnd = BN_new()) == NULL) ||
-	    ((cofactor = BN_new()) == NULL) ||
-	    ((grp->pwe = EC_POINT_new(grp->group)) == NULL) ||
-	    ((grp->order = BN_new()) == NULL) ||
-	    ((grp->prime = BN_new()) == NULL) ||
-	    ((x_candidate = BN_new()) == NULL)) {
+	prime = crypto_ec_get_prime(grp->group);
+	cofactor = crypto_bignum_init();
+	grp->pwe = crypto_ec_point_init(grp->group);
+	tmp1 = crypto_bignum_init();
+	pm1 = crypto_bignum_init();
+	one = crypto_bignum_init_set((const u8 *) "\x01", 1);
+	if (!cofactor || !grp->pwe || !tmp1 || !pm1 || !one) {
 		wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
 		goto fail;
 	}
 
-	if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL))
-	{
-		wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp "
-			   "curve");
-		goto fail;
-	}
-	if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) {
-		wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve");
-		goto fail;
-	}
-	if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) {
+	if (crypto_ec_cofactor(grp->group, cofactor) < 0) {
 		wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
 			   "curve");
 		goto fail;
 	}
-	primebitlen = BN_num_bits(grp->prime);
-	primebytelen = BN_num_bytes(grp->prime);
+	primebitlen = crypto_ec_prime_len_bits(grp->group);
+	primebytelen = crypto_ec_prime_len(grp->group);
 	if ((prfbuf = os_malloc(primebytelen)) == NULL) {
 		wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
 			   "buffer");
 		goto fail;
 	}
+	if (crypto_bignum_sub(prime, one, pm1) < 0)
+		goto fail;
+
+	/* get a random quadratic residue and nonresidue */
+	while (!qr || !qnr) {
+		int res;
+
+		if (crypto_bignum_rand(tmp1, prime) < 0)
+			goto fail;
+		res = crypto_bignum_legendre(tmp1, prime);
+		if (!qr && res == 1) {
+			qr = tmp1;
+			tmp1 = crypto_bignum_init();
+		} else if (!qnr && res == -1) {
+			qnr = tmp1;
+			tmp1 = crypto_bignum_init();
+		}
+		if (!tmp1)
+			goto fail;
+	}
+
 	os_memset(prfbuf, 0, primebytelen);
 	ctr = 0;
-	while (1) {
-		if (ctr > 30) {
-			wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
-				   "point on curve for group %d, something's "
-				   "fishy", num);
-			goto fail;
-		}
+
+	/*
+	 * Run through the hunting-and-pecking loop 40 times to mask the time
+	 * necessary to find PWE. The odds of PWE not being found in 40 loops is
+	 * roughly 1 in 1 trillion.
+	 */
+	while (ctr < 40) {
 		ctr++;
 
 		/*
@@ -207,15 +194,25 @@
 		eap_pwd_h_update(hash, &ctr, sizeof(ctr));
 		eap_pwd_h_final(hash, pwe_digest);
 
-		BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd);
-
+		crypto_bignum_deinit(rnd, 1);
+		rnd = crypto_bignum_init_set(pwe_digest, SHA256_MAC_LEN);
+		if (!rnd) {
+			wpa_printf(MSG_INFO, "EAP-pwd: unable to create rnd");
+			goto fail;
+		}
 		if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
 				(u8 *) "EAP-pwd Hunting And Pecking",
 				os_strlen("EAP-pwd Hunting And Pecking"),
 				prfbuf, primebitlen) < 0)
 			goto fail;
 
-		BN_bin2bn(prfbuf, primebytelen, x_candidate);
+		crypto_bignum_deinit(x_candidate, 1);
+		x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
+		if (!x_candidate) {
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd: unable to create x_candidate");
+			goto fail;
+		}
 
 		/*
 		 * eap_pwd_kdf() returns a string of bits 0..primebitlen but
@@ -224,97 +221,157 @@
 		 * then excessive bits-- those _after_ primebitlen-- so now
 		 * we have to shift right the amount we masked off.
 		 */
-		if (primebitlen % 8)
-			BN_rshift(x_candidate, x_candidate,
-				  (8 - (primebitlen % 8)));
+		if ((primebitlen % 8) &&
+		    crypto_bignum_rshift(x_candidate,
+					 (8 - (primebitlen % 8)),
+					 x_candidate) < 0)
+			goto fail;
 
-		if (BN_ucmp(x_candidate, grp->prime) >= 0)
+		if (crypto_bignum_cmp(x_candidate, prime) >= 0)
 			continue;
 
 		wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
 			    prfbuf, primebytelen);
 
 		/*
-		 * need to unambiguously identify the solution, if there is
-		 * one...
+		 * compute y^2 using the equation of the curve
+		 *
+		 *      y^2 = x^3 + ax + b
 		 */
-		if (BN_is_odd(rnd))
-			is_odd = 1;
-		else
-			is_odd = 0;
+		tmp2 = crypto_ec_point_compute_y_sqr(grp->group, x_candidate);
+		if (!tmp2)
+			goto fail;
 
 		/*
-		 * solve the quadratic equation, if it's not solvable then we
-		 * don't have a point
+		 * mask tmp2 so doing legendre won't leak timing info
+		 *
+		 * tmp1 is a random number between 1 and p-1
 		 */
-		if (!EC_POINT_set_compressed_coordinates_GFp(grp->group,
-							     grp->pwe,
-							     x_candidate,
-							     is_odd, NULL))
-			continue;
+		if (crypto_bignum_rand(tmp1, pm1) < 0 ||
+		    crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0 ||
+		    crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0)
+			goto fail;
+
 		/*
-		 * If there's a solution to the equation then the point must be
-		 * on the curve so why check again explicitly? OpenSSL code
-		 * says this is required by X9.62. We're not X9.62 but it can't
-		 * hurt just to be sure.
+		 * Now tmp2 (y^2) is masked, all values between 1 and p-1
+		 * are equally probable. Multiplying by r^2 does not change
+		 * whether or not tmp2 is a quadratic residue, just masks it.
+		 *
+		 * Flip a coin, multiply by the random quadratic residue or the
+		 * random quadratic nonresidue and record heads or tails.
 		 */
-		if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) {
-			wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
-			continue;
+		if (crypto_bignum_is_odd(tmp1)) {
+			crypto_bignum_mulmod(tmp2, qr, prime, tmp2);
+			check = 1;
+		} else {
+			crypto_bignum_mulmod(tmp2, qnr, prime, tmp2);
+			check = -1;
 		}
 
-		if (BN_cmp(cofactor, BN_value_one())) {
-			/* make sure the point is not in a small sub-group */
-			if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe,
-					  cofactor, NULL)) {
-				wpa_printf(MSG_INFO, "EAP-pwd: cannot "
-					   "multiply generator by order");
+		/*
+		 * Now it's safe to do legendre, if check is 1 then it's
+		 * a straightforward test (multiplying by qr does not
+		 * change result), if check is -1 then it's the opposite test
+		 * (multiplying a qr by qnr would make a qnr).
+		 */
+		if (crypto_bignum_legendre(tmp2, prime) == check) {
+			if (found == 1)
+				continue;
+
+			/* need to unambiguously identify the solution */
+			is_odd = crypto_bignum_is_odd(rnd);
+
+			/*
+			 * We know x_candidate is a quadratic residue so set
+			 * it here.
+			 */
+			if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe,
+							  x_candidate,
+							  is_odd) != 0) {
+				wpa_printf(MSG_INFO,
+					   "EAP-pwd: Could not solve for y");
 				continue;
 			}
-			if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) {
-				wpa_printf(MSG_INFO, "EAP-pwd: point is at "
-					   "infinity");
+
+			/*
+			 * If there's a solution to the equation then the point
+			 * must be on the curve so why check again explicitly?
+			 * OpenSSL code says this is required by X9.62. We're
+			 * not X9.62 but it can't hurt just to be sure.
+			 */
+			if (!crypto_ec_point_is_on_curve(grp->group,
+							 grp->pwe)) {
+				wpa_printf(MSG_INFO,
+					   "EAP-pwd: point is not on curve");
 				continue;
 			}
+
+			if (!crypto_bignum_is_one(cofactor)) {
+				/* make sure the point is not in a small
+				 * sub-group */
+				if (crypto_ec_point_mul(grp->group, grp->pwe,
+							cofactor,
+							grp->pwe) != 0) {
+					wpa_printf(MSG_INFO,
+						   "EAP-pwd: cannot multiply generator by order");
+					continue;
+				}
+				if (crypto_ec_point_is_at_infinity(grp->group,
+								   grp->pwe)) {
+					wpa_printf(MSG_INFO,
+						   "EAP-pwd: point is at infinity");
+					continue;
+				}
+			}
+			wpa_printf(MSG_DEBUG,
+				   "EAP-pwd: found a PWE in %d tries", ctr);
+			found = 1;
 		}
-		/* if we got here then we have a new generator. */
-		break;
 	}
-	wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr);
-	grp->group_num = num;
+	if (found == 0) {
+		wpa_printf(MSG_INFO,
+			   "EAP-pwd: unable to find random point on curve for group %d, something's fishy",
+			   num);
+		goto fail;
+	}
 	if (0) {
  fail:
-		EC_GROUP_free(grp->group);
-		grp->group = NULL;
-		EC_POINT_clear_free(grp->pwe);
+		crypto_ec_point_deinit(grp->pwe, 1);
 		grp->pwe = NULL;
-		BN_clear_free(grp->order);
-		grp->order = NULL;
-		BN_clear_free(grp->prime);
-		grp->prime = NULL;
 		ret = 1;
 	}
 	/* cleanliness and order.... */
-	BN_clear_free(cofactor);
-	BN_clear_free(x_candidate);
-	BN_clear_free(rnd);
+	crypto_bignum_deinit(cofactor, 1);
+	crypto_bignum_deinit(x_candidate, 1);
+	crypto_bignum_deinit(rnd, 1);
+	crypto_bignum_deinit(pm1, 0);
+	crypto_bignum_deinit(tmp1, 1);
+	crypto_bignum_deinit(tmp2, 1);
+	crypto_bignum_deinit(qr, 1);
+	crypto_bignum_deinit(qnr, 1);
+	crypto_bignum_deinit(one, 0);
 	os_free(prfbuf);
 
 	return ret;
 }
 
 
-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
-		 const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+		 const struct crypto_bignum *peer_scalar,
+		 const struct crypto_bignum *server_scalar,
 		 const u8 *confirm_peer, const u8 *confirm_server,
 		 const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id)
 {
 	struct crypto_hash *hash;
 	u8 mk[SHA256_MAC_LEN], *cruft;
 	u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
-	int offset;
+	size_t prime_len, order_len;
 
-	if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
+	prime_len = crypto_ec_prime_len(grp->group);
+	order_len = crypto_ec_order_len(grp->group);
+
+	cruft = os_malloc(prime_len);
+	if (!cruft)
 		return -1;
 
 	/*
@@ -328,14 +385,10 @@
 		return -1;
 	}
 	eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32));
-	offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
-	os_memset(cruft, 0, BN_num_bytes(grp->prime));
-	BN_bn2bin(peer_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
-	offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
-	os_memset(cruft, 0, BN_num_bytes(grp->prime));
-	BN_bn2bin(server_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+	crypto_bignum_to_bin(peer_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
+	crypto_bignum_to_bin(server_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 	eap_pwd_h_final(hash, &session_id[1]);
 
 	/* then compute MK = H(k | confirm-peer | confirm-server) */
@@ -344,10 +397,8 @@
 		os_free(cruft);
 		return -1;
 	}
-	offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
-	os_memset(cruft, 0, BN_num_bytes(grp->prime));
-	BN_bn2bin(k, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime));
+	crypto_bignum_to_bin(k, cruft, prime_len, prime_len);
+	eap_pwd_h_update(hash, cruft, prime_len);
 	os_free(cruft);
 	eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN);
 	eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN);
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
index a0d717e..6b07cf8 100644
--- a/src/eap_common/eap_pwd_common.h
+++ b/src/eap_common/eap_pwd_common.h
@@ -9,20 +9,14 @@
 #ifndef EAP_PWD_COMMON_H
 #define EAP_PWD_COMMON_H
 
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/evp.h>
-
 /*
  * definition of a finite cyclic group
  * TODO: support one based on a prime field
  */
 typedef struct group_definition_ {
 	u16 group_num;
-	EC_GROUP *group;
-	EC_POINT *pwe;
-	BIGNUM *order;
-	BIGNUM *prime;
+	struct crypto_ec *group;
+	struct crypto_ec_point *pwe;
 } EAP_PWD_group;
 
 /*
@@ -52,17 +46,22 @@
 	u8 prep;
 #define EAP_PWD_PREP_NONE               0
 #define EAP_PWD_PREP_MS                 1
+#define EAP_PWD_PREP_SSHA1              3
+#define EAP_PWD_PREP_SSHA256            4
+#define EAP_PWD_PREP_SSHA512            5
 	u8 identity[0];     /* length inferred from payload */
 } STRUCT_PACKED;
 
 /* common routines */
+EAP_PWD_group * get_eap_pwd_group(u16 num);
 int compute_password_element(EAP_PWD_group *grp, u16 num,
 			     const u8 *password, size_t password_len,
 			     const u8 *id_server, size_t id_server_len,
 			     const u8 *id_peer, size_t id_peer_len,
 			     const u8 *token);
-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
-		 const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+		 const struct crypto_bignum *peer_scalar,
+		 const struct crypto_bignum  *server_scalar,
 		 const u8 *confirm_peer, const u8 *confirm_server,
 		 const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id);
 struct crypto_hash * eap_pwd_h_init(void);
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 52b0491..974c475 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -94,6 +94,7 @@
 		sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
 }
 
+
 static void eap_report_error(struct eap_sm *sm, int error_code)
 {
 	wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code);
@@ -101,6 +102,7 @@
 		sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code);
 }
 
+
 static void eap_sm_free_key(struct eap_sm *sm)
 {
 	if (sm->eapKeyData) {
@@ -668,6 +670,9 @@
 }
 
 
+/* Note: If ext_session and/or ext_emsk are passed to this function, they are
+ * expected to point to allocated memory and those allocations will be freed
+ * unconditionally. */
 void eap_peer_erp_init(struct eap_sm *sm, u8 *ext_session_id,
 		       size_t ext_session_id_len, u8 *ext_emsk,
 		       size_t ext_emsk_len)
@@ -686,7 +691,7 @@
 
 	realm = eap_home_realm(sm);
 	if (!realm)
-		return;
+		goto fail;
 	realm_len = os_strlen(realm);
 	wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
 	eap_erp_remove_keys_realm(sm, realm);
@@ -773,7 +778,10 @@
 	dl_list_add(&sm->erp_keys, &erp->list);
 	erp = NULL;
 fail:
-	bin_clear_free(emsk, emsk_len);
+	if (ext_emsk)
+		bin_clear_free(ext_emsk, ext_emsk_len);
+	else
+		bin_clear_free(emsk, emsk_len);
 	bin_clear_free(ext_session_id, ext_session_id_len);
 	bin_clear_free(erp, sizeof(*erp));
 	os_free(realm);
@@ -1940,7 +1948,6 @@
 	const struct eap_hdr *hdr;
 	size_t plen;
 	const u8 *pos;
-        int error_code;
 
 	sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
 	sm->reqId = 0;
@@ -2028,6 +2035,8 @@
 
 		/* Get the error code from method */
 		if (sm->m && sm->m->get_error_code) {
+			int error_code;
+
 			error_code = sm->m->get_error_code(sm->eap_method_priv);
 			if (error_code != NO_EAP_METHOD_ERROR)
 				eap_report_error(sm, error_code);
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 679f101..a444141 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1528,14 +1528,16 @@
 	return key;
 }
 
+
 static int eap_aka_get_error_code(void *priv)
 {
 	struct eap_aka_data *data = priv;
+	int current_data_error;
 
 	if (!data)
 		return NO_EAP_METHOD_ERROR;
 
-	int current_data_error = data->error_code;
+	current_data_error = data->error_code;
 
 	/* Now reset for next transaction */
 	data->error_code = NO_EAP_METHOD_ERROR;
@@ -1543,6 +1545,7 @@
 	return current_data_error;
 }
 
+
 int eap_peer_aka_register(void)
 {
 	struct eap_method *eap;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 5b38969..096f0f2 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -208,10 +208,10 @@
 	const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
 
 	/**
-	 * get_error_code - Get latest EAP method error code
+	 * get_error_code - Get the latest EAP method error code
 	 * @priv: Pointer to private EAP method data from eap_method::init()
-	 * Returns: An int for the EAP Method Error code if exists or
-	 * NO_EAP_METHOD_ERROR otherwise
+	 * Returns: An int for the EAP method specific error code if exists or
+	 * NO_EAP_METHOD_ERROR otherwise.
 	 *
 	 * This method is an optional handler that only EAP methods that need to
 	 * report their error code need to implement.
diff --git a/src/eap_peer/eap_proxy_qmi_oc.c b/src/eap_peer/eap_proxy_qmi_oc.c
index 4c07da5..9fcf512 100644
--- a/src/eap_peer/eap_proxy_qmi_oc.c
+++ b/src/eap_peer/eap_proxy_qmi_oc.c
@@ -32,7 +32,7 @@
 
 #ifdef CONFIG_EAP_PROXY
 #include "qmi_client.h"
-#include "eap_proxy_qmi.h"
+#include "eap_proxy_qmi_oc.h"
 #include "qmi_client.h"
 #include "qmi_idl_lib.h"
 #include "authentication_service_v01.h"
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index ec277ac..761c16a 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -9,8 +9,11 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha1.h"
 #include "crypto/sha256.h"
+#include "crypto/sha512.h"
 #include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
 #include "eap_peer/eap_i.h"
 #include "eap_common/eap_pwd_common.h"
 
@@ -28,6 +31,8 @@
 	size_t password_len;
 	int password_hash;
 	u16 group_num;
+	u8 prep;
+	u8 token[4];
 	EAP_PWD_group *grp;
 
 	struct wpabuf *inbuf;
@@ -36,18 +41,16 @@
 	size_t out_frag_pos;
 	size_t mtu;
 
-	BIGNUM *k;
-	BIGNUM *private_value;
-	BIGNUM *server_scalar;
-	BIGNUM *my_scalar;
-	EC_POINT *my_element;
-	EC_POINT *server_element;
+	struct crypto_bignum *k;
+	struct crypto_bignum *private_value;
+	struct crypto_bignum *server_scalar;
+	struct crypto_bignum *my_scalar;
+	struct crypto_ec_point *my_element;
+	struct crypto_ec_point *server_element;
 
 	u8 msk[EAP_MSK_LEN];
 	u8 emsk[EAP_EMSK_LEN];
 	u8 session_id[1 + SHA256_MAC_LEN];
-
-	BN_CTX *bnctx;
 };
 
 
@@ -107,15 +110,8 @@
 		return NULL;
 	}
 
-	if ((data->bnctx = BN_CTX_new()) == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
-		os_free(data);
-		return NULL;
-	}
-
 	if ((data->id_peer = os_malloc(identity_len)) == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
-		BN_CTX_free(data->bnctx);
 		os_free(data);
 		return NULL;
 	}
@@ -125,7 +121,6 @@
 
 	if ((data->password = os_malloc(password_len)) == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
-		BN_CTX_free(data->bnctx);
 		bin_clear_free(data->id_peer, data->id_peer_len);
 		os_free(data);
 		return NULL;
@@ -152,21 +147,18 @@
 {
 	struct eap_pwd_data *data = priv;
 
-	BN_clear_free(data->private_value);
-	BN_clear_free(data->server_scalar);
-	BN_clear_free(data->my_scalar);
-	BN_clear_free(data->k);
-	BN_CTX_free(data->bnctx);
-	EC_POINT_clear_free(data->my_element);
-	EC_POINT_clear_free(data->server_element);
+	crypto_bignum_deinit(data->private_value, 1);
+	crypto_bignum_deinit(data->server_scalar, 1);
+	crypto_bignum_deinit(data->my_scalar, 1);
+	crypto_bignum_deinit(data->k, 1);
+	crypto_ec_point_deinit(data->my_element, 1);
+	crypto_ec_point_deinit(data->server_element, 1);
 	bin_clear_free(data->id_peer, data->id_peer_len);
 	bin_clear_free(data->id_server, data->id_server_len);
 	bin_clear_free(data->password, data->password_len);
 	if (data->grp) {
-		EC_GROUP_free(data->grp->group);
-		EC_POINT_clear_free(data->grp->pwe);
-		BN_clear_free(data->grp->order);
-		BN_clear_free(data->grp->prime);
+		crypto_ec_deinit(data->grp->group);
+		crypto_ec_point_deinit(data->grp->pwe, 1);
 		os_free(data->grp);
 	}
 	wpabuf_free(data->inbuf);
@@ -218,10 +210,6 @@
 			    const u8 *payload, size_t payload_len)
 {
 	struct eap_pwd_id *id;
-	const u8 *password;
-	size_t password_len;
-	u8 pwhashhash[16];
-	int res;
 
 	if (data->state != PWD_ID_Req) {
 		ret->ignore = TRUE;
@@ -248,7 +236,10 @@
 	}
 
 	if (id->prep != EAP_PWD_PREP_NONE &&
-	    id->prep != EAP_PWD_PREP_MS) {
+	    id->prep != EAP_PWD_PREP_MS &&
+	    id->prep != EAP_PWD_PREP_SSHA1 &&
+	    id->prep != EAP_PWD_PREP_SSHA256 &&
+	    id->prep != EAP_PWD_PREP_SSHA512) {
 		wpa_printf(MSG_DEBUG,
 			   "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)",
 			   id->prep);
@@ -266,6 +257,15 @@
 	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d",
 		   data->group_num);
 
+	data->prep = id->prep;
+	os_memcpy(data->token, id->token, sizeof(id->token));
+
+	if (data->id_server || data->grp) {
+		wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
 	data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id));
 	if (data->id_server == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
@@ -277,7 +277,7 @@
 	wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
 			  data->id_server, data->id_server_len);
 
-	data->grp = os_zalloc(sizeof(EAP_PWD_group));
+	data->grp = get_eap_pwd_group(data->group_num);
 	if (data->grp == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
 			   "group");
@@ -285,54 +285,6 @@
 		return;
 	}
 
-	if (id->prep == EAP_PWD_PREP_MS) {
-#ifdef CONFIG_FIPS
-		wpa_printf(MSG_ERROR,
-			   "EAP-PWD (peer): MS password hash not supported in FIPS mode");
-		eap_pwd_state(data, FAILURE);
-		return;
-#else /* CONFIG_FIPS */
-		if (data->password_hash) {
-			res = hash_nt_password_hash(data->password, pwhashhash);
-		} else {
-			u8 pwhash[16];
-
-			res = nt_password_hash(data->password,
-					       data->password_len, pwhash);
-			if (res == 0)
-				res = hash_nt_password_hash(pwhash, pwhashhash);
-			os_memset(pwhash, 0, sizeof(pwhash));
-		}
-
-		if (res) {
-			eap_pwd_state(data, FAILURE);
-			return;
-		}
-
-		password = pwhashhash;
-		password_len = sizeof(pwhashhash);
-#endif /* CONFIG_FIPS */
-	} else {
-		password = data->password;
-		password_len = data->password_len;
-	}
-
-	/* compute PWE */
-	res = compute_password_element(data->grp, data->group_num,
-				       password, password_len,
-				       data->id_server, data->id_server_len,
-				       data->id_peer, data->id_peer_len,
-				       id->token);
-	os_memset(pwhashhash, 0, sizeof(pwhashhash));
-	if (res) {
-		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
-		eap_pwd_state(data, FAILURE);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
-		   BN_num_bits(data->grp->prime));
-
 	data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
 				    data->id_peer_len);
 	if (data->outbuf == NULL) {
@@ -356,109 +308,301 @@
 				const struct wpabuf *reqData,
 				const u8 *payload, size_t payload_len)
 {
-	EC_POINT *K = NULL, *point = NULL;
-	BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL;
-	u16 offset;
-	u8 *ptr, *scalar = NULL, *element = NULL;
+	struct crypto_ec_point *K = NULL, *point = NULL;
+	struct crypto_bignum *mask = NULL, *cofactor = NULL;
+	const u8 *ptr = payload;
+	u8 *scalar = NULL, *element = NULL;
 	size_t prime_len, order_len;
+	const u8 *password;
+	size_t password_len;
+	u8 pwhashhash[16];
+	const u8 *salt_pwd[2];
+	size_t salt_pwd_len[2], exp_len;
+	u8 salt_len, salthashpwd[64]; /* 64 = SHA512_DIGEST_LENGTH */
+	int res;
 
 	if (data->state != PWD_Commit_Req) {
 		ret->ignore = TRUE;
 		goto fin;
 	}
 
-	prime_len = BN_num_bytes(data->grp->prime);
-	order_len = BN_num_bytes(data->grp->order);
-
-	if (payload_len != 2 * prime_len + order_len) {
-		wpa_printf(MSG_INFO,
-			   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
-			   (unsigned int) payload_len,
-			   (unsigned int) (2 * prime_len + order_len));
+	if (!data->grp) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP-PWD (client): uninitialized EAP-pwd group");
+		ret->ignore = TRUE;
 		goto fin;
 	}
 
-	if (((data->private_value = BN_new()) == NULL) ||
-	    ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
-	    ((cofactor = BN_new()) == NULL) ||
-	    ((data->my_scalar = BN_new()) == NULL) ||
-	    ((mask = BN_new()) == NULL)) {
+	prime_len = crypto_ec_prime_len(data->grp->group);
+	order_len = crypto_ec_order_len(data->grp->group);
+
+	switch (data->prep) {
+	case EAP_PWD_PREP_MS:
+		wpa_printf(MSG_DEBUG,
+			   "EAP-pwd commit request, password prep is MS");
+#ifdef CONFIG_FIPS
+		wpa_printf(MSG_ERROR,
+			   "EAP-PWD (peer): MS password hash not supported in FIPS mode");
+		eap_pwd_state(data, FAILURE);
+		return;
+#else /* CONFIG_FIPS */
+		if (payload_len != 2 * prime_len + order_len) {
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+				   (unsigned int) payload_len,
+				   (unsigned int) (2 * prime_len + order_len));
+			goto fin;
+		}
+		if (data->password_hash) {
+			res = hash_nt_password_hash(data->password, pwhashhash);
+		} else {
+			u8 pwhash[16];
+
+			res = nt_password_hash(data->password,
+					       data->password_len, pwhash);
+			if (res == 0)
+				res = hash_nt_password_hash(pwhash, pwhashhash);
+			os_memset(pwhash, 0, sizeof(pwhash));
+		}
+
+		if (res) {
+			eap_pwd_state(data, FAILURE);
+			return;
+		}
+
+		password = pwhashhash;
+		password_len = sizeof(pwhashhash);
+#endif /* CONFIG_FIPS */
+		break;
+	case EAP_PWD_PREP_SSHA1:
+		wpa_printf(MSG_DEBUG,
+			   "EAP-pwd commit request, password prep is salted sha1");
+		if (payload_len < 1 || *ptr == 0) {
+			wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+			goto fin;
+		}
+		salt_len = *ptr++;
+		exp_len = 1 + salt_len + 2 * prime_len + order_len;
+		if (payload_len != exp_len) {
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+				   (unsigned int) payload_len,
+				   (unsigned int) exp_len);
+			goto fin;
+		}
+
+		/* salted-password = Hash(password | salt) */
+		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+				data->password, data->password_len);
+		wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+		salt_pwd[0] = data->password;
+		salt_pwd[1] = ptr;
+		salt_pwd_len[0] = data->password_len;
+		salt_pwd_len[1] = salt_len;
+		if (sha1_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+			goto fin;
+
+		wpa_printf(MSG_DEBUG,
+			   "EAP-pwd: sha1 hashed %d byte salt with password",
+			   (int) salt_len);
+		ptr += salt_len;
+		password = salthashpwd;
+		password_len = SHA1_MAC_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+				password, password_len);
+		break;
+	case EAP_PWD_PREP_SSHA256:
+		wpa_printf(MSG_DEBUG,
+			   "EAP-pwd commit request, password prep is salted sha256");
+		if (payload_len < 1 || *ptr == 0) {
+			wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+			goto fin;
+		}
+		salt_len = *ptr++;
+		exp_len = 1 + salt_len + 2 * prime_len + order_len;
+		if (payload_len != exp_len) {
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+				   (unsigned int) payload_len,
+				   (unsigned int) exp_len);
+			goto fin;
+		}
+
+		/* salted-password = Hash(password | salt) */
+		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+				data->password, data->password_len);
+		wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+		salt_pwd[0] = data->password;
+		salt_pwd[1] = ptr;
+		salt_pwd_len[0] = data->password_len;
+		salt_pwd_len[1] = salt_len;
+		if (sha256_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+			goto fin;
+
+		ptr += salt_len;
+		password = salthashpwd;
+		password_len = SHA256_MAC_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+				password, password_len);
+		break;
+#ifdef CONFIG_SHA512
+	case EAP_PWD_PREP_SSHA512:
+		wpa_printf(MSG_DEBUG,
+			   "EAP-pwd commit request, password prep is salted sha512");
+		if (payload_len < 1 || *ptr == 0) {
+			wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+			goto fin;
+		}
+		salt_len = *ptr++;
+		exp_len = 1 + salt_len + 2 * prime_len + order_len;
+		if (payload_len != exp_len) {
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+				   (unsigned int) payload_len,
+				   (unsigned int) exp_len);
+			goto fin;
+		}
+
+		/* salted-password = Hash(password | salt) */
+		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+				data->password, data->password_len);
+		wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+		salt_pwd[0] = data->password;
+		salt_pwd[1] = ptr;
+		salt_pwd_len[0] = data->password_len;
+		salt_pwd_len[1] = salt_len;
+		if (sha512_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+			goto fin;
+
+		ptr += salt_len;
+		password = salthashpwd;
+		password_len = SHA512_MAC_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+				password, password_len);
+		break;
+#endif /* CONFIG_SHA512 */
+	case EAP_PWD_PREP_NONE:
+		wpa_printf(MSG_DEBUG,
+			   "EAP-pwd commit request, password prep is NONE");
+		if (data->password_hash) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-PWD: Unhashed password not available");
+			eap_pwd_state(data, FAILURE);
+			return;
+		}
+		if (payload_len != 2 * prime_len + order_len) {
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+				   (unsigned int) payload_len,
+				   (unsigned int) (2 * prime_len + order_len));
+			goto fin;
+		}
+		password = data->password;
+		password_len = data->password_len;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "EAP-pwd: Unsupported password pre-processing technique (Prep=%u)",
+			   data->prep);
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	/* compute PWE */
+	res = compute_password_element(data->grp, data->group_num,
+				       password, password_len,
+				       data->id_server, data->id_server_len,
+				       data->id_peer, data->id_peer_len,
+				       data->token);
+	os_memset(pwhashhash, 0, sizeof(pwhashhash));
+	os_memset(salthashpwd, 0, sizeof(salthashpwd));
+	if (res) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
+		   (int) crypto_ec_prime_len_bits(data->grp->group));
+
+	data->private_value = crypto_bignum_init();
+	data->my_element = crypto_ec_point_init(data->grp->group);
+	cofactor = crypto_bignum_init();
+	data->my_scalar = crypto_bignum_init();
+	mask = crypto_bignum_init();
+	if (!data->private_value || !data->my_element || !cofactor ||
+	    !data->my_scalar || !mask) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
 		goto fin;
 	}
 
-	if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
+	if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) {
 		wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
 			   "for curve");
 		goto fin;
 	}
 
-	if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
-	    BN_rand_range(mask, data->grp->order) != 1 ||
-	    BN_add(data->my_scalar, data->private_value, mask) != 1 ||
-	    BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
-		   data->bnctx) != 1) {
+	if (crypto_bignum_rand(data->private_value,
+			       crypto_ec_get_order(data->grp->group)) < 0 ||
+	    crypto_bignum_rand(mask,
+			       crypto_ec_get_order(data->grp->group)) < 0 ||
+	    crypto_bignum_add(data->private_value, mask,
+			      data->my_scalar) < 0 ||
+	    crypto_bignum_mod(data->my_scalar,
+			      crypto_ec_get_order(data->grp->group),
+			      data->my_scalar) < 0) {
 		wpa_printf(MSG_INFO,
 			   "EAP-pwd (peer): unable to get randomness");
 		goto fin;
 	}
 
-	if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
-			  data->grp->pwe, mask, data->bnctx)) {
+	if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+				data->my_element) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
 			   "fail");
 		eap_pwd_state(data, FAILURE);
 		goto fin;
 	}
 
-	if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
-	{
+	if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
 		goto fin;
 	}
 
-	if (((x = BN_new()) == NULL) ||
-	    ((y = BN_new()) == NULL)) {
-		wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
-		goto fin;
-	}
-
 	/* process the request */
-	if (((data->server_scalar = BN_new()) == NULL) ||
-	    ((data->k = BN_new()) == NULL) ||
-	    ((K = EC_POINT_new(data->grp->group)) == NULL) ||
-	    ((point = EC_POINT_new(data->grp->group)) == NULL) ||
-	    ((data->server_element = EC_POINT_new(data->grp->group)) == NULL))
-	{
+	data->k = crypto_bignum_init();
+	K = crypto_ec_point_init(data->grp->group);
+	point = crypto_ec_point_init(data->grp->group);
+	if (!data->k || !K || !point) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
 			   "fail");
 		goto fin;
 	}
 
 	/* element, x then y, followed by scalar */
-	ptr = (u8 *) payload;
-	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
-	ptr += BN_num_bytes(data->grp->prime);
-	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
-	ptr += BN_num_bytes(data->grp->prime);
-	BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar);
-	if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
-						 data->server_element, x, y,
-						 data->bnctx)) {
+	data->server_element = crypto_ec_point_from_bin(data->grp->group, ptr);
+	if (!data->server_element) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
 			   "fail");
 		goto fin;
 	}
+	ptr += prime_len * 2;
+	data->server_scalar = crypto_bignum_init_set(ptr, order_len);
+	if (!data->server_scalar) {
+		wpa_printf(MSG_INFO,
+			   "EAP-PWD (peer): setting peer scalar fail");
+		goto fin;
+	}
 
 	/* check to ensure server's element is not in a small sub-group */
-	if (BN_cmp(cofactor, BN_value_one())) {
-		if (!EC_POINT_mul(data->grp->group, point, NULL,
-				  data->server_element, cofactor, NULL)) {
+	if (!crypto_bignum_is_one(cofactor)) {
+		if (crypto_ec_point_mul(data->grp->group, data->server_element,
+					cofactor, point) < 0) {
 			wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
 				   "server element by order!\n");
 			goto fin;
 		}
-		if (EC_POINT_is_at_infinity(data->grp->group, point)) {
+		if (crypto_ec_point_is_at_infinity(data->grp->group, point)) {
 			wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
 				   "is at infinity!\n");
 			goto fin;
@@ -466,21 +610,20 @@
 	}
 
 	/* compute the shared key, k */
-	if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
-			   data->server_scalar, data->bnctx)) ||
-	    (!EC_POINT_add(data->grp->group, K, K, data->server_element,
-			   data->bnctx)) ||
-	    (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
-			   data->bnctx))) {
+	if (crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+				data->server_scalar, K) < 0 ||
+	    crypto_ec_point_add(data->grp->group, K, data->server_element,
+				K) < 0 ||
+	    crypto_ec_point_mul(data->grp->group, K, data->private_value,
+				K) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
 			   "fail");
 		goto fin;
 	}
 
 	/* ensure that the shared key isn't in a small sub-group */
-	if (BN_cmp(cofactor, BN_value_one())) {
-		if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
-				  NULL)) {
+	if (!crypto_bignum_is_one(cofactor)) {
+		if (crypto_ec_point_mul(data->grp->group, K, cofactor, K) < 0) {
 			wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
 				   "shared key point by order");
 			goto fin;
@@ -493,30 +636,22 @@
 	 * never going to happen it is a simple and safe check "just to be
 	 * sure" so let's be safe.
 	 */
-	if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+	if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
 			   "infinity!\n");
 		goto fin;
 	}
 
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
-						 NULL, data->bnctx)) {
+	if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
 			   "shared secret from point");
 		goto fin;
 	}
 
 	/* now do the response */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->my_element, x, y,
-						 data->bnctx)) {
-		wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
-		goto fin;
-	}
-
-	if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
-	    ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
-	     NULL)) {
+	scalar = os_zalloc(order_len);
+	element = os_zalloc(prime_len * 2);
+	if (!scalar || !element) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail");
 		goto fin;
 	}
@@ -526,36 +661,28 @@
 	 * sufficiently smaller than the prime or order might need pre-pending
 	 * with zeros.
 	 */
-	os_memset(scalar, 0, BN_num_bytes(data->grp->order));
-	os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->my_scalar);
-	BN_bn2bin(data->my_scalar, scalar + offset);
+	crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
+	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
+				   element + prime_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
+		goto fin;
+	}
 
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, element + offset);
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
-
-	data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) +
-				    2 * BN_num_bytes(data->grp->prime));
+	data->outbuf = wpabuf_alloc(order_len + 2 * prime_len);
 	if (data->outbuf == NULL)
 		goto fin;
 
 	/* we send the element as (x,y) follwed by the scalar */
-	wpabuf_put_data(data->outbuf, element,
-			2 * BN_num_bytes(data->grp->prime));
-	wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
+	wpabuf_put_data(data->outbuf, element, 2 * prime_len);
+	wpabuf_put_data(data->outbuf, scalar, order_len);
 
 fin:
 	os_free(scalar);
 	os_free(element);
-	BN_clear_free(x);
-	BN_clear_free(y);
-	BN_clear_free(mask);
-	BN_clear_free(cofactor);
-	EC_POINT_clear_free(K);
-	EC_POINT_clear_free(point);
+	crypto_bignum_deinit(mask, 1);
+	crypto_bignum_deinit(cofactor, 1);
+	crypto_ec_point_deinit(K, 1);
+	crypto_ec_point_deinit(point, 1);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
 	else
@@ -569,12 +696,11 @@
 				 const struct wpabuf *reqData,
 				 const u8 *payload, size_t payload_len)
 {
-	BIGNUM *x = NULL, *y = NULL;
-	struct crypto_hash *hash;
+	struct crypto_hash *hash = NULL;
 	u32 cs;
 	u16 grp;
 	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
-	int offset;
+	size_t prime_len = 0, order_len = 0;
 
 	if (data->state != PWD_Confirm_Req) {
 		ret->ignore = TRUE;
@@ -588,6 +714,9 @@
 		goto fin;
 	}
 
+	prime_len = crypto_ec_prime_len(data->grp->group);
+	order_len = crypto_ec_order_len(data->grp->group);
+
 	/*
 	 * first build up the ciphersuite which is group | random_function |
 	 *	prf
@@ -600,9 +729,9 @@
 	ptr += sizeof(u8);
 	*ptr = EAP_PWD_DEFAULT_PRF;
 
-	/* each component of the cruft will be at most as big as the prime */
-	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
-	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+	/* each component of the point will be at most as big as the prime */
+	cruft = os_malloc(prime_len * 2);
+	if (!cruft) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
 			   "fail");
 		goto fin;
@@ -620,65 +749,41 @@
 	 * zero the memory each time because this is mod prime math and some
 	 * value may start with a few zeros and the previous one did not.
 	 */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
-	BN_bn2bin(data->k, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+	eap_pwd_h_update(hash, cruft, prime_len);
 
 	/* server element: x, y */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->server_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
+				   cruft, cruft + prime_len) != 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* server scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->server_scalar);
-	BN_bn2bin(data->server_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* my element: x, y */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->my_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+				   cruft + prime_len) != 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* my scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->my_scalar);
-	BN_bn2bin(data->my_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* the ciphersuite */
 	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
 	/* random function fin */
 	eap_pwd_h_final(hash, conf);
+	hash = NULL;
 
 	ptr = (u8 *) payload;
 	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
@@ -698,66 +803,43 @@
 		goto fin;
 
 	/* k */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
-	BN_bn2bin(data->k, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+	eap_pwd_h_update(hash, cruft, prime_len);
 
 	/* my element */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->my_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+				   cruft + prime_len) != 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* my scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->my_scalar);
-	BN_bn2bin(data->my_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* server element: x, y */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->server_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
+				   cruft, cruft + prime_len) != 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* server scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->server_scalar);
-	BN_bn2bin(data->server_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* the ciphersuite */
 	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
 	/* all done */
 	eap_pwd_h_final(hash, conf);
+	hash = NULL;
 
-	if (compute_keys(data->grp, data->bnctx, data->k,
+	if (compute_keys(data->grp, data->k,
 			 data->my_scalar, data->server_scalar, conf, ptr,
 			 &cs, data->msk, data->emsk, data->session_id) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
@@ -772,10 +854,7 @@
 	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
-	if (data->grp)
-		bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
-	BN_clear_free(x);
-	BN_clear_free(y);
+	bin_clear_free(cruft, prime_len * 2);
 	if (data->outbuf == NULL) {
 		ret->methodState = METHOD_DONE;
 		ret->decision = DECISION_FAIL;
@@ -783,6 +862,10 @@
 	} else {
 		eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
 	}
+
+	/* clean allocated memory */
+	if (hash)
+		eap_pwd_h_final(hash, conf);
 }
 
 
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index c0896aa..ba5eea9 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -1248,14 +1248,16 @@
 	return key;
 }
 
+
 static int eap_sim_get_error_code(void *priv)
 {
 	struct eap_sim_data *data = priv;
+	int current_data_error;
 
 	if (!data)
 		return NO_EAP_METHOD_ERROR;
 
-	int current_data_error = data->error_code;
+	current_data_error = data->error_code;
 
 	/* Now reset for next transaction */
 	data->error_code = NO_EAP_METHOD_ERROR;
@@ -1263,6 +1265,7 @@
 	return current_data_error;
 }
 
+
 int eap_peer_sim_register(void)
 {
 	struct eap_method *eap;
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index c1820a4..cb74702 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -173,14 +173,31 @@
 static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
 			    struct eap_method_ret *ret)
 {
+	const char *label;
+
 	wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
 
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
+	if (data->ssl.tls_out) {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Fragment(s) remaining");
+		return;
+	}
+
+	if (data->ssl.tls_v13) {
+		label = "EXPORTER_EAP_TLS_Key_Material";
+
+		/* A possible NewSessionTicket may be received before
+		 * EAP-Success, so need to allow it to be received. */
+		ret->methodState = METHOD_MAY_CONT;
+		ret->decision = DECISION_COND_SUCC;
+	} else {
+		label = "client EAP encryption";
+
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_UNCOND_SUCC;
+	}
 
 	eap_tls_free_key(data);
-	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
-						 "client EAP encryption",
+	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
 						 EAP_TLS_KEY_LEN +
 						 EAP_EMSK_LEN);
 	if (data->key_data) {
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index b3d4aba..0de1315 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -80,6 +80,10 @@
 		params->flags |= TLS_CONN_DISABLE_TLSv1_2;
 	if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
 		params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+	if (os_strstr(txt, "tls_disable_tlsv1_3=1"))
+		params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+	if (os_strstr(txt, "tls_disable_tlsv1_3=0"))
+		params->flags &= ~TLS_CONN_DISABLE_TLSv1_3;
 	if (os_strstr(txt, "tls_ext_cert_check=1"))
 		params->flags |= TLS_CONN_EXT_CERT_CHECK;
 	if (os_strstr(txt, "tls_ext_cert_check=0"))
@@ -159,6 +163,23 @@
 		 */
 		params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
 	}
+	if (data->eap_type == EAP_TYPE_FAST ||
+	    data->eap_type == EAP_TYPE_TTLS ||
+	    data->eap_type == EAP_TYPE_PEAP) {
+		/* The current EAP peer implementation is not yet ready for the
+		 * TLS v1.3 changes, so disable this by default for now. */
+		params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+	}
+	if (data->eap_type == EAP_TYPE_TLS) {
+		/* While the current EAP-TLS implementation is more or less
+		 * complete for TLS v1.3, there has been no interoperability
+		 * testing with other implementations, so disable for by default
+		 * for now until there has been chance to confirm that no
+		 * significant interoperability issues show up with TLS version
+		 * update.
+		 */
+		params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+	}
 	if (phase2) {
 		wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
 		eap_tls_params_from_conf2(params, config);
@@ -366,6 +387,13 @@
 	struct tls_random keys;
 	u8 *out;
 
+	if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+		*len = 64;
+		return eap_peer_tls_derive_key(sm, data,
+					       "EXPORTER_EAP_TLS_Session-Id",
+					       64);
+	}
+
 	if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) ||
 	    keys.client_random == NULL || keys.server_random == NULL)
 		return NULL;
@@ -669,6 +697,8 @@
 		 * the AS.
 		 */
 		int res = eap_tls_process_input(sm, data, in_data, out_data);
+		char buf[20];
+
 		if (res) {
 			/*
 			 * Input processing failed (res = -1) or more data is
@@ -681,6 +711,12 @@
 		 * The incoming message has been reassembled and processed. The
 		 * response was allocated into data->tls_out buffer.
 		 */
+
+		if (tls_get_version(data->ssl_ctx, data->conn,
+				    buf, sizeof(buf)) == 0) {
+			wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
+			data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
+		}
 	}
 
 	if (data->tls_out == NULL) {
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index acd2b78..306e6a9 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -73,6 +73,11 @@
 	 * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
 	 */
 	u8 eap_type;
+
+	/**
+	 * tls_v13 - Whether TLS v1.3 or newer is used
+	 */
+	int tls_v13;
 };
 
 
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index c67fa82..4fbc661 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -31,6 +31,8 @@
 	size_t password_len;
 	int password_hash; /* whether password is hashed with
 			    * nt_password_hash() */
+	u8 *salt;
+	size_t salt_len;
 	int phase2;
 	int force_version;
 	unsigned int remediation:1;
@@ -38,6 +40,7 @@
 	int ttls_auth; /* bitfield of
 			* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
 	struct hostapd_radius_attr *accept_attr;
+	u32 t_c_timestamp;
 };
 
 struct eap_eapol_interface {
@@ -149,6 +152,7 @@
 void eap_sm_pending_cb(struct eap_sm *sm);
 int eap_sm_method_pending(struct eap_sm *sm);
 const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
+const char * eap_get_serial_num(struct eap_sm *sm);
 struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
 void eap_server_clear_identity(struct eap_sm *sm);
 void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3d6f8d5..cf8a9f0 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -159,6 +159,7 @@
 	void *eap_method_priv;
 	u8 *identity;
 	size_t identity_len;
+	char *serial_num;
 	/* Whether Phase 2 method should validate identity match */
 	int require_identity_match;
 	int lastId; /* Identifier used in the last EAP-Packet */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 9706e25..38a1b5c 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -326,6 +326,9 @@
 		if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
 			sm->eap_if.eapReq = TRUE;
 	}
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
+		MAC2STR(sm->peer_addr));
 }
 
 
@@ -634,6 +637,9 @@
 	SM_ENTRY(EAP, TIMEOUT_FAILURE);
 
 	sm->eap_if.eapTimeout = TRUE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR,
+		MAC2STR(sm->peer_addr));
 }
 
 
@@ -1011,6 +1017,9 @@
 		if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
 			sm->eap_if.eapReq = TRUE;
 	}
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
+		MAC2STR(sm->peer_addr));
 }
 
 
@@ -1101,6 +1110,9 @@
 	SM_ENTRY(EAP, TIMEOUT_FAILURE2);
 
 	sm->eap_if.eapTimeout = TRUE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR,
+		MAC2STR(sm->peer_addr));
 }
 
 
@@ -1110,6 +1122,9 @@
 
 	eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
 	sm->eap_if.eapFail = TRUE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
+		MAC2STR(sm->peer_addr));
 }
 
 
@@ -1136,6 +1151,9 @@
 	 * started properly.
 	 */
 	sm->start_reauth = TRUE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
+		MAC2STR(sm->peer_addr));
 }
 
 
@@ -1802,6 +1820,8 @@
 		return;
 	bin_clear_free(user->password, user->password_len);
 	user->password = NULL;
+	bin_clear_free(user->salt, user->salt_len);
+	user->salt = NULL;
 	os_free(user);
 }
 
@@ -1900,6 +1920,7 @@
 	wpabuf_free(sm->lastReqData);
 	wpabuf_free(sm->eap_if.eapRespData);
 	os_free(sm->identity);
+	os_free(sm->serial_num);
 	os_free(sm->pac_opaque_encr_key);
 	os_free(sm->eap_fast_a_id);
 	os_free(sm->eap_fast_a_id_info);
@@ -1971,6 +1992,17 @@
 }
 
 
+/**
+ * eap_get_serial_num - Get the serial number of user certificate
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to the serial number or %NULL if not available
+ */
+const char * eap_get_serial_num(struct eap_sm *sm)
+{
+	return sm->serial_num;
+}
+
+
 void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len)
 {
 #ifdef CONFIG_ERP
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index fa0342f..a63f820 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -1516,7 +1516,7 @@
 		if (eap_fast_process_phase1(sm, data))
 			break;
 
-		/* fall through to PHASE2_START */
+		/* fall through */
 	case PHASE2_START:
 		eap_fast_process_phase2_start(sm, data);
 		break;
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 1833419..32e6872 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -223,7 +223,7 @@
 			}
 			data->out_used = 0;
 		}
-		/* pass through */
+		/* fall through */
 	case WAIT_FRAG_ACK:
 		return eap_ikev2_build_msg(data, id);
 	case FRAG_ACK:
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 68f0af9..d0fa54a 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -11,6 +11,7 @@
 #include "common.h"
 #include "crypto/sha256.h"
 #include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_pwd_common.h"
 
@@ -26,8 +27,11 @@
 	u8 *password;
 	size_t password_len;
 	int password_hash;
+	u8 *salt;
+	size_t salt_len;
 	u32 token;
 	u16 group_num;
+	u8 password_prep;
 	EAP_PWD_group *grp;
 
 	struct wpabuf *inbuf;
@@ -36,20 +40,18 @@
 	size_t out_frag_pos;
 	size_t mtu;
 
-	BIGNUM *k;
-	BIGNUM *private_value;
-	BIGNUM *peer_scalar;
-	BIGNUM *my_scalar;
-	EC_POINT *my_element;
-	EC_POINT *peer_element;
+	struct crypto_bignum *k;
+	struct crypto_bignum *private_value;
+	struct crypto_bignum *peer_scalar;
+	struct crypto_bignum *my_scalar;
+	struct crypto_ec_point *my_element;
+	struct crypto_ec_point *peer_element;
 
 	u8 my_confirm[SHA256_MAC_LEN];
 
 	u8 msk[EAP_MSK_LEN];
 	u8 emsk[EAP_EMSK_LEN];
 	u8 session_id[1 + SHA256_MAC_LEN];
-
-	BN_CTX *bnctx;
 };
 
 
@@ -116,13 +118,17 @@
 	os_memcpy(data->password, sm->user->password, data->password_len);
 	data->password_hash = sm->user->password_hash;
 
-	data->bnctx = BN_CTX_new();
-	if (data->bnctx == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
-		bin_clear_free(data->password, data->password_len);
-		bin_clear_free(data->id_server, data->id_server_len);
-		os_free(data);
-		return NULL;
+	data->salt_len = sm->user->salt_len;
+	if (data->salt_len) {
+		data->salt = os_memdup(sm->user->salt, sm->user->salt_len);
+		if (!data->salt) {
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd: Memory allocation of salt failed");
+			bin_clear_free(data->id_server, data->id_server_len);
+			bin_clear_free(data->password, data->password_len);
+			os_free(data);
+			return NULL;
+		}
 	}
 
 	data->in_frag_pos = data->out_frag_pos = 0;
@@ -138,21 +144,19 @@
 {
 	struct eap_pwd_data *data = priv;
 
-	BN_clear_free(data->private_value);
-	BN_clear_free(data->peer_scalar);
-	BN_clear_free(data->my_scalar);
-	BN_clear_free(data->k);
-	BN_CTX_free(data->bnctx);
-	EC_POINT_clear_free(data->my_element);
-	EC_POINT_clear_free(data->peer_element);
+	crypto_bignum_deinit(data->private_value, 1);
+	crypto_bignum_deinit(data->peer_scalar, 1);
+	crypto_bignum_deinit(data->my_scalar, 1);
+	crypto_bignum_deinit(data->k, 1);
+	crypto_ec_point_deinit(data->my_element, 1);
+	crypto_ec_point_deinit(data->peer_element, 1);
 	bin_clear_free(data->id_peer, data->id_peer_len);
 	bin_clear_free(data->id_server, data->id_server_len);
 	bin_clear_free(data->password, data->password_len);
+	bin_clear_free(data->salt, data->salt_len);
 	if (data->grp) {
-		EC_GROUP_free(data->grp->group);
-		EC_POINT_clear_free(data->grp->pwe);
-		BN_clear_free(data->grp->order);
-		BN_clear_free(data->grp->prime);
+		crypto_ec_deinit(data->grp->group);
+		crypto_ec_point_deinit(data->grp->pwe, 1);
 		os_free(data->grp);
 	}
 	wpabuf_free(data->inbuf);
@@ -185,12 +189,45 @@
 		return;
 	}
 
+	wpa_hexdump_key(MSG_DEBUG, "EAP-pwd (server): password",
+			data->password, data->password_len);
+	if (data->salt_len)
+		wpa_hexdump(MSG_DEBUG, "EAP-pwd (server): salt",
+			    data->salt, data->salt_len);
+
+	/*
+	 * If this is a salted password then figure out how it was hashed
+	 * based on the length.
+	 */
+	if (data->salt_len) {
+		switch (data->password_len) {
+		case 20:
+			data->password_prep = EAP_PWD_PREP_SSHA1;
+			break;
+		case 32:
+			data->password_prep = EAP_PWD_PREP_SSHA256;
+			break;
+		case 64:
+			data->password_prep = EAP_PWD_PREP_SSHA512;
+			break;
+		default:
+			wpa_printf(MSG_INFO,
+				   "EAP-pwd (server): bad size %d for salted password",
+				   (int) data->password_len);
+			eap_pwd_state(data, FAILURE);
+			return;
+		}
+	} else {
+		/* Otherwise, figure out whether it's MS hashed or plain */
+		data->password_prep = data->password_hash ? EAP_PWD_PREP_MS :
+			EAP_PWD_PREP_NONE;
+	}
+
 	wpabuf_put_be16(data->outbuf, data->group_num);
 	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
 	wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
 	wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
-	wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS :
-		      EAP_PWD_PREP_NONE);
+	wpabuf_put_u8(data->outbuf, data->password_prep);
 	wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
 }
 
@@ -198,9 +235,9 @@
 static void eap_pwd_build_commit_req(struct eap_sm *sm,
 				     struct eap_pwd_data *data, u8 id)
 {
-	BIGNUM *mask = NULL, *x = NULL, *y = NULL;
+	struct crypto_bignum *mask = NULL;
 	u8 *scalar = NULL, *element = NULL;
-	u16 offset;
+	size_t prime_len, order_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
 	/*
@@ -210,93 +247,82 @@
 	if (data->out_frag_pos)
 		return;
 
-	if (((data->private_value = BN_new()) == NULL) ||
-	    ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
-	    ((data->my_scalar = BN_new()) == NULL) ||
-	    ((mask = BN_new()) == NULL)) {
+	prime_len = crypto_ec_prime_len(data->grp->group);
+	order_len = crypto_ec_order_len(data->grp->group);
+
+	data->private_value = crypto_bignum_init();
+	data->my_element = crypto_ec_point_init(data->grp->group);
+	data->my_scalar = crypto_bignum_init();
+	mask = crypto_bignum_init();
+	if (!data->private_value || !data->my_element || !data->my_scalar ||
+	    !mask) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
 			   "fail");
 		goto fin;
 	}
 
-	if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
-	    BN_rand_range(mask, data->grp->order) != 1 ||
-	    BN_add(data->my_scalar, data->private_value, mask) != 1 ||
-	    BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
-		   data->bnctx) != 1) {
+	if (crypto_bignum_rand(data->private_value,
+			       crypto_ec_get_order(data->grp->group)) < 0 ||
+	    crypto_bignum_rand(mask,
+			       crypto_ec_get_order(data->grp->group)) < 0 ||
+	    crypto_bignum_add(data->private_value, mask, data->my_scalar) < 0 ||
+	    crypto_bignum_mod(data->my_scalar,
+			      crypto_ec_get_order(data->grp->group),
+			      data->my_scalar) < 0) {
 		wpa_printf(MSG_INFO,
 			   "EAP-pwd (server): unable to get randomness");
 		goto fin;
 	}
 
-	if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
-			  data->grp->pwe, mask, data->bnctx)) {
+	if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+				data->my_element) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
 			   "fail");
 		eap_pwd_state(data, FAILURE);
 		goto fin;
 	}
 
-	if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
-	{
+	if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
 			   "fail");
 		goto fin;
 	}
-	BN_clear_free(mask);
 
-	if (((x = BN_new()) == NULL) ||
-	    ((y = BN_new()) == NULL)) {
-		wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
-			   "fail");
+	scalar = os_malloc(order_len);
+	element = os_malloc(prime_len * 2);
+	if (!scalar || !element) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
 		goto fin;
 	}
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->my_element, x, y,
-						 data->bnctx)) {
+
+	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
+				   element + prime_len) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
 			   "fail");
 		goto fin;
 	}
 
-	if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
-	    ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
-	     NULL)) {
-		wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
-		goto fin;
-	}
+	crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
 
-	/*
-	 * bignums occupy as little memory as possible so one that is
-	 * sufficiently smaller than the prime or order might need pre-pending
-	 * with zeros.
-	 */
-	os_memset(scalar, 0, BN_num_bytes(data->grp->order));
-	os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->my_scalar);
-	BN_bn2bin(data->my_scalar, scalar + offset);
-
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, element + offset);
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
-
-	data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
-				    BN_num_bytes(data->grp->order));
+	data->outbuf = wpabuf_alloc(2 * prime_len + order_len +
+				    (data->salt ? 1 + data->salt_len : 0));
 	if (data->outbuf == NULL)
 		goto fin;
 
+	/* If we're doing salted password prep, add the salt */
+	if (data->salt_len) {
+		wpabuf_put_u8(data->outbuf, data->salt_len);
+		wpabuf_put_data(data->outbuf, data->salt, data->salt_len);
+	}
+
 	/* We send the element as (x,y) followed by the scalar */
-	wpabuf_put_data(data->outbuf, element,
-			2 * BN_num_bytes(data->grp->prime));
-	wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
+	wpabuf_put_data(data->outbuf, element, 2 * prime_len);
+	wpabuf_put_data(data->outbuf, scalar, order_len);
 
 fin:
+	crypto_bignum_deinit(mask, 1);
 	os_free(scalar);
 	os_free(element);
-	BN_clear_free(x);
-	BN_clear_free(y);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
 }
@@ -305,11 +331,10 @@
 static void eap_pwd_build_confirm_req(struct eap_sm *sm,
 				      struct eap_pwd_data *data, u8 id)
 {
-	BIGNUM *x = NULL, *y = NULL;
 	struct crypto_hash *hash;
 	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
 	u16 grp;
-	int offset;
+	size_t prime_len, order_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
 	/*
@@ -319,9 +344,12 @@
 	if (data->out_frag_pos)
 		return;
 
+	prime_len = crypto_ec_prime_len(data->grp->group);
+	order_len = crypto_ec_order_len(data->grp->group);
+
 	/* Each component of the cruft will be at most as big as the prime */
-	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
-	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+	cruft = os_malloc(prime_len * 2);
+	if (!cruft) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
 			   "fail");
 		goto fin;
@@ -341,64 +369,38 @@
 	 *
 	 * First is k
 	 */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
-	BN_bn2bin(data->k, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+	eap_pwd_h_update(hash, cruft, prime_len);
 
 	/* server element: x, y */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->my_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+				   cruft + prime_len) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* server scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->my_scalar);
-	BN_bn2bin(data->my_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* peer element: x, y */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->peer_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
+				   cruft + prime_len) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* peer scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->peer_scalar);
-	BN_bn2bin(data->peer_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* ciphersuite */
 	grp = htons(data->group_num);
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, prime_len);
 	ptr = cruft;
 	os_memcpy(ptr, &grp, sizeof(u16));
 	ptr += sizeof(u16);
@@ -419,9 +421,7 @@
 	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
-	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
-	BN_clear_free(x);
-	BN_clear_free(y);
+	bin_clear_free(cruft, prime_len * 2);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
 }
@@ -603,12 +603,15 @@
 	    (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
 	    (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
 	    (id->prf != EAP_PWD_DEFAULT_PRF) ||
-	    id->prep !=
-	    data->password_hash ? EAP_PWD_PREP_MS : EAP_PWD_PREP_NONE) {
+	    (id->prep != data->password_prep)) {
 		wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
 		eap_pwd_state(data, FAILURE);
 		return;
 	}
+	if (data->id_peer || data->grp) {
+		wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
+		return;
+	}
 	data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
 	if (data->id_peer == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
@@ -619,14 +622,19 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
 			  data->id_peer, data->id_peer_len);
 
-	data->grp = os_zalloc(sizeof(EAP_PWD_group));
+	data->grp = get_eap_pwd_group(data->group_num);
 	if (data->grp == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
 			   "group");
 		return;
 	}
 
-	if (data->password_hash) {
+	/*
+	 * If it's PREP_MS then hash the password again, otherwise regardless
+	 * of the prep the client is doing, the password we have is the one to
+	 * use to generate the password element.
+	 */
+	if (data->password_prep == EAP_PWD_PREP_MS) {
 		res = hash_nt_password_hash(data->password, pwhashhash);
 		if (res)
 			return;
@@ -649,7 +657,7 @@
 		return;
 	}
 	wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
-		   BN_num_bits(data->grp->prime));
+		   (int) crypto_ec_prime_len_bits(data->grp->group));
 
 	eap_pwd_state(data, PWD_Commit_Req);
 }
@@ -659,16 +667,16 @@
 eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
 			    const u8 *payload, size_t payload_len)
 {
-	u8 *ptr;
-	BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
-	EC_POINT *K = NULL, *point = NULL;
+	const u8 *ptr;
+	struct crypto_bignum *cofactor = NULL;
+	struct crypto_ec_point *K = NULL, *point = NULL;
 	int res = 0;
 	size_t prime_len, order_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
 
-	prime_len = BN_num_bytes(data->grp->prime);
-	order_len = BN_num_bytes(data->grp->order);
+	prime_len = crypto_ec_prime_len(data->grp->group);
+	order_len = crypto_ec_order_len(data->grp->group);
 
 	if (payload_len != 2 * prime_len + order_len) {
 		wpa_printf(MSG_INFO,
@@ -678,49 +686,47 @@
 		goto fin;
 	}
 
-	if (((data->peer_scalar = BN_new()) == NULL) ||
-	    ((data->k = BN_new()) == NULL) ||
-	    ((cofactor = BN_new()) == NULL) ||
-	    ((x = BN_new()) == NULL) ||
-	    ((y = BN_new()) == NULL) ||
-	    ((point = EC_POINT_new(data->grp->group)) == NULL) ||
-	    ((K = EC_POINT_new(data->grp->group)) == NULL) ||
-	    ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
+	data->k = crypto_bignum_init();
+	cofactor = crypto_bignum_init();
+	point = crypto_ec_point_init(data->grp->group);
+	K = crypto_ec_point_init(data->grp->group);
+	if (!data->k || !cofactor || !point || !K) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
 			   "fail");
 		goto fin;
 	}
 
-	if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
+	if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
 			   "cofactor for curve");
 		goto fin;
 	}
 
 	/* element, x then y, followed by scalar */
-	ptr = (u8 *) payload;
-	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
-	ptr += BN_num_bytes(data->grp->prime);
-	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
-	ptr += BN_num_bytes(data->grp->prime);
-	BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
-	if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
-						 data->peer_element, x, y,
-						 data->bnctx)) {
+	ptr = payload;
+	data->peer_element = crypto_ec_point_from_bin(data->grp->group, ptr);
+	if (!data->peer_element) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
 			   "fail");
 		goto fin;
 	}
+	ptr += prime_len * 2;
+	data->peer_scalar = crypto_bignum_init_set(ptr, order_len);
+	if (!data->peer_scalar) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+			   "fail");
+		goto fin;
+	}
 
 	/* check to ensure peer's element is not in a small sub-group */
-	if (BN_cmp(cofactor, BN_value_one())) {
-		if (!EC_POINT_mul(data->grp->group, point, NULL,
-				  data->peer_element, cofactor, NULL)) {
+	if (!crypto_bignum_is_one(cofactor)) {
+		if (crypto_ec_point_mul(data->grp->group, data->peer_element,
+					cofactor, point) != 0) {
 			wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
 				   "multiply peer element by order");
 			goto fin;
 		}
-		if (EC_POINT_is_at_infinity(data->grp->group, point)) {
+		if (crypto_ec_point_is_at_infinity(data->grp->group, point)) {
 			wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
 				   "is at infinity!\n");
 			goto fin;
@@ -728,21 +734,21 @@
 	}
 
 	/* compute the shared key, k */
-	if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
-			   data->peer_scalar, data->bnctx)) ||
-	    (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
-			   data->bnctx)) ||
-	    (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
-			   data->bnctx))) {
+	if ((crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+				 data->peer_scalar, K) < 0) ||
+	    (crypto_ec_point_add(data->grp->group, K, data->peer_element,
+				 K) < 0) ||
+	    (crypto_ec_point_mul(data->grp->group, K, data->private_value,
+				 K) < 0)) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
 			   "fail");
 		goto fin;
 	}
 
 	/* ensure that the shared key isn't in a small sub-group */
-	if (BN_cmp(cofactor, BN_value_one())) {
-		if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
-				  NULL)) {
+	if (!crypto_bignum_is_one(cofactor)) {
+		if (crypto_ec_point_mul(data->grp->group, K, cofactor,
+					K) != 0) {
 			wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
 				   "multiply shared key point by order!\n");
 			goto fin;
@@ -755,13 +761,12 @@
 	 * never going to happen it is a simple and safe check "just to be
 	 * sure" so let's be safe.
 	 */
-	if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+	if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
 			   "at infinity");
 		goto fin;
 	}
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
-						 NULL, data->bnctx)) {
+	if (crypto_ec_point_x(data->grp->group, K, data->k)) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
 			   "shared secret from secret point");
 		goto fin;
@@ -769,11 +774,9 @@
 	res = 1;
 
 fin:
-	EC_POINT_clear_free(K);
-	EC_POINT_clear_free(point);
-	BN_clear_free(cofactor);
-	BN_clear_free(x);
-	BN_clear_free(y);
+	crypto_ec_point_deinit(K, 1);
+	crypto_ec_point_deinit(point, 1);
+	crypto_bignum_deinit(cofactor, 1);
 
 	if (res)
 		eap_pwd_state(data, PWD_Confirm_Req);
@@ -786,12 +789,14 @@
 eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
 			     const u8 *payload, size_t payload_len)
 {
-	BIGNUM *x = NULL, *y = NULL;
 	struct crypto_hash *hash;
 	u32 cs;
 	u16 grp;
 	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
-	int offset;
+	size_t prime_len, order_len;
+
+	prime_len = crypto_ec_prime_len(data->grp->group);
+	order_len = crypto_ec_order_len(data->grp->group);
 
 	if (payload_len != SHA256_MAC_LEN) {
 		wpa_printf(MSG_INFO,
@@ -810,8 +815,8 @@
 	*ptr = EAP_PWD_DEFAULT_PRF;
 
 	/* each component of the cruft will be at most as big as the prime */
-	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
-	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+	cruft = os_malloc(prime_len * 2);
+	if (!cruft) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
 		goto fin;
 	}
@@ -825,62 +830,36 @@
 		goto fin;
 
 	/* k */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
-	BN_bn2bin(data->k, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+	eap_pwd_h_update(hash, cruft, prime_len);
 
 	/* peer element: x, y */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->peer_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
+				   cruft + prime_len) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* peer scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->peer_scalar);
-	BN_bn2bin(data->peer_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* server element: x, y */
-	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
-						 data->my_element, x, y,
-						 data->bnctx)) {
+	if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+				   cruft + prime_len) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
 			   "assignment fail");
 		goto fin;
 	}
-
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
-	BN_bn2bin(x, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
-	BN_bn2bin(y, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, prime_len * 2);
 
 	/* server scalar */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	offset = BN_num_bytes(data->grp->order) -
-		BN_num_bytes(data->my_scalar);
-	BN_bn2bin(data->my_scalar, cruft + offset);
-	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+	crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+	eap_pwd_h_update(hash, cruft, order_len);
 
 	/* ciphersuite */
-	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
 	/* all done */
@@ -894,7 +873,7 @@
 	}
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
-	if (compute_keys(data->grp, data->bnctx, data->k,
+	if (compute_keys(data->grp, data->k,
 			 data->peer_scalar, data->my_scalar, conf,
 			 data->my_confirm, &cs, data->msk, data->emsk,
 			 data->session_id) < 0)
@@ -903,9 +882,7 @@
 		eap_pwd_state(data, SUCCESS);
 
 fin:
-	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
-	BN_clear_free(x);
-	BN_clear_free(y);
+	bin_clear_free(cruft, prime_len * 2);
 }
 
 
@@ -1126,4 +1103,3 @@
 
 	return eap_server_method_register(eap);
 }
-
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 7249858..8b9e53c 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -302,17 +302,22 @@
 {
 	struct eap_tls_data *data = priv;
 	u8 *eapKeyData;
+	const char *label;
 
 	if (data->state != SUCCESS)
 		return NULL;
 
-	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "client EAP encryption",
-					       EAP_TLS_KEY_LEN);
+	if (data->ssl.tls_v13)
+		label = "EXPORTER_EAP_TLS_Key_Material";
+	else
+		label = "client EAP encryption";
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
+					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 	if (eapKeyData) {
 		*len = EAP_TLS_KEY_LEN;
 		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
 			    eapKeyData, EAP_TLS_KEY_LEN);
+		os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
 	}
@@ -325,12 +330,16 @@
 {
 	struct eap_tls_data *data = priv;
 	u8 *eapKeyData, *emsk;
+	const char *label;
 
 	if (data->state != SUCCESS)
 		return NULL;
 
-	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "client EAP encryption",
+	if (data->ssl.tls_v13)
+		label = "EXPORTER_EAP_TLS_Key_Material";
+	else
+		label = "client EAP encryption";
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 	if (eapKeyData) {
 		emsk = os_malloc(EAP_EMSK_LEN);
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 3c9027b..0ae7867 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -107,7 +107,7 @@
 
 
 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
-			       char *label, size_t len)
+			       const char *label, size_t len)
 {
 	u8 *out;
 
@@ -145,6 +145,13 @@
 	struct tls_random keys;
 	u8 *out;
 
+	if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+		*len = 64;
+		return eap_server_tls_derive_key(sm, data,
+						 "EXPORTER_EAP_TLS_Session-Id",
+						 64);
+	}
+
 	if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
 		return NULL;
 
@@ -305,6 +312,8 @@
 
 int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
 {
+	char buf[20];
+
 	if (data->tls_out) {
 		/* This should not happen.. */
 		wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
@@ -327,6 +336,16 @@
 		return -1;
 	}
 
+	if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
+		wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
+		data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
+	}
+
+	if (!sm->serial_num &&
+	    tls_connection_established(sm->ssl_ctx, data->conn))
+		sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
+								data->conn);
+
 	return 0;
 }
 
@@ -373,7 +392,7 @@
 	if (data->tls_in &&
 	    eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
 		return -1;
-		
+
 	if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
 		if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
 						    *pos, end - *pos) < 0)
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 7d9d285..4a5cb98 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -257,7 +257,7 @@
 			}
 			data->out_used = 0;
 		}
-		/* pass through */
+		/* fall through */
 	case WAIT_FRAG_ACK:
 		return eap_wsc_build_msg(data, id);
 	case FRAG_ACK:
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index dc943eb..31f6e72 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -50,6 +50,11 @@
 
 	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
 	struct wpabuf tmpbuf;
+
+	/**
+	 * tls_v13 - Whether TLS v1.3 or newer is used
+	 */
+	int tls_v13;
 };
 
 
@@ -73,7 +78,7 @@
 			    int verify_peer, int eap_type);
 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
-			       char *label, size_t len);
+			       const char *label, size_t len);
 u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
 				      struct eap_ssl_data *data, u8 eap_type,
 				      size_t *len);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index cb463ef..9f029b0 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -503,10 +503,14 @@
 			session_id = eap_proxy_get_eap_session_id(
 				sm->eap_proxy, &session_id_len);
 			emsk = eap_proxy_get_emsk(sm->eap_proxy, &emsk_len);
-			if (sm->config->erp && session_id && emsk)
+			if (sm->config->erp && session_id && emsk) {
 				eap_peer_erp_init(sm->eap, session_id,
 						  session_id_len, emsk,
 						  emsk_len);
+			} else {
+				os_free(session_id);
+				bin_clear_free(emsk, emsk_len);
+			}
 		}
 		return;
 	}
@@ -2014,6 +2018,7 @@
 		sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
 }
 
+
 static void eapol_sm_notify_eap_error(void *ctx, int error_code)
 {
 	struct eapol_sm *sm = ctx;
@@ -2022,6 +2027,7 @@
 		sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
 }
 
+
 #ifdef CONFIG_EAP_PROXY
 
 static void eapol_sm_eap_proxy_cb(void *ctx)
diff --git a/src/fst/fst_ctrl_aux.h b/src/fst/fst_ctrl_aux.h
index e2133f5..0aff5d0 100644
--- a/src/fst/fst_ctrl_aux.h
+++ b/src/fst/fst_ctrl_aux.h
@@ -35,6 +35,17 @@
 					 *  more info */
 };
 
+enum fst_reason {
+	REASON_TEARDOWN,
+	REASON_SETUP,
+	REASON_SWITCH,
+	REASON_STT,
+	REASON_REJECT,
+	REASON_ERROR_PARAMS,
+	REASON_RESET,
+	REASON_DETACH_IFACE,
+};
+
 enum fst_initiator {
 	FST_INITIATOR_UNDEFINED,
 	FST_INITIATOR_LOCAL,
@@ -57,16 +68,7 @@
 		enum fst_session_state new_state;
 		union fst_session_state_switch_extra {
 			struct {
-				enum fst_reason {
-					REASON_TEARDOWN,
-					REASON_SETUP,
-					REASON_SWITCH,
-					REASON_STT,
-					REASON_REJECT,
-					REASON_ERROR_PARAMS,
-					REASON_RESET,
-					REASON_DETACH_IFACE,
-				} reason;
+				enum fst_reason reason;
 				u8 reject_code; /* REASON_REJECT */
 				/* REASON_SWITCH,
 				 * REASON_TEARDOWN,
diff --git a/src/fst/fst_ctrl_iface.c b/src/fst/fst_ctrl_iface.c
index 7820e58..7df3362 100644
--- a/src/fst/fst_ctrl_iface.c
+++ b/src/fst/fst_ctrl_iface.c
@@ -49,7 +49,7 @@
 		if (ss->extra.to_initial.reject_code != WLAN_STATUS_SUCCESS)
 			os_snprintf(reject_str, sizeof(reject_str), "%u",
 				    ss->extra.to_initial.reject_code);
-		/* no break */
+		/* fall through */
 	case REASON_TEARDOWN:
 	case REASON_SWITCH:
 		switch (ss->extra.to_initial.initiator) {
diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h
index 2a45245..5387177 100644
--- a/src/l2_packet/l2_packet.h
+++ b/src/l2_packet/l2_packet.h
@@ -42,6 +42,7 @@
 enum l2_packet_filter_type {
 	L2_PACKET_FILTER_DHCP,
 	L2_PACKET_FILTER_NDISC,
+	L2_PACKET_FILTER_PKTTYPE,
 };
 
 /**
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 65b4906..291c9dd 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -84,6 +84,26 @@
 	.filter = ndisc_sock_filter_insns,
 };
 
+/* drop packet if skb->pkt_type is PACKET_OTHERHOST (0x03). Generated by:
+ * $ bpfc - <<EOF
+ * > ldb #type
+ * > jeq #0x03, drop
+ * > pass: ret #-1
+ * > drop: ret #0
+ * > EOF
+ */
+static struct sock_filter pkt_type_filter_insns[] = {
+	{ 0x30, 0, 0, 0xfffff004 },
+	{ 0x15, 1, 0, 0x00000003 },
+	{ 0x6, 0, 0, 0xffffffff },
+	{ 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog pkt_type_sock_filter = {
+	.len = ARRAY_SIZE(pkt_type_filter_insns),
+	.filter = pkt_type_filter_insns,
+};
+
 
 int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
 {
@@ -471,6 +491,9 @@
 	case L2_PACKET_FILTER_NDISC:
 		sock_filter = &ndisc_sock_filter;
 		break;
+	case L2_PACKET_FILTER_PKTTYPE:
+		sock_filter = &pkt_type_sock_filter;
+		break;
 	default:
 		return -1;
 	}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 1a31ef2..585b4a0 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1797,7 +1797,12 @@
 	}
 	p2p->ssid_set = 0;
 
-	p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+	if (p2p->passphrase_set) {
+		os_memcpy(params->passphrase, p2p->passphrase, os_strlen(p2p->passphrase));
+	} else {
+		p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+	}
+	p2p->passphrase_set = 0;
 	return 0;
 }
 
@@ -3889,6 +3894,19 @@
 	if (p2p->in_listen)
 		return 0; /* Internal timeout will trigger the next step */
 
+	if (p2p->state == P2P_WAIT_PEER_CONNECT && p2p->go_neg_peer &&
+	    p2p->pending_listen_freq) {
+		/*
+		 * Better wait a bit if the driver is unable to start
+		 * offchannel operation for some reason to continue with
+		 * P2P_WAIT_PEER_(IDLE/CONNECT) state transitions.
+		 */
+		p2p_dbg(p2p,
+			"Listen operation did not seem to start - delay idle phase to avoid busy loop");
+		p2p_set_timeout(p2p, 0, 100000);
+		return 1;
+	}
+
 	if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
 		if (p2p->go_neg_peer->connect_reqs >= 120) {
 			p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 6a4d751..a73d99e 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -11,6 +11,7 @@
 
 #include "utils/list.h"
 #include "p2p.h"
+#include "ap/ap_config.h"
 
 #define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
 
@@ -358,6 +359,16 @@
 	int ssid_set;
 
 	/**
+	 * passphrase - WPA2-Personal passphrase for GO Negotiation (if local end will be GO)
+	 */
+	char passphrase[MAX_PASSPHRASE_LEN + 1];
+
+	/**
+	 * passphrase_set - Whether passphrase is already set for GO Negotiation
+	 */
+	int passphrase_set;
+
+	/**
 	 * Regulatory class for own operational channel
 	 */
 	u8 op_reg_class;
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index cad0292..cda23fc 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -45,6 +45,14 @@
 		.sak_len = DEFAULT_SA_KEY_LEN,
 		.index = 0,
 	},
+	/* GCM-AES-256 */
+	{
+		.id = CS_ID_GCM_AES_256,
+		.name = CS_NAME_GCM_AES_256,
+		.capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
+		.sak_len = 32,
+		.index = 1 /* index */
+	},
 };
 #define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
 #define DEFAULT_CS_INDEX  0
@@ -245,13 +253,15 @@
  * ieee802_1x_kay_get_participant -
  */
 static struct ieee802_1x_mka_participant *
-ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn)
+ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn,
+			       size_t len)
 {
 	struct ieee802_1x_mka_participant *participant;
 
 	dl_list_for_each(participant, &kay->participant_list,
 			 struct ieee802_1x_mka_participant, list) {
-		if (os_memcmp(participant->ckn.name, ckn,
+		if (participant->ckn.len == len &&
+		    os_memcmp(participant->ckn.name, ckn,
 			      participant->ckn.len) == 0)
 			return participant;
 	}
@@ -748,6 +758,8 @@
 	struct ieee802_1x_mka_participant *participant;
 	const struct ieee802_1x_mka_basic_body *body;
 	struct ieee802_1x_kay_peer *peer;
+	size_t ckn_len;
+	size_t body_len;
 
 	body = (const struct ieee802_1x_mka_basic_body *) mka_msg;
 
@@ -761,7 +773,15 @@
 		return NULL;
 	}
 
-	participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+	body_len = get_mka_param_body_len(body);
+	if (body_len < sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN) {
+		wpa_printf(MSG_DEBUG, "KaY: Too small body length %zu",
+			   body_len);
+		return NULL;
+	}
+	ckn_len = body_len -
+	    (sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
+	participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
 	if (!participant) {
 		wpa_printf(MSG_DEBUG, "Peer is not included in my CA");
 		return NULL;
@@ -1331,8 +1351,8 @@
 		}
 	}
 
-	/* check old key is valid */
-	if (body->otx || body->orx) {
+	/* check old key is valid (but only if we remember our old key) */
+	if (participant->oki.kn != 0 && (body->otx || body->orx)) {
 		if (os_memcmp(participant->oki.mi, body->osrv_mi,
 			      sizeof(participant->oki.mi)) != 0 ||
 		    be_to_host32(body->okn) != participant->oki.kn ||
@@ -1614,7 +1634,8 @@
 		os_free(unwrap_sak);
 		return -1;
 	}
-	wpa_hexdump(MSG_DEBUG, "\tAES Key Unwrap of SAK:", unwrap_sak, sak_len);
+	wpa_hexdump_key(MSG_DEBUG, "\tAES Key Unwrap of SAK:",
+			unwrap_sak, sak_len);
 
 	sa_key = os_zalloc(sizeof(*sa_key));
 	if (!sa_key) {
@@ -2005,7 +2026,7 @@
 		wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
 		goto fail;
 	}
-	wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
+	wpa_hexdump_key(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
 	os_free(context);
 	context = NULL;
 
@@ -2081,6 +2102,7 @@
 	struct ieee802_1x_kay_peer *key_server = NULL;
 	struct ieee802_1x_kay *kay = participant->kay;
 	Boolean i_is_key_server;
+	int priority_comparison;
 
 	if (participant->is_obliged_key_server) {
 		participant->new_sak = TRUE;
@@ -2111,8 +2133,14 @@
 
 		tmp.key_server_priority = kay->actor_priority;
 		os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
-		if (compare_priorities(&tmp, key_server) < 0)
+		priority_comparison = compare_priorities(&tmp, key_server);
+		if (priority_comparison < 0) {
 			i_is_key_server = TRUE;
+		} else if (priority_comparison == 0) {
+			wpa_printf(MSG_WARNING,
+				   "KaY: Cannot elect key server between me and peer, duplicate MAC detected");
+			key_server = NULL;
+		}
 	} else if (participant->can_be_key_server) {
 		i_is_key_server = TRUE;
 	}
@@ -2387,7 +2415,7 @@
 			participant->orx = FALSE;
 			participant->is_key_server = FALSE;
 			participant->is_elected = FALSE;
-			kay->authenticated = TRUE;
+			kay->authenticated = FALSE;
 			kay->secured = FALSE;
 			kay->failed = FALSE;
 			kay->ltx_kn = 0;
@@ -2404,7 +2432,7 @@
 				ieee802_1x_delete_transmit_sa(kay, txsa);
 			}
 
-			ieee802_1x_cp_connect_authenticated(kay->cp);
+			ieee802_1x_cp_connect_pending(kay->cp);
 			ieee802_1x_cp_sm_step(kay->cp);
 		} else {
 			ieee802_1x_kay_elect_key_server(participant);
@@ -2856,6 +2884,7 @@
 	size_t mka_msg_len;
 	struct ieee802_1x_mka_participant *participant;
 	size_t body_len;
+	size_t ckn_len;
 	u8 icv[MAX_ICV_LEN];
 	u8 *msg_icv;
 
@@ -2895,8 +2924,22 @@
 		return -1;
 	}
 
+	if (body_len < sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN) {
+		wpa_printf(MSG_DEBUG, "KaY: Too small body length %zu",
+			   body_len);
+		return -1;
+	}
+	ckn_len = body_len -
+		(sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
+	if (ckn_len < 1 || ckn_len > MAX_CKN_LEN) {
+		wpa_printf(MSG_ERROR,
+			   "KaY: Received EAPOL-MKA CKN Length (%zu bytes) is out of range (<= %u bytes)",
+			   ckn_len, MAX_CKN_LEN);
+		return -1;
+	}
+
 	/* CKN should be owned by I */
-	participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+	participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
 	if (!participant) {
 		wpa_printf(MSG_DEBUG, "CKN is not included in my CA");
 		return -1;
@@ -3234,8 +3277,9 @@
  * ieee802_1x_kay_create_mka -
  */
 struct ieee802_1x_mka_participant *
-ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
-			  struct mka_key *cak, u32 life,
+ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
+			  const struct mka_key_name *ckn,
+			  const struct mka_key *cak, u32 life,
 			  enum mka_created_mode mode, Boolean is_authenticator)
 {
 	struct ieee802_1x_mka_participant *participant;
@@ -3403,7 +3447,7 @@
 	wpa_printf(MSG_DEBUG, "KaY: participant removed");
 
 	/* get the participant */
-	participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+	participant = ieee802_1x_kay_get_participant(kay, ckn->name, ckn->len);
 	if (!participant) {
 		wpa_hexdump(MSG_DEBUG, "KaY: participant is not found",
 			    ckn->name, ckn->len);
@@ -3462,7 +3506,7 @@
 	if (!kay || !ckn)
 		return;
 
-	participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+	participant = ieee802_1x_kay_get_participant(kay, ckn->name, ckn->len);
 	if (!participant)
 		return;
 
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 8f394fd..b265059 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -241,7 +241,8 @@
 
 struct ieee802_1x_mka_participant *
 ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
-			  struct mka_key_name *ckn, struct mka_key *cak,
+			  const struct mka_key_name *ckn,
+			  const struct mka_key *cak,
 			  u32 life, enum mka_created_mode mode,
 			  Boolean is_authenticator);
 void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
diff --git a/src/radius/radius.c b/src/radius/radius.c
index fc98ad6..07240ea 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -250,6 +250,8 @@
 	{ RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
 	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_WLAN_REASON_CODE, "WLAN-Reason-Code",
+	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher",
 	  RADIUS_ATTR_HEXDUMP },
 	{ RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher",
diff --git a/src/radius/radius.h b/src/radius/radius.h
index cd510d2..630c0f9 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -102,8 +102,13 @@
        RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES = 130,
        RADIUS_ATTR_LOCATION_CAPABLE = 131,
        RADIUS_ATTR_REQUESTED_LOCATION_INFO = 132,
+       RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_NAME = 164,
+       RADIUS_ATTR_GSS_ACCEPTOR_HOST_NAME = 165,
+       RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFICS = 166,
+       RADIUS_ATTR_GSS_ACCEPTOR_REALM_NAME = 167,
        RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
        RADIUS_ATTR_WLAN_HESSID = 181,
+       RADIUS_ATTR_WLAN_REASON_CODE = 185,
        RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186,
        RADIUS_ATTR_WLAN_GROUP_CIPHER = 187,
        RADIUS_ATTR_WLAN_AKM_SUITE = 188,
@@ -193,6 +198,11 @@
 	RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION = 3,
 	RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ = 4,
 	RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL = 5,
+	RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM = 6,
+	RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME = 7,
+	RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP = 8,
+	RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING = 9,
+	RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL = 10,
 };
 
 #ifdef _MSC_VER
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 06c804d..a87ee74 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -904,13 +904,13 @@
 		switch (res) {
 		case RADIUS_RX_PROCESSED:
 			radius_msg_free(msg);
-			/* continue */
+			/* fall through */
 		case RADIUS_RX_QUEUED:
 			radius_client_msg_free(req);
 			return;
 		case RADIUS_RX_INVALID_AUTHENTICATOR:
 			invalid_authenticator++;
-			/* continue */
+			/* fall through */
 		case RADIUS_RX_UNKNOWN:
 			/* continue with next handler */
 			break;
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index ed24c19..aaa3fc2 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -27,6 +27,7 @@
 	void *ctx;
 	enum radius_das_res (*disconnect)(void *ctx,
 					  struct radius_das_attrs *attr);
+	enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
 };
 
 
@@ -161,6 +162,10 @@
 			   abuf, from_port);
 		error = 508;
 		break;
+	case RADIUS_DAS_COA_FAILED:
+		/* not used with Disconnect-Request */
+		error = 405;
+		break;
 	case RADIUS_DAS_SUCCESS:
 		error = 0;
 		break;
@@ -184,6 +189,195 @@
 }
 
 
+static struct radius_msg * radius_das_coa(struct radius_das_data *das,
+					  struct radius_msg *msg,
+					  const char *abuf, int from_port)
+{
+	struct radius_hdr *hdr;
+	struct radius_msg *reply;
+	u8 allowed[] = {
+		RADIUS_ATTR_USER_NAME,
+		RADIUS_ATTR_NAS_IP_ADDRESS,
+		RADIUS_ATTR_CALLING_STATION_ID,
+		RADIUS_ATTR_NAS_IDENTIFIER,
+		RADIUS_ATTR_ACCT_SESSION_ID,
+		RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+		RADIUS_ATTR_EVENT_TIMESTAMP,
+		RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+		RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+#ifdef CONFIG_HS20
+		RADIUS_ATTR_VENDOR_SPECIFIC,
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_IPV6
+		RADIUS_ATTR_NAS_IPV6_ADDRESS,
+#endif /* CONFIG_IPV6 */
+		0
+	};
+	int error = 405;
+	u8 attr;
+	enum radius_das_res res;
+	struct radius_das_attrs attrs;
+	u8 *buf;
+	size_t len;
+	char tmp[100];
+	u8 sta_addr[ETH_ALEN];
+
+	hdr = radius_msg_get_hdr(msg);
+
+	if (!das->coa) {
+		wpa_printf(MSG_INFO, "DAS: CoA not supported");
+		goto fail;
+	}
+
+	attr = radius_msg_find_unlisted_attr(msg, allowed);
+	if (attr) {
+		wpa_printf(MSG_INFO,
+			   "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
+			   attr, abuf, from_port);
+		error = 401;
+		goto fail;
+	}
+
+	os_memset(&attrs, 0, sizeof(attrs));
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+				    &buf, &len, NULL) == 0) {
+		if (len != 4) {
+			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
+				   abuf, from_port);
+			error = 407;
+			goto fail;
+		}
+		attrs.nas_ip_addr = buf;
+	}
+
+#ifdef CONFIG_IPV6
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+				    &buf, &len, NULL) == 0) {
+		if (len != 16) {
+			wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
+				   abuf, from_port);
+			error = 407;
+			goto fail;
+		}
+		attrs.nas_ipv6_addr = buf;
+	}
+#endif /* CONFIG_IPV6 */
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+				    &buf, &len, NULL) == 0) {
+		attrs.nas_identifier = buf;
+		attrs.nas_identifier_len = len;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				    &buf, &len, NULL) == 0) {
+		if (len >= sizeof(tmp))
+			len = sizeof(tmp) - 1;
+		os_memcpy(tmp, buf, len);
+		tmp[len] = '\0';
+		if (hwaddr_aton2(tmp, sta_addr) < 0) {
+			wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
+				   "'%s' from %s:%d", tmp, abuf, from_port);
+			error = 407;
+			goto fail;
+		}
+		attrs.sta_addr = sta_addr;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+				    &buf, &len, NULL) == 0) {
+		attrs.user_name = buf;
+		attrs.user_name_len = len;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+				    &buf, &len, NULL) == 0) {
+		attrs.acct_session_id = buf;
+		attrs.acct_session_id_len = len;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+				    &buf, &len, NULL) == 0) {
+		attrs.acct_multi_session_id = buf;
+		attrs.acct_multi_session_id_len = len;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+				    &buf, &len, NULL) == 0) {
+		attrs.cui = buf;
+		attrs.cui_len = len;
+	}
+
+#ifdef CONFIG_HS20
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+				    &buf, &len, NULL) == 0) {
+		if (len < 10 || WPA_GET_BE32(buf) != RADIUS_VENDOR_ID_WFA ||
+		    buf[4] != RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING ||
+		    buf[5] < 6) {
+			wpa_printf(MSG_INFO,
+				   "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
+				   attr, abuf, from_port);
+			error = 401;
+			goto fail;
+		}
+		attrs.hs20_t_c_filtering = &buf[6];
+	}
+
+	if (!attrs.hs20_t_c_filtering) {
+			wpa_printf(MSG_INFO,
+				   "DAS: No supported authorization change attribute in CoA-Request from %s:%d",
+				   abuf, from_port);
+			error = 402;
+			goto fail;
+	}
+#endif /* CONFIG_HS20 */
+
+	res = das->coa(das->ctx, &attrs);
+	switch (res) {
+	case RADIUS_DAS_NAS_MISMATCH:
+		wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
+			   abuf, from_port);
+		error = 403;
+		break;
+	case RADIUS_DAS_SESSION_NOT_FOUND:
+		wpa_printf(MSG_INFO,
+			   "DAS: Session not found for request from %s:%d",
+			   abuf, from_port);
+		error = 503;
+		break;
+	case RADIUS_DAS_MULTI_SESSION_MATCH:
+		wpa_printf(MSG_INFO,
+			   "DAS: Multiple sessions match for request from %s:%d",
+			   abuf, from_port);
+		error = 508;
+		break;
+	case RADIUS_DAS_COA_FAILED:
+		wpa_printf(MSG_INFO, "DAS: CoA failed for request from %s:%d",
+			   abuf, from_port);
+		error = 407;
+		break;
+	case RADIUS_DAS_SUCCESS:
+		error = 0;
+		break;
+	}
+
+fail:
+	reply = radius_msg_new(error ? RADIUS_CODE_COA_NAK :
+			       RADIUS_CODE_COA_ACK, hdr->identifier);
+	if (!reply)
+		return NULL;
+
+	if (error &&
+	    !radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) {
+		radius_msg_free(reply);
+		return NULL;
+	}
+
+	return reply;
+}
+
+
 static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
 {
 	struct radius_das_data *das = eloop_ctx;
@@ -219,7 +413,8 @@
 
 	wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
 		   len, abuf, from_port);
-	if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+	if (das->client_addr.u.v4.s_addr &&
+	    das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
 		wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
 		return;
 	}
@@ -270,19 +465,7 @@
 		reply = radius_das_disconnect(das, msg, abuf, from_port);
 		break;
 	case RADIUS_CODE_COA_REQUEST:
-		/* TODO */
-		reply = radius_msg_new(RADIUS_CODE_COA_NAK,
-				       hdr->identifier);
-		if (reply == NULL)
-			break;
-
-		/* Unsupported Service */
-		if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
-					       405)) {
-			radius_msg_free(reply);
-			reply = NULL;
-			break;
-		}
+		reply = radius_das_coa(das, msg, abuf, from_port);
 		break;
 	default:
 		wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
@@ -369,6 +552,7 @@
 		conf->require_message_authenticator;
 	das->ctx = conf->ctx;
 	das->disconnect = conf->disconnect;
+	das->coa = conf->coa;
 
 	os_memcpy(&das->client_addr, conf->client_addr,
 		  sizeof(das->client_addr));
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index 9863fdc..233d662 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -16,6 +16,7 @@
 	RADIUS_DAS_NAS_MISMATCH,
 	RADIUS_DAS_SESSION_NOT_FOUND,
 	RADIUS_DAS_MULTI_SESSION_MATCH,
+	RADIUS_DAS_COA_FAILED,
 };
 
 struct radius_das_attrs {
@@ -35,6 +36,9 @@
 	size_t acct_multi_session_id_len;
 	const u8 *cui;
 	size_t cui_len;
+
+	/* Authorization changes */
+	const u8 *hs20_t_c_filtering;
 };
 
 struct radius_das_conf {
@@ -48,6 +52,7 @@
 	void *ctx;
 	enum radius_das_res (*disconnect)(void *ctx,
 					  struct radius_das_attrs *attr);
+	enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
 };
 
 struct radius_das_data *
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index c76bb22..e3afc0d 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -80,6 +80,7 @@
 	struct eap_eapol_interface *eap_if;
 	char *username; /* from User-Name attribute */
 	char *nas_ip;
+	u8 mac_addr[ETH_ALEN]; /* from Calling-Station-Id attribute */
 
 	struct radius_msg *last_msg;
 	char *last_from_addr;
@@ -92,8 +93,11 @@
 
 	unsigned int remediation:1;
 	unsigned int macacl:1;
+	unsigned int t_c_filtering:1;
 
 	struct hostapd_radius_attr *accept_attr;
+
+	u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
 };
 
 /**
@@ -111,6 +115,14 @@
 	int shared_secret_len;
 	struct radius_session *sessions;
 	struct radius_server_counters counters;
+
+	u8 next_dac_identifier;
+	struct radius_msg *pending_dac_coa_req;
+	u8 pending_dac_coa_id;
+	u8 pending_dac_coa_addr[ETH_ALEN];
+	struct radius_msg *pending_dac_disconnect_req;
+	u8 pending_dac_disconnect_id;
+	u8 pending_dac_disconnect_addr[ETH_ALEN];
 };
 
 /**
@@ -346,6 +358,8 @@
 	char *subscr_remediation_url;
 	u8 subscr_remediation_method;
 
+	char *t_c_server_url;
+
 #ifdef CONFIG_SQLITE
 	sqlite3 *db;
 #endif /* CONFIG_SQLITE */
@@ -628,8 +642,8 @@
 			      struct radius_client *client,
 			      struct radius_msg *msg, const char *from_addr)
 {
-	u8 *user;
-	size_t user_len;
+	u8 *user, *id;
+	size_t user_len, id_len;
 	int res;
 	struct radius_session *sess;
 	struct eap_config eap_conf;
@@ -675,6 +689,21 @@
 		return NULL;
 	}
 
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, &id,
+				    &id_len, NULL) == 0) {
+		char buf[3 * ETH_ALEN];
+
+		os_memset(buf, 0, sizeof(buf));
+		if (id_len >= sizeof(buf))
+			id_len = sizeof(buf) - 1;
+		os_memcpy(buf, id, id_len);
+		if (hwaddr_aton2(buf, sess->mac_addr) < 0)
+			os_memset(sess->mac_addr, 0, ETH_ALEN);
+		else
+			RADIUS_DEBUG("Calling-Station-Id: " MACSTR,
+				     MAC2STR(sess->mac_addr));
+	}
+
 	srv_log(sess, "New session created");
 
 	os_memset(&eap_conf, 0, sizeof(eap_conf));
@@ -718,6 +747,125 @@
 }
 
 
+#ifdef CONFIG_HS20
+static void radius_srv_hs20_t_c_pending(struct radius_session *sess)
+{
+#ifdef CONFIG_SQLITE
+	char *sql;
+	char addr[3 * ETH_ALEN], *id_str;
+	const u8 *id;
+	size_t id_len;
+
+	if (!sess->server->db || !sess->eap ||
+	    is_zero_ether_addr(sess->mac_addr))
+		return;
+
+	os_snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sess->mac_addr));
+
+	id = eap_get_identity(sess->eap, &id_len);
+	if (!id)
+		return;
+	id_str = os_malloc(id_len + 1);
+	if (!id_str)
+		return;
+	os_memcpy(id_str, id, id_len);
+	id_str[id_len] = '\0';
+
+	sql = sqlite3_mprintf("INSERT OR REPLACE INTO pending_tc (mac_addr,identity) VALUES (%Q,%Q)",
+			      addr, id_str);
+	os_free(id_str);
+	if (!sql)
+		return;
+
+	if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+	    SQLITE_OK) {
+		RADIUS_ERROR("Failed to add pending_tc entry into sqlite database: %s",
+			     sqlite3_errmsg(sess->server->db));
+	}
+	sqlite3_free(sql);
+#endif /* CONFIG_SQLITE */
+}
+#endif /* CONFIG_HS20 */
+
+
+static void radius_server_add_session(struct radius_session *sess)
+{
+#ifdef CONFIG_SQLITE
+	char *sql;
+	char addr_txt[ETH_ALEN * 3];
+	struct os_time now;
+
+	if (!sess->server->db)
+		return;
+
+
+	os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
+		    MAC2STR(sess->mac_addr));
+
+	os_get_time(&now);
+	sql = sqlite3_mprintf("INSERT OR REPLACE INTO current_sessions(mac_addr,identity,start_time,nas,hs20_t_c_filtering) VALUES (%Q,%Q,%d,%Q,%u)",
+			      addr_txt, sess->username, now.sec,
+			      sess->nas_ip, sess->t_c_filtering);
+	if (sql) {
+			if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
+					 NULL) != SQLITE_OK) {
+				RADIUS_ERROR("Failed to add current_sessions entry into sqlite database: %s",
+					     sqlite3_errmsg(sess->server->db));
+			}
+			sqlite3_free(sql);
+	}
+#endif /* CONFIG_SQLITE */
+}
+
+
+static void db_update_last_msk(struct radius_session *sess, const char *msk)
+{
+#ifdef CONFIG_RADIUS_TEST
+#ifdef CONFIG_SQLITE
+	char *sql = NULL;
+	char *id_str = NULL;
+	const u8 *id;
+	size_t id_len;
+	const char *serial_num;
+
+	if (!sess->server->db)
+		return;
+
+	serial_num = eap_get_serial_num(sess->eap);
+	if (serial_num) {
+		id_len = 5 + os_strlen(serial_num) + 1;
+		id_str = os_malloc(id_len);
+		if (!id_str)
+			return;
+		os_snprintf(id_str, id_len, "cert-%s", serial_num);
+	} else {
+		id = eap_get_identity(sess->eap, &id_len);
+		if (!id)
+			return;
+		id_str = os_malloc(id_len + 1);
+		if (!id_str)
+			return;
+		os_memcpy(id_str, id, id_len);
+		id_str[id_len] = '\0';
+	}
+
+	sql = sqlite3_mprintf("UPDATE users SET last_msk=%Q WHERE identity=%Q",
+			      msk, id_str);
+	os_free(id_str);
+	if (!sql)
+		return;
+
+	if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+	    SQLITE_OK) {
+		RADIUS_DEBUG("Failed to update last_msk: %s",
+			     sqlite3_errmsg(sess->server->db));
+	}
+	sqlite3_free(sql);
+#endif /* CONFIG_SQLITE */
+#endif /* CONFIG_RADIUS_TEST */
+}
+
+
 static struct radius_msg *
 radius_server_encapsulate_eap(struct radius_server_data *data,
 			      struct radius_client *client,
@@ -728,6 +876,7 @@
 	int code;
 	unsigned int sess_id;
 	struct radius_hdr *hdr = radius_msg_get_hdr(request);
+	u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
 
 	if (sess->eap_if->eapFail) {
 		sess->eap_if->eapFail = FALSE;
@@ -762,9 +911,18 @@
 	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
 		int len;
 #ifdef CONFIG_RADIUS_TEST
+		char buf[2 * 64 + 1];
+
+		len = sess->eap_if->eapKeyDataLen;
+		if (len > 64)
+			len = 64;
+		len = wpa_snprintf_hex(buf, sizeof(buf),
+				       sess->eap_if->eapKeyData, len);
+		buf[len] = '\0';
+
 		if (data->dump_msk_file) {
 			FILE *f;
-			char buf[2 * 64 + 1];
+
 			f = fopen(data->dump_msk_file, "a");
 			if (f) {
 				len = sess->eap_if->eapKeyDataLen;
@@ -778,6 +936,8 @@
 				fclose(f);
 			}
 		}
+
+		db_update_last_msk(sess, buf);
 #endif /* CONFIG_RADIUS_TEST */
 		if (sess->eap_if->eapKeyDataLen > 64) {
 			len = 32;
@@ -820,6 +980,61 @@
 			RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
 		}
 	}
+
+	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) {
+		u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */
+		const char *url = data->t_c_server_url, *pos;
+		char *url2, *end2, *pos2;
+		size_t url_len;
+
+		if (!radius_msg_add_wfa(
+			    msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
+			    buf, sizeof(buf))) {
+			RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
+			radius_msg_free(msg);
+			return NULL;
+		}
+
+		if (!url) {
+			RADIUS_DEBUG("No t_c_server_url configured");
+			radius_msg_free(msg);
+			return NULL;
+		}
+
+		pos = os_strstr(url, "@1@");
+		if (!pos) {
+			RADIUS_DEBUG("No @1@ macro in t_c_server_url");
+			radius_msg_free(msg);
+			return NULL;
+		}
+
+		url_len = os_strlen(url) + ETH_ALEN * 3 - 1 - 3;
+		url2 = os_malloc(url_len + 1);
+		if (!url2) {
+			RADIUS_DEBUG("Failed to allocate room for T&C Server URL");
+			os_free(url2);
+			radius_msg_free(msg);
+			return NULL;
+		}
+		pos2 = url2;
+		end2 = url2 + url_len + 1;
+		os_memcpy(pos2, url, pos - url);
+		pos2 += pos - url;
+		os_snprintf(pos2, end2 - pos2, MACSTR, MAC2STR(sess->mac_addr));
+		pos2 += ETH_ALEN * 3 - 1;
+		os_memcpy(pos2, pos + 3, os_strlen(pos + 3));
+		if (!radius_msg_add_wfa(msg,
+					RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL,
+					(const u8 *) url2, url_len)) {
+			RADIUS_DEBUG("Failed to add WFA-HS20-T-C-URL");
+			os_free(url2);
+			radius_msg_free(msg);
+			return NULL;
+		}
+		os_free(url2);
+
+		radius_srv_hs20_t_c_pending(sess);
+	}
 #endif /* CONFIG_HS20 */
 
 	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
@@ -841,12 +1056,24 @@
 		}
 	}
 
+	if (code == RADIUS_CODE_ACCESS_REJECT) {
+		if (radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
+					      reason) < 0) {
+			RADIUS_DEBUG("Failed to add WLAN-Reason-Code attribute");
+			radius_msg_free(msg);
+			return NULL;
+		}
+	}
+
 	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
 				  client->shared_secret_len,
 				  hdr->authenticator) < 0) {
 		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
 	}
 
+	if (code == RADIUS_CODE_ACCESS_ACCEPT)
+		radius_server_add_session(sess);
+
 	return msg;
 }
 
@@ -993,6 +1220,51 @@
 }
 
 
+static void radius_server_hs20_t_c_check(struct radius_session *sess,
+					 struct radius_msg *msg)
+{
+#ifdef CONFIG_HS20
+	u8 *buf, *pos, *end, type, sublen, *timestamp = NULL;
+	size_t len;
+
+	buf = NULL;
+	for (;;) {
+		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+					    &buf, &len, buf) < 0)
+			break;
+		if (len < 6)
+			continue;
+		pos = buf;
+		end = buf + len;
+		if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
+			continue;
+		pos += 4;
+
+		type = *pos++;
+		sublen = *pos++;
+		if (sublen < 2)
+			continue; /* invalid length */
+		sublen -= 2; /* skip header */
+		if (pos + sublen > end)
+			continue; /* invalid WFA VSA */
+
+		if (type == RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP && len >= 4) {
+			timestamp = pos;
+			break;
+		}
+	}
+
+	if (!timestamp)
+		return;
+	RADIUS_DEBUG("HS20-Timestamp: %u", WPA_GET_BE32(timestamp));
+	if (sess->t_c_timestamp != WPA_GET_BE32(timestamp)) {
+		RADIUS_DEBUG("Last read T&C timestamp does not match HS20-Timestamp --> require filtering");
+		sess->t_c_filtering = 1;
+	}
+#endif /* CONFIG_HS20 */
+}
+
+
 static int radius_server_request(struct radius_server_data *data,
 				 struct radius_msg *msg,
 				 struct sockaddr *from, socklen_t fromlen,
@@ -1123,10 +1395,15 @@
 
 	if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
 		is_complete = 1;
-	if (sess->eap_if->eapFail)
+	if (sess->eap_if->eapFail) {
 		srv_log(sess, "EAP authentication failed");
-	else if (sess->eap_if->eapSuccess)
+		db_update_last_msk(sess, "FAIL");
+	} else if (sess->eap_if->eapSuccess) {
 		srv_log(sess, "EAP authentication succeeded");
+	}
+
+	if (sess->eap_if->eapSuccess)
+		radius_server_hs20_t_c_check(sess, msg);
 
 	reply = radius_server_encapsulate_eap(data, client, sess, msg);
 
@@ -1189,6 +1466,116 @@
 }
 
 
+static void
+radius_server_receive_disconnect_resp(struct radius_server_data *data,
+				      struct radius_client *client,
+				      struct radius_msg *msg, int ack)
+{
+	struct radius_hdr *hdr;
+
+	if (!client->pending_dac_disconnect_req) {
+		RADIUS_DEBUG("Ignore unexpected Disconnect response");
+		radius_msg_free(msg);
+		return;
+	}
+
+	hdr = radius_msg_get_hdr(msg);
+	if (hdr->identifier != client->pending_dac_disconnect_id) {
+		RADIUS_DEBUG("Ignore unexpected Disconnect response with unexpected identifier %u (expected %u)",
+			     hdr->identifier,
+			     client->pending_dac_disconnect_id);
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
+			      client->shared_secret_len,
+			      client->pending_dac_disconnect_req, 0)) {
+		RADIUS_DEBUG("Ignore Disconnect response with invalid authenticator");
+		radius_msg_free(msg);
+		return;
+	}
+
+	RADIUS_DEBUG("Disconnect-%s received for " MACSTR,
+		     ack ? "ACK" : "NAK",
+		     MAC2STR(client->pending_dac_disconnect_addr));
+
+	radius_msg_free(msg);
+	radius_msg_free(client->pending_dac_disconnect_req);
+	client->pending_dac_disconnect_req = NULL;
+}
+
+
+static void radius_server_receive_coa_resp(struct radius_server_data *data,
+					   struct radius_client *client,
+					   struct radius_msg *msg, int ack)
+{
+	struct radius_hdr *hdr;
+#ifdef CONFIG_SQLITE
+	char addrtxt[3 * ETH_ALEN];
+	char *sql;
+	int res;
+#endif /* CONFIG_SQLITE */
+
+	if (!client->pending_dac_coa_req) {
+		RADIUS_DEBUG("Ignore unexpected CoA response");
+		radius_msg_free(msg);
+		return;
+	}
+
+	hdr = radius_msg_get_hdr(msg);
+	if (hdr->identifier != client->pending_dac_coa_id) {
+		RADIUS_DEBUG("Ignore unexpected CoA response with unexpected identifier %u (expected %u)",
+			     hdr->identifier,
+			     client->pending_dac_coa_id);
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
+			      client->shared_secret_len,
+			      client->pending_dac_coa_req, 0)) {
+		RADIUS_DEBUG("Ignore CoA response with invalid authenticator");
+		radius_msg_free(msg);
+		return;
+	}
+
+	RADIUS_DEBUG("CoA-%s received for " MACSTR,
+		     ack ? "ACK" : "NAK",
+		     MAC2STR(client->pending_dac_coa_addr));
+
+	radius_msg_free(msg);
+	radius_msg_free(client->pending_dac_coa_req);
+	client->pending_dac_coa_req = NULL;
+
+#ifdef CONFIG_SQLITE
+	if (!data->db)
+		return;
+
+	os_snprintf(addrtxt, sizeof(addrtxt), MACSTR,
+		    MAC2STR(client->pending_dac_coa_addr));
+
+	if (ack) {
+		sql = sqlite3_mprintf("UPDATE current_sessions SET hs20_t_c_filtering=0, waiting_coa_ack=0, coa_ack_received=1 WHERE mac_addr=%Q",
+				      addrtxt);
+	} else {
+		sql = sqlite3_mprintf("UPDATE current_sessions SET waiting_coa_ack=0 WHERE mac_addr=%Q",
+				      addrtxt);
+	}
+	if (!sql)
+		return;
+
+	res = sqlite3_exec(data->db, sql, NULL, NULL, NULL);
+	sqlite3_free(sql);
+	if (res != SQLITE_OK) {
+		RADIUS_ERROR("Failed to update current_sessions entry: %s",
+			     sqlite3_errmsg(data->db));
+		return;
+	}
+#endif /* CONFIG_SQLITE */
+}
+
+
 static void radius_server_receive_auth(int sock, void *eloop_ctx,
 				       void *sock_ctx)
 {
@@ -1269,6 +1656,26 @@
 		radius_msg_dump(msg);
 	}
 
+	if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_ACK) {
+		radius_server_receive_disconnect_resp(data, client, msg, 1);
+		return;
+	}
+
+	if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_NAK) {
+		radius_server_receive_disconnect_resp(data, client, msg, 0);
+		return;
+	}
+
+	if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_ACK) {
+		radius_server_receive_coa_resp(data, client, msg, 1);
+		return;
+	}
+
+	if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_NAK) {
+		radius_server_receive_coa_resp(data, client, msg, 0);
+		return;
+	}
+
 	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) {
 		RADIUS_DEBUG("Unexpected RADIUS code %d",
 			     radius_msg_get_hdr(msg)->code);
@@ -1529,6 +1936,8 @@
 
 		radius_server_free_sessions(data, prev->sessions);
 		os_free(prev->shared_secret);
+		radius_msg_free(prev->pending_dac_coa_req);
+		radius_msg_free(prev->pending_dac_disconnect_req);
 		os_free(prev);
 	}
 }
@@ -1765,6 +2174,9 @@
 	}
 	data->subscr_remediation_method = conf->subscr_remediation_method;
 
+	if (conf->t_c_server_url)
+		data->t_c_server_url = os_strdup(conf->t_c_server_url);
+
 #ifdef CONFIG_SQLITE
 	if (conf->sqlite_file) {
 		if (sqlite3_open(conf->sqlite_file, &data->db)) {
@@ -1881,6 +2293,7 @@
 	os_free(data->dump_msk_file);
 #endif /* CONFIG_RADIUS_TEST */
 	os_free(data->subscr_remediation_url);
+	os_free(data->t_c_server_url);
 
 #ifdef CONFIG_SQLITE
 	if (data->db)
@@ -2049,6 +2462,7 @@
 		sess->accept_attr = user->accept_attr;
 		sess->remediation = user->remediation;
 		sess->macacl = user->macacl;
+		sess->t_c_timestamp = user->t_c_timestamp;
 	}
 
 	if (ret) {
@@ -2175,3 +2589,212 @@
 
 	radius_msg_free(msg);
 }
+
+
+#ifdef CONFIG_SQLITE
+
+struct db_session_fields {
+	char *identity;
+	char *nas;
+	int hs20_t_c_filtering;
+	int waiting_coa_ack;
+	int coa_ack_received;
+};
+
+
+static int get_db_session_fields(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct db_session_fields *fields = ctx;
+	int i;
+
+	for (i = 0; i < argc; i++) {
+		if (!argv[i])
+			continue;
+
+		RADIUS_DEBUG("Session DB: %s=%s", col[i], argv[i]);
+
+		if (os_strcmp(col[i], "identity") == 0) {
+			os_free(fields->identity);
+			fields->identity = os_strdup(argv[i]);
+		} else if (os_strcmp(col[i], "nas") == 0) {
+			os_free(fields->nas);
+			fields->nas = os_strdup(argv[i]);
+		} else if (os_strcmp(col[i], "hs20_t_c_filtering") == 0) {
+			fields->hs20_t_c_filtering = atoi(argv[i]);
+		} else if (os_strcmp(col[i], "waiting_coa_ack") == 0) {
+			fields->waiting_coa_ack = atoi(argv[i]);
+		} else if (os_strcmp(col[i], "coa_ack_received") == 0) {
+			fields->coa_ack_received = atoi(argv[i]);
+		}
+	}
+
+	return 0;
+}
+
+
+static void free_db_session_fields(struct db_session_fields *fields)
+{
+	os_free(fields->identity);
+	fields->identity = NULL;
+	os_free(fields->nas);
+	fields->nas = NULL;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+int radius_server_dac_request(struct radius_server_data *data, const char *req)
+{
+#ifdef CONFIG_SQLITE
+	char *sql;
+	int res;
+	int disconnect;
+	const char *pos = req;
+	u8 addr[ETH_ALEN];
+	char addrtxt[3 * ETH_ALEN];
+	int t_c_clear = 0;
+	struct db_session_fields fields;
+	struct sockaddr_in das;
+	struct radius_client *client;
+	struct radius_msg *msg;
+	struct wpabuf *buf;
+	u8 identifier;
+	struct os_time now;
+
+	if (!data)
+		return -1;
+
+	/* req: <disconnect|coa> <MAC Address> [t_c_clear] */
+
+	if (os_strncmp(pos, "disconnect ", 11) == 0) {
+		disconnect = 1;
+		pos += 11;
+	} else if (os_strncmp(req, "coa ", 4) == 0) {
+		disconnect = 0;
+		pos += 4;
+	} else {
+		return -1;
+	}
+
+	if (hwaddr_aton(pos, addr))
+		return -1;
+	pos = os_strchr(pos, ' ');
+	if (pos) {
+		if (os_strstr(pos, "t_c_clear"))
+			t_c_clear = 1;
+	}
+
+	if (!disconnect && !t_c_clear) {
+		RADIUS_ERROR("DAC request for CoA without any authorization change");
+		return -1;
+	}
+
+	if (!data->db) {
+		RADIUS_ERROR("SQLite database not in use");
+		return -1;
+	}
+
+	os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(addr));
+
+	sql = sqlite3_mprintf("SELECT * FROM current_sessions WHERE mac_addr=%Q",
+			      addrtxt);
+	if (!sql)
+		return -1;
+
+	os_memset(&fields, 0, sizeof(fields));
+	res = sqlite3_exec(data->db, sql, get_db_session_fields, &fields, NULL);
+	sqlite3_free(sql);
+	if (res != SQLITE_OK) {
+		RADIUS_ERROR("Failed to find matching current_sessions entry from sqlite database: %s",
+			     sqlite3_errmsg(data->db));
+		free_db_session_fields(&fields);
+		return -1;
+	}
+
+	if (!fields.nas) {
+		RADIUS_ERROR("No NAS information found from current_sessions");
+		free_db_session_fields(&fields);
+		return -1;
+	}
+
+	os_memset(&das, 0, sizeof(das));
+	das.sin_family = AF_INET;
+	das.sin_addr.s_addr = inet_addr(fields.nas);
+	das.sin_port = htons(3799);
+
+	free_db_session_fields(&fields);
+
+	client = radius_server_get_client(data, &das.sin_addr, 0);
+	if (!client) {
+		RADIUS_ERROR("No NAS information available to protect the packet");
+		return -1;
+	}
+
+	identifier = client->next_dac_identifier++;
+
+	msg = radius_msg_new(disconnect ? RADIUS_CODE_DISCONNECT_REQUEST :
+			     RADIUS_CODE_COA_REQUEST, identifier);
+	if (!msg)
+		return -1;
+
+	os_snprintf(addrtxt, sizeof(addrtxt), RADIUS_802_1X_ADDR_FORMAT,
+		    MAC2STR(addr));
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				 (u8 *) addrtxt, os_strlen(addrtxt))) {
+		RADIUS_ERROR("Could not add Calling-Station-Id");
+		radius_msg_free(msg);
+		return -1;
+	}
+
+	if (!disconnect && t_c_clear) {
+		u8 val[4] = { 0x00, 0x00, 0x00, 0x00 }; /* E=0 */
+
+		if (!radius_msg_add_wfa(
+			    msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
+			    val, sizeof(val))) {
+			RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
+			radius_msg_free(msg);
+			return -1;
+		}
+	}
+
+	os_get_time(&now);
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+				       now.sec)) {
+		RADIUS_ERROR("Failed to add Event-Timestamp attribute");
+		radius_msg_free(msg);
+		return -1;
+	}
+
+	radius_msg_finish_acct(msg, (u8 *) client->shared_secret,
+			       client->shared_secret_len);
+
+	if (wpa_debug_level <= MSG_MSGDUMP)
+		radius_msg_dump(msg);
+
+	buf = radius_msg_get_buf(msg);
+	if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
+		   (struct sockaddr *) &das, sizeof(das)) < 0) {
+		RADIUS_ERROR("Failed to send packet - sendto: %s",
+			     strerror(errno));
+		radius_msg_free(msg);
+		return -1;
+	}
+
+	if (disconnect) {
+		radius_msg_free(client->pending_dac_disconnect_req);
+		client->pending_dac_disconnect_req = msg;
+		client->pending_dac_disconnect_id = identifier;
+		os_memcpy(client->pending_dac_disconnect_addr, addr, ETH_ALEN);
+	} else {
+		radius_msg_free(client->pending_dac_coa_req);
+		client->pending_dac_coa_req = msg;
+		client->pending_dac_coa_id = identifier;
+		os_memcpy(client->pending_dac_coa_addr, addr, ETH_ALEN);
+	}
+
+	return 0;
+#else /* CONFIG_SQLITE */
+	return -1;
+#endif /* CONFIG_SQLITE */
+}
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 996f00e..167bbf5 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -233,6 +233,8 @@
 
 	char *subscr_remediation_url;
 	u8 subscr_remediation_method;
+
+	char *t_c_server_url;
 };
 
 
@@ -246,5 +248,6 @@
 			  size_t buflen);
 
 void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx);
+int radius_server_dac_request(struct radius_server_data *data, const char *req);
 
 #endif /* RADIUS_SERVER_H */
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index f5024f2..fdd5220 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -96,7 +96,7 @@
 	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
 
 	entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
-		pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
+		pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0);
 	if (entry) {
 		sec = pmksa->pmksa->reauth_time - now.sec;
 		if (sec < 0)
@@ -341,17 +341,20 @@
  * @aa: Authenticator address or %NULL to match any
  * @pmkid: PMKID or %NULL to match any
  * @network_ctx: Network context or %NULL to match any
+ * @akmp: Specific AKMP to search for or 0 for any
  * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
  */
 struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
 					       const u8 *aa, const u8 *pmkid,
-					       const void *network_ctx)
+					       const void *network_ctx,
+					       int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 	while (entry) {
 		if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
 		    (pmkid == NULL ||
 		     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
+		    (!akmp || akmp == entry->akmp) &&
 		    (network_ctx == NULL || network_ctx == entry->network_ctx))
 			return entry;
 		entry = entry->next;
@@ -390,6 +393,7 @@
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  * @network_ctx: Network configuration context
  * @aa: Authenticator address for the new AP
+ * @akmp: Specific AKMP to search for or 0 for any
  * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
  *
  * Try to create a new PMKSA cache entry opportunistically by guessing that the
@@ -398,7 +402,7 @@
  */
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
-			      const u8 *aa)
+			      const u8 *aa, int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
@@ -406,7 +410,8 @@
 	if (network_ctx == NULL)
 		return NULL;
 	while (entry) {
-		if (entry->network_ctx == network_ctx) {
+		if (entry->network_ctx == network_ctx &&
+		    (!akmp || entry->akmp == akmp)) {
 			entry = pmksa_cache_clone_entry(pmksa, entry, aa);
 			if (entry) {
 				wpa_printf(MSG_DEBUG, "RSN: added "
@@ -476,11 +481,13 @@
  */
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 			    const u8 *bssid, void *network_ctx,
-			    int try_opportunistic, const u8 *fils_cache_id)
+			    int try_opportunistic, const u8 *fils_cache_id,
+			    int akmp)
 {
 	struct rsn_pmksa_cache *pmksa = sm->pmksa;
 	wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
-		   "try_opportunistic=%d", network_ctx, try_opportunistic);
+		   "try_opportunistic=%d akmp=0x%x",
+		   network_ctx, try_opportunistic, akmp);
 	if (pmkid)
 		wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
 			    pmkid, PMKID_LEN);
@@ -495,14 +502,14 @@
 	sm->cur_pmksa = NULL;
 	if (pmkid)
 		sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
-						network_ctx);
+						network_ctx, akmp);
 	if (sm->cur_pmksa == NULL && bssid)
 		sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
-						network_ctx);
+						network_ctx, akmp);
 	if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
 		sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
 							      network_ctx,
-							      bssid);
+							      bssid, akmp);
 	if (sm->cur_pmksa == NULL && fils_cache_id)
 		sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa,
 							      network_ctx,
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index f9a72a6..6c49fa9 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -61,7 +61,8 @@
 void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
 					       const u8 *aa, const u8 *pmkid,
-					       const void *network_ctx);
+					       const void *network_ctx,
+					       int akmp);
 int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
 struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry *
@@ -76,10 +77,11 @@
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 			    const u8 *bssid, void *network_ctx,
-			    int try_opportunistic, const u8 *fils_cache_id);
+			    int try_opportunistic, const u8 *fils_cache_id,
+			    int akmp);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
-			      void *network_ctx, const u8 *aa);
+			      void *network_ctx, const u8 *aa, int akmp);
 void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
 		       const u8 *pmk, size_t pmk_len);
 
@@ -99,7 +101,7 @@
 
 static inline struct rsn_pmksa_cache_entry *
 pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
-		const void *network_ctx)
+		const void *network_ctx, int akmp)
 {
 	return NULL;
 }
@@ -146,7 +148,8 @@
 					  const u8 *bssid,
 					  void *network_ctx,
 					  int try_opportunistic,
-					  const u8 *fils_cache_id)
+					  const u8 *fils_cache_id,
+					  int akmp)
 {
 	return -1;
 }
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d4276b9..d0c43f4 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -323,7 +323,7 @@
 	dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
 			      struct rsn_pmksa_candidate, list) {
 		struct rsn_pmksa_cache_entry *p = NULL;
-		p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL);
+		p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL, 0);
 		if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
 		    (p == NULL || p->opportunistic)) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
@@ -372,7 +372,7 @@
 
 	if (sm->network_ctx && sm->proactive_key_caching)
 		pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
-					      bssid);
+					      bssid, 0);
 
 	if (!preauth) {
 		wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
@@ -483,7 +483,7 @@
 	if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
 		return;
 
-	pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL);
+	pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL, 0);
 	if (pmksa && (!pmksa->opportunistic ||
 		      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
 		return;
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 5e350ed..14b346a 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -35,6 +35,7 @@
 #define TDLS_TESTING_DECLINE_RESP BIT(9)
 #define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10)
 #define TDLS_TESTING_WRONG_MIC BIT(11)
+#define TDLS_TESTING_DOUBLE_TPK_M2 BIT(12)
 unsigned int tdls_testing = 0;
 #endif /* CONFIG_TDLS_TESTING */
 
@@ -2124,6 +2125,13 @@
 		goto error;
 	}
 
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_DOUBLE_TPK_M2) {
+		wpa_printf(MSG_INFO, "TDLS: Testing - Send another TPK M2");
+		wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
 	return 0;
 
 error:
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index ff4a6ed..72a2d66 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
  * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * This software may be distributed under the terms of the BSD license.
@@ -181,8 +181,7 @@
 	int key_info, ver;
 	u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
 
-	if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
-	    wpa_key_mgmt_suite_b(sm->key_mgmt))
+	if (wpa_use_akm_defined(sm->key_mgmt))
 		ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
 	else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
 		 wpa_key_mgmt_sha256(sm->key_mgmt))
@@ -269,7 +268,7 @@
 		 * event before receiving this 1/4 message, so try to find a
 		 * matching PMKSA cache entry here. */
 		sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
-						NULL);
+						NULL, 0);
 		if (sm->cur_pmksa) {
 			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 				"RSN: found matching PMKID from PMKSA cache");
@@ -289,6 +288,18 @@
 		eapol_sm_notify_cached(sm->eapol);
 #ifdef CONFIG_IEEE80211R
 		sm->xxkey_len = 0;
+#ifdef CONFIG_SAE
+		if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE &&
+		    sm->pmk_len == PMK_LEN) {
+			/* Need to allow FT key derivation to proceed with
+			 * PMK from SAE being used as the XXKey in cases where
+			 * the PMKID in msg 1/4 matches the PMKSA entry that was
+			 * just added based on SAE authentication for the
+			 * initial mobility domain association. */
+			os_memcpy(sm->xxkey, sm->pmk, sm->pmk_len);
+			sm->xxkey_len = sm->pmk_len;
+		}
+#endif /* CONFIG_SAE */
 #endif /* CONFIG_IEEE80211R */
 	} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
 		int res, pmk_len;
@@ -312,8 +323,15 @@
 			u8 buf[2 * PMK_LEN];
 			if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
 			{
-				os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
-				sm->xxkey_len = PMK_LEN;
+				if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
+					os_memcpy(sm->xxkey, buf,
+						  SHA384_MAC_LEN);
+					sm->xxkey_len = SHA384_MAC_LEN;
+				} else {
+					os_memcpy(sm->xxkey, buf + PMK_LEN,
+						  PMK_LEN);
+					sm->xxkey_len = PMK_LEN;
+				}
 				os_memset(buf, 0, sizeof(buf));
 			}
 #endif /* CONFIG_IEEE80211R */
@@ -343,8 +361,8 @@
 						     fils_cache_id);
 			}
 			if (!sm->cur_pmksa && pmkid &&
-			    pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
-			{
+			    pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL,
+				    0)) {
 				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 					"RSN: the new PMK matches with the "
 					"PMKID");
@@ -989,7 +1007,7 @@
 	}
 
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
-		"WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
+		"WPA: IGTK keyid %d pn " COMPACT_MACSTR,
 		keyidx, MAC2STR(igtk->pn));
 	wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
 	if (keyidx > 4095) {
@@ -1443,7 +1461,13 @@
 	if (ie.gtk)
 		wpa_sm_set_rekey_offload(sm);
 
-	if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+	/* Add PMKSA cache entry for Suite B AKMs here since PMKID can be
+	 * calculated only after KCK has been derived. Though, do not replace an
+	 * existing PMKSA entry after each 4-way handshake (i.e., new KCK/PMKID)
+	 * to avoid unnecessary changes of PMKID while continuing to use the
+	 * same PMK. */
+	if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+	    !sm->cur_pmksa) {
 		struct rsn_pmksa_cache_entry *sa;
 
 		sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL,
@@ -1739,7 +1763,7 @@
 			os_memset(&sm->tptk, 0, sizeof(sm->tptk));
 			/*
 			 * This assures the same TPTK in sm->tptk can never be
-			 * copied twice to sm->pkt as the new PTK. In
+			 * copied twice to sm->ptk as the new PTK. In
 			 * combination with the installed flag in the wpa_ptk
 			 * struct, this assures the same PTK is only installed
 			 * once.
@@ -1814,10 +1838,7 @@
 #endif /* CONFIG_NO_RC4 */
 	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
 		   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
-		   sm->key_mgmt == WPA_KEY_MGMT_OWE ||
-		   sm->key_mgmt == WPA_KEY_MGMT_DPP ||
-		   sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
-		   wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+		   wpa_use_aes_key_wrap(sm->key_mgmt)) {
 		u8 *buf;
 
 		wpa_printf(MSG_DEBUG,
@@ -2094,29 +2115,14 @@
 	    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
 #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
 	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
-	    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
-	    !wpa_key_mgmt_fils(sm->key_mgmt) &&
-	    sm->key_mgmt != WPA_KEY_MGMT_OWE &&
-	    sm->key_mgmt != WPA_KEY_MGMT_DPP &&
-	    sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
+	    !wpa_use_akm_defined(sm->key_mgmt)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: Unsupported EAPOL-Key descriptor version %d",
 			ver);
 		goto out;
 	}
 
-	if (sm->key_mgmt == WPA_KEY_MGMT_OSEN &&
-	    ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-			"OSEN: Unsupported EAPOL-Key descriptor version %d",
-			ver);
-		goto out;
-	}
-
-	if ((wpa_key_mgmt_suite_b(sm->key_mgmt) ||
-	     wpa_key_mgmt_fils(sm->key_mgmt) ||
-	     sm->key_mgmt == WPA_KEY_MGMT_DPP ||
-	     sm->key_mgmt == WPA_KEY_MGMT_OWE) &&
+	if (wpa_use_akm_defined(sm->key_mgmt) &&
 	    ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
@@ -2127,7 +2133,8 @@
 #ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
 		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
-		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+		    !wpa_use_akm_defined(sm->key_mgmt)) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 				"FT: AP did not use AES-128-CMAC");
 			goto out;
@@ -2137,9 +2144,7 @@
 #ifdef CONFIG_IEEE80211W
 	if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
 		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-		    sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
-		    !wpa_key_mgmt_fils(sm->key_mgmt) &&
-		    !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+		    !wpa_use_akm_defined(sm->key_mgmt)) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 				"WPA: AP did not use the "
 				"negotiated AES-128-CMAC");
@@ -2148,10 +2153,7 @@
 	} else
 #endif /* CONFIG_IEEE80211W */
 	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
-	    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
-	    !wpa_key_mgmt_fils(sm->key_mgmt) &&
-	    sm->key_mgmt != WPA_KEY_MGMT_OWE &&
-	    sm->key_mgmt != WPA_KEY_MGMT_DPP &&
+	    !wpa_use_akm_defined(sm->key_mgmt) &&
 	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: CCMP is used, but EAPOL-Key "
@@ -2171,7 +2173,7 @@
 		} else
 			goto out;
 	} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
-		   !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+		   !wpa_use_akm_defined(sm->key_mgmt) &&
 		   ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: GCMP is used, but EAPOL-Key "
@@ -2219,6 +2221,17 @@
 
 	if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
 	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && mic_len) {
+		/*
+		 * Only decrypt the Key Data field if the frame's authenticity
+		 * was verified. When using AES-SIV (FILS), the MIC flag is not
+		 * set, so this check should only be performed if mic_len != 0
+		 * which is the case in this code branch.
+		 */
+		if (!(key_info & WPA_KEY_INFO_MIC)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Ignore EAPOL-Key with encrypted but unauthenticated data");
+			goto out;
+		}
 		if (wpa_supplicant_decrypt_key_data(sm, key, mic_len,
 						    ver, key_data,
 						    &key_data_len))
@@ -2427,6 +2440,7 @@
 	}
 
 	if (deauth) {
+		sm->pmk_len = 0;
 		os_memset(sm->pmk, 0, sizeof(sm->pmk));
 		wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
 	}
@@ -3140,7 +3154,7 @@
 int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
 			const void *network_ctx)
 {
-	return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx) != NULL;
+	return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx, 0) != NULL;
 }
 
 
@@ -3149,6 +3163,7 @@
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
 	sm->ptk_set = 0;
 	sm->tptk_set = 0;
+	sm->pmk_len = 0;
 	os_memset(sm->pmk, 0, sizeof(sm->pmk));
 	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
 	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
@@ -3160,8 +3175,11 @@
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R
 	os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+	sm->xxkey_len = 0;
 	os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+	sm->pmk_r0_len = 0;
 	os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+	sm->pmk_r1_len = 0;
 #endif /* CONFIG_IEEE80211R */
 }
 
@@ -3306,6 +3324,12 @@
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
+unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm)
+{
+	return sm->key_mgmt;
+}
+
+
 #ifdef CONFIG_FILS
 
 struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md)
@@ -3531,6 +3555,7 @@
 	os_memcpy(sm->fils_anonce, elems.fils_nonce, FILS_NONCE_LEN);
 	wpa_hexdump(MSG_DEBUG, "FILS: ANonce", sm->fils_anonce, FILS_NONCE_LEN);
 
+#ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
 		struct wpa_ft_ies parse;
 
@@ -3539,7 +3564,8 @@
 			goto fail;
 		}
 
-		if (wpa_ft_parse_ies(pos, end - pos, &parse) < 0) {
+		if (wpa_ft_parse_ies(pos, end - pos, &parse,
+				     wpa_key_mgmt_sha384(sm->key_mgmt)) < 0) {
 			wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs");
 			goto fail;
 		}
@@ -3578,6 +3604,7 @@
 		wpabuf_free(sm->fils_ft_ies);
 		sm->fils_ft_ies = NULL;
 	}
+#endif /* CONFIG_IEEE80211R */
 
 	/* PMKID List */
 	if (rsn.pmkid && rsn.num_pmkid > 0) {
@@ -3738,6 +3765,7 @@
 	struct rsn_ie_hdr *rsnie;
 	u16 capab;
 	u8 *pos;
+	int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
 
 	/* RSNIE[PMKR0Name/PMKR1Name] */
 	rsnie = wpabuf_put(buf, sizeof(*rsnie));
@@ -3805,18 +3833,20 @@
 	if (wpa_derive_pmk_r0(sm->fils_ft, sm->fils_ft_len, sm->ssid,
 			      sm->ssid_len, sm->mobility_domain,
 			      sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
-			      sm->pmk_r0, sm->pmk_r0_name) < 0) {
+			      sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) {
 		wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMK-R0");
 		return -1;
 	}
-	wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+	sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
+	wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
+			sm->pmk_r0, sm->pmk_r0_len);
 	wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
 		    sm->pmk_r0_name, WPA_PMK_NAME_LEN);
 	wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
 		   MAC2STR(sm->r1kh_id));
 	pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
 	if (wpa_derive_pmk_r1_name(sm->pmk_r0_name, sm->r1kh_id, sm->own_addr,
-				   pos) < 0) {
+				   pos, use_sha384) < 0) {
 		wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
 		return -1;
 	}
@@ -4378,8 +4408,10 @@
 		res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
 				      os_strlen(info), sm->pmk, hash_len);
 	os_memset(prk, 0, SHA512_MAC_LEN);
-	if (res < 0)
+	if (res < 0) {
+		sm->pmk_len = 0;
 		return -1;
+	}
 	sm->pmk_len = hash_len;
 
 	wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, sm->pmk_len);
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 81c0171..21f4b17 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -353,6 +353,9 @@
 
 int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
 int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+		    const u8 *mdie);
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm);
 int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 			    int ft_action, const u8 *target_ap,
 			    const u8 *ric_ies, size_t ric_ies_len);
@@ -377,6 +380,12 @@
 	return 0;
 }
 
+static inline int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+				  const u8 *mdie)
+{
+	return 0;
+}
+
 static inline int
 wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 			int ft_action, const u8 *target_ap)
@@ -429,6 +438,7 @@
 int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
 void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
 const u8 * wpa_sm_get_anonce(struct wpa_sm *sm);
+unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm);
 
 struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md);
 int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 1ff7afe..b8d60e3 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/sha384.h"
 #include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -23,6 +24,7 @@
 {
 	u8 ptk_name[WPA_PMK_NAME_LEN];
 	const u8 *anonce = key->key_nonce;
+	int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
 
 	if (sm->xxkey_len == 0) {
 		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
@@ -30,21 +32,26 @@
 		return -1;
 	}
 
-	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
-			  sm->ssid_len, sm->mobility_domain,
-			  sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
-			  sm->pmk_r0, sm->pmk_r0_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+	sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
+	if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
+			      sm->ssid_len, sm->mobility_domain,
+			      sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
+			      sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, sm->pmk_r0_len);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
 		    sm->pmk_r0_name, WPA_PMK_NAME_LEN);
-	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
-			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+	sm->pmk_r1_len = sm->pmk_r0_len;
+	if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
+			      sm->r1kh_id, sm->own_addr, sm->pmk_r1,
+			      sm->pmk_r1_name) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
 		    WPA_PMK_NAME_LEN);
-	return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
-				 sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
-				 sm->key_mgmt, sm->pairwise_cipher);
+	return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
+				 sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
+				 ptk_name, sm->key_mgmt, sm->pairwise_cipher);
 }
 
 
@@ -58,11 +65,13 @@
 int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
 {
 	struct wpa_ft_ies ft;
+	int use_sha384;
 
 	if (sm == NULL)
 		return 0;
 
-	if (wpa_ft_parse_ies(ies, ies_len, &ft) < 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)
@@ -146,16 +155,17 @@
 			       const u8 *ap_mdie)
 {
 	size_t buf_len;
-	u8 *buf, *pos, *ftie_len, *ftie_pos;
+	u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
 	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
 	struct rsn_ie_hdr *rsnie;
 	u16 capab;
+	int mdie_len;
 
 	sm->ft_completed = 0;
 	sm->ft_reassoc_completed = 0;
 
-	buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+	buf_len = 2 + sizeof(struct rsn_mdie) + 2 +
+		sizeof(struct rsn_ftie_sha384) +
 		2 + sm->r0kh_id_len + ric_ies_len + 100;
 	buf = os_zalloc(buf_len);
 	if (buf == NULL)
@@ -201,6 +211,10 @@
 	/* Authenticated Key Management Suite List */
 	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+#ifdef CONFIG_SHA384
+	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+#endif /* CONFIG_SHA384 */
 	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
 	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
@@ -222,7 +236,10 @@
 	/* RSN Capabilities */
 	capab = 0;
 #ifdef CONFIG_IEEE80211W
-	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+	if (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)
 		capab |= WPA_CAPABILITY_MFPC;
 #endif /* CONFIG_IEEE80211W */
 	WPA_PUT_LE16(pos, capab);
@@ -237,34 +254,63 @@
 	pos += WPA_PMK_NAME_LEN;
 
 #ifdef CONFIG_IEEE80211W
-	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
-		/* Management Group Cipher Suite */
+	/* Management Group Cipher Suite */
+	switch (sm->mgmt_group_cipher) {
+	case WPA_CIPHER_AES_128_CMAC:
 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
 		pos += RSN_SELECTOR_LEN;
+		break;
+	case WPA_CIPHER_BIP_GMAC_128:
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
+		pos += RSN_SELECTOR_LEN;
+		break;
+	case WPA_CIPHER_BIP_GMAC_256:
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
+		pos += RSN_SELECTOR_LEN;
+		break;
+	case WPA_CIPHER_BIP_CMAC_256:
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
+		pos += RSN_SELECTOR_LEN;
+		break;
 	}
 #endif /* CONFIG_IEEE80211W */
 
 	rsnie->len = (pos - (u8 *) rsnie) - 2;
 
 	/* MDIE */
-	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
-	*pos++ = sizeof(*mdie);
-	mdie = (struct rsn_mdie *) pos;
-	pos += sizeof(*mdie);
-	os_memcpy(mdie->mobility_domain, sm->mobility_domain,
-		  MOBILITY_DOMAIN_ID_LEN);
-	mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
-		sm->mdie_ft_capab;
+	mdie_len = wpa_ft_add_mdie(sm, pos, buf_len - (pos - buf), ap_mdie);
+	if (mdie_len <= 0) {
+		os_free(buf);
+		return NULL;
+	}
+	mdie = (struct rsn_mdie *) (pos + 2);
+	pos += mdie_len;
 
 	/* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */
 	ftie_pos = pos;
 	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
 	ftie_len = pos++;
-	ftie = (struct rsn_ftie *) pos;
-	pos += sizeof(*ftie);
-	os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
-	if (anonce)
-		os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+	if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
+		struct rsn_ftie_sha384 *ftie;
+
+		ftie = (struct rsn_ftie_sha384 *) pos;
+		fte_mic = ftie->mic;
+		elem_count = &ftie->mic_control[1];
+		pos += sizeof(*ftie);
+		os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+		if (anonce)
+			os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+	} else {
+		struct rsn_ftie *ftie;
+
+		ftie = (struct rsn_ftie *) pos;
+		fte_mic = ftie->mic;
+		elem_count = &ftie->mic_control[1];
+		pos += sizeof(*ftie);
+		os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+		if (anonce)
+			os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+	}
 	if (kck) {
 		/* R1KH-ID sub-element in third FT message */
 		*pos++ = FTIE_SUBELEM_R1KH_ID;
@@ -298,13 +344,12 @@
 		 * RIC-Request (if present)
 		 */
 		/* Information element count */
-		ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
-							       ric_ies_len);
+		*elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
 		if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
 			       ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
 			       ftie_pos, 2 + *ftie_len,
 			       (u8 *) rsnie, 2 + rsnie->len, ric_ies,
-			       ric_ies_len, ftie->mic) < 0) {
+			       ric_ies_len, fte_mic) < 0) {
 			wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
 			os_free(buf);
 			return NULL;
@@ -373,6 +418,37 @@
 }
 
 
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *buf, size_t buf_len,
+		    const u8 *ap_mdie)
+{
+	u8 *pos = buf;
+	struct rsn_mdie *mdie;
+
+	if (buf_len < 2 + sizeof(*mdie)) {
+		wpa_printf(MSG_INFO,
+			   "FT: Failed to add MDIE: short buffer, length=%zu",
+			   buf_len);
+		return 0;
+	}
+
+	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
+	*pos++ = sizeof(*mdie);
+	mdie = (struct rsn_mdie *) pos;
+	os_memcpy(mdie->mobility_domain, sm->mobility_domain,
+		  MOBILITY_DOMAIN_ID_LEN);
+	mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
+		sm->mdie_ft_capab;
+
+	return 2 + sizeof(*mdie);
+}
+
+
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm)
+{
+	return sm->mobility_domain;
+}
+
+
 int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 			    int ft_action, const u8 *target_ap,
 			    const u8 *ric_ies, size_t ric_ies_len)
@@ -381,10 +457,13 @@
 	size_t ft_ies_len;
 	struct wpa_ft_ies parse;
 	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
 	u8 ptk_name[WPA_PMK_NAME_LEN];
 	int ret;
 	const u8 *bssid;
+	const u8 *kck;
+	size_t kck_len;
+	int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+	const u8 *anonce, *snonce;
 
 	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
 	wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
@@ -410,7 +489,7 @@
 		return -1;
 	}
 
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+	if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
 		return -1;
 	}
@@ -423,16 +502,34 @@
 		return -1;
 	}
 
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return -1;
+	if (use_sha384) {
+		struct rsn_ftie_sha384 *ftie;
+
+		ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return -1;
+		}
+
+		anonce = ftie->anonce;
+		snonce = ftie->snonce;
+	} else {
+		struct rsn_ftie *ftie;
+
+		ftie = (struct rsn_ftie *) parse.ftie;
+		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return -1;
+		}
+
+		anonce = ftie->anonce;
+		snonce = ftie->snonce;
 	}
 
-	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+	if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
 		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
-			    ftie->snonce, WPA_NONCE_LEN);
+			    snonce, WPA_NONCE_LEN);
 		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
 			    sm->snonce, WPA_NONCE_LEN);
 		return -1;
@@ -471,23 +568,34 @@
 	os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
-	os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
-	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
-			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
+	os_memcpy(sm->anonce, anonce, WPA_NONCE_LEN);
+	if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
+			      sm->r1kh_id, sm->own_addr, sm->pmk_r1,
+			      sm->pmk_r1_name) < 0)
+		return -1;
+	sm->pmk_r1_len = sm->pmk_r0_len;
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
 		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
 
 	bssid = target_ap;
-	if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
-			      sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
-			      ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+	if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
+			      anonce, sm->own_addr, bssid,
+			      sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
+			      sm->pairwise_cipher) < 0)
 		return -1;
 
-	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
+	if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+		kck = sm->ptk.kck2;
+		kck_len = sm->ptk.kck2_len;
+	} else {
+		kck = sm->ptk.kck;
+		kck_len = sm->ptk.kck_len;
+	}
+	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, anonce,
 				    sm->pmk_r1_name,
-				    sm->ptk.kck, sm->ptk.kck_len, bssid,
+				    kck, kck_len, bssid,
 				    ric_ies, ric_ies_len,
 				    parse.mdie ? parse.mdie - 2 : NULL);
 	if (ft_ies) {
@@ -550,6 +658,16 @@
 	int keyidx;
 	enum wpa_alg alg;
 	size_t gtk_len, keylen, rsc_len;
+	const u8 *kek;
+	size_t kek_len;
+
+	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;
+	}
 
 	if (gtk_elem == NULL) {
 		wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
@@ -566,8 +684,7 @@
 		return -1;
 	}
 	gtk_len = gtk_elem_len - 19;
-	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
-		       gtk)) {
+	if (aes_unwrap(kek, kek_len, gtk_len / 8, gtk_elem + 11, gtk)) {
 		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
 			   "decrypt GTK");
 		return -1;
@@ -621,10 +738,24 @@
 static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
 				       size_t igtk_elem_len)
 {
-	u8 igtk[WPA_IGTK_LEN];
+	u8 igtk[WPA_IGTK_MAX_LEN];
+	size_t igtk_len;
 	u16 keyidx;
+	const u8 *kek;
+	size_t kek_len;
 
-	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+	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;
+	}
+
+	if (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 (igtk_elem == NULL) {
@@ -635,19 +766,19 @@
 	wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
 			igtk_elem, igtk_elem_len);
 
-	if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
+	igtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+	if (igtk_elem_len != 2 + 6 + 1 + igtk_len + 8) {
 		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
 			   "length %lu", (unsigned long) igtk_elem_len);
 		return -1;
 	}
-	if (igtk_elem[8] != WPA_IGTK_LEN) {
+	if (igtk_elem[8] != igtk_len) {
 		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
 			   "%d", igtk_elem[8]);
 		return -1;
 	}
 
-	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
-		       igtk_elem + 9, igtk)) {
+	if (aes_unwrap(kek, kek_len, igtk_len / 8, igtk_elem + 9, igtk)) {
 		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
 			   "decrypt IGTK");
 		return -1;
@@ -658,13 +789,16 @@
 	keyidx = WPA_GET_LE16(igtk_elem);
 
 	wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
-			WPA_IGTK_LEN);
-	if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0,
-			   igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) {
+			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) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
 			   "driver.");
+		os_memset(igtk, 0, sizeof(igtk));
 		return -1;
 	}
+	os_memset(igtk, 0, sizeof(igtk));
 
 	return 0;
 }
@@ -676,9 +810,13 @@
 {
 	struct wpa_ft_ies parse;
 	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
 	unsigned int count;
 	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+	const u8 *kck;
+	size_t kck_len;
+	int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+	const u8 *anonce, *snonce, *fte_mic;
+	u8 fte_elem_count;
 
 	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
 
@@ -693,7 +831,7 @@
 		return 0;
 	}
 
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+	if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
 		return -1;
 	}
@@ -706,25 +844,47 @@
 		return -1;
 	}
 
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return -1;
+	if (use_sha384) {
+		struct rsn_ftie_sha384 *ftie;
+
+		ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return -1;
+		}
+
+		anonce = ftie->anonce;
+		snonce = ftie->snonce;
+		fte_elem_count = ftie->mic_control[1];
+		fte_mic = ftie->mic;
+	} else {
+		struct rsn_ftie *ftie;
+
+		ftie = (struct rsn_ftie *) parse.ftie;
+		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+			return -1;
+		}
+
+		anonce = ftie->anonce;
+		snonce = ftie->snonce;
+		fte_elem_count = ftie->mic_control[1];
+		fte_mic = ftie->mic;
 	}
 
-	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+	if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
 		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
-			    ftie->snonce, WPA_NONCE_LEN);
+			    snonce, WPA_NONCE_LEN);
 		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
 			    sm->snonce, WPA_NONCE_LEN);
 		return -1;
 	}
 
-	if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
+	if (os_memcmp(anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
 		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
-			    ftie->anonce, WPA_NONCE_LEN);
+			    anonce, WPA_NONCE_LEN);
 		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
 			    sm->anonce, WPA_NONCE_LEN);
 		return -1;
@@ -769,14 +929,22 @@
 	count = 3;
 	if (parse.ric)
 		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
-	if (ftie->mic_control[1] != count) {
+	if (fte_elem_count != count) {
 		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
 			   "Control: received %u expected %u",
-			   ftie->mic_control[1], count);
+			   fte_elem_count, count);
 		return -1;
 	}
 
-	if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
+	if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+		kck = sm->ptk.kck2;
+		kck_len = sm->ptk.kck2_len;
+	} else {
+		kck = sm->ptk.kck;
+		kck_len = sm->ptk.kck_len;
+	}
+
+	if (wpa_ft_mic(kck, kck_len, sm->own_addr, src_addr, 6,
 		       parse.mdie - 2, parse.mdie_len + 2,
 		       parse.ftie - 2, parse.ftie_len + 2,
 		       parse.rsn - 2, parse.rsn_len + 2,
@@ -786,9 +954,9 @@
 		return -1;
 	}
 
-	if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+	if (os_memcmp_const(mic, fte_mic, 16) != 0) {
 		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
-		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", fte_mic, 16);
 		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
 		return -1;
 	}
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index e8da194..b94b17a 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -1,6 +1,6 @@
 /*
  * Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -112,11 +112,14 @@
 #endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_IEEE80211R
-	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+	u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
+				* first 384 bits of MSK */
 	size_t xxkey_len;
-	u8 pmk_r0[PMK_LEN];
+	u8 pmk_r0[PMK_LEN_MAX];
+	size_t pmk_r0_len;
 	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
-	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1[PMK_LEN_MAX];
+	size_t pmk_r1_len;
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
 	u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index d649058..a3410d1 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -161,6 +161,10 @@
 #ifdef CONFIG_IEEE80211R
 	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+#ifdef CONFIG_SHA384
+	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+#endif /* CONFIG_SHA384 */
 	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
 #endif /* CONFIG_IEEE80211R */
@@ -200,6 +204,10 @@
 	} else if (key_mgmt & WPA_KEY_MGMT_DPP) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+	} else if (key_mgmt & WPA_KEY_MGMT_OSEN) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+#endif /* CONFIG_HS20 */
 	} else {
 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
 			   key_mgmt);
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index 062e6fe..dfb4b67 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -97,6 +97,7 @@
 	if (pid == 0) {
 		/* run the external command in the child process */
 		char *argv[14];
+		char *envp[] = { "PATH=/system/bin:/vendor/bin", NULL };
 
 		argv[0] = "browser-wpadebug";
 		argv[1] = "start";
@@ -113,8 +114,8 @@
 		argv[12] = "-3"; /* USER_CURRENT_OR_SELF */
 		argv[13] = NULL;
 
-		execv("/system/bin/am", argv);
-		wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+		execve("/system/bin/am", argv, envp);
+		wpa_printf(MSG_ERROR, "execve: %s", strerror(errno));
 		exit(0);
 		return -1;
 	}
diff --git a/src/utils/common.h b/src/utils/common.h
index 46e96a6..f824d00 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -150,6 +150,7 @@
 #define host_to_le32(n) (n)
 #define be_to_host32(n) wpa_swap_32(n)
 #define host_to_be32(n) wpa_swap_32(n)
+#define host_to_le64(n) (n)
 
 #define WPA_BYTE_SWAP_DEFINED
 
@@ -435,6 +436,7 @@
 #define __bitwise __attribute__((bitwise))
 #else
 #define __force
+#undef __bitwise
 #define __bitwise
 #endif
 
diff --git a/src/utils/json.c b/src/utils/json.c
index eae627d..b9130d3 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -230,6 +230,8 @@
 				token = json_alloc_token(&tokens);
 				if (!token)
 					goto fail;
+				if (!root)
+					root = token;
 			} else if (curr_token->state == JSON_WAITING_VALUE) {
 				token = curr_token;
 			} else if (curr_token->parent &&
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 62758d8..a56462b 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -58,6 +58,10 @@
 #ifndef CONFIG_NO_STDOUT_DEBUG
 
 #ifdef CONFIG_DEBUG_FILE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
 static FILE *out_file = NULL;
 #endif /* CONFIG_DEBUG_FILE */
 
@@ -539,6 +543,8 @@
 int wpa_debug_open_file(const char *path)
 {
 #ifdef CONFIG_DEBUG_FILE
+	int out_fd;
+
 	if (!path)
 		return 0;
 
@@ -548,10 +554,28 @@
 		last_path = os_strdup(path);
 	}
 
-	out_file = fopen(path, "a");
+	out_fd = open(path, O_CREAT | O_APPEND | O_WRONLY,
+		      S_IRUSR | S_IWUSR | S_IRGRP);
+	if (out_fd < 0) {
+		wpa_printf(MSG_ERROR,
+			   "%s: Failed to open output file descriptor, using standard output",
+			   __func__);
+		return -1;
+	}
+
+#ifdef __linux__
+	if (fcntl(out_fd, F_SETFD, FD_CLOEXEC) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: Failed to set FD_CLOEXEC - continue without: %s",
+			   __func__, strerror(errno));
+	}
+#endif /* __linux__ */
+
+	out_file = fdopen(out_fd, "a");
 	if (out_file == NULL) {
 		wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
 			   "output file, using standard output");
+		close(out_fd);
 		return -1;
 	}
 #ifndef _WIN32
diff --git a/src/utils/xml-utils.c b/src/utils/xml-utils.c
index a37a92d..dae91fe 100644
--- a/src/utils/xml-utils.c
+++ b/src/utils/xml-utils.c
@@ -246,7 +246,9 @@
 			xml_node_create_text(ctx, tnds, NULL, "Path", uri);
 
 		val = get_val(ctx, node);
-		xml_node_create_text(ctx, tnds, NULL, "Value", val ? val : "");
+		if (val || !xml_node_first_child(ctx, node))
+			xml_node_create_text(ctx, tnds, NULL, "Value",
+					     val ? val : "");
 		xml_node_get_text_free(ctx, val);
 
 		new_uri = add_path(uri, name);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 2e34721..bcae1ba 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -654,6 +654,7 @@
 	pub = wpabuf_zeropad(pub, 192);
 	if (pub == NULL) {
 		wpabuf_free(priv);
+		dh5_free(dh_ctx);
 		return -1;
 	}
 	wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub);
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore
index 0e3ad1b..30e3fd4 100644
--- a/wpa_supplicant/.gitignore
+++ b/wpa_supplicant/.gitignore
@@ -1 +1,2 @@
 *.service
+.settings
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 51ec414..39f8b50 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -12,6 +12,10 @@
   CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
 endif
 
+ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
+  CONFIG_DRIVER_NL80211_QCA=y
+endif
+
 include $(LOCAL_PATH)/android.config
 
 # To ignore possible wrong network configurations
@@ -240,10 +244,6 @@
 NEED_AES_OMAC1=y
 endif
 
-ifdef CONFIG_IEEE80211R_AP
-CONFIG_IEEE80211R=y
-endif
-
 ifdef CONFIG_IEEE80211R
 L_CFLAGS += -DCONFIG_IEEE80211R
 OBJS += src/rsn_supp/wpa_ft.c
@@ -711,6 +711,7 @@
 OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
 CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
+NEED_ECC=y
 endif
 
 ifdef CONFIG_EAP_EKE
@@ -955,10 +956,6 @@
 OBJS += src/ap/wpa_auth.c
 OBJS += src/ap/wpa_auth_ie.c
 OBJS += src/ap/pmksa_cache_auth.c
-ifdef CONFIG_IEEE80211R_AP
-L_CFLAGS += -DCONFIG_IEEE80211R_AP
-OBJS += src/ap/wpa_auth_ft.c
-endif
 endif
 
 ifdef CONFIG_ACS
@@ -1066,22 +1063,33 @@
 endif
 
 ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
 ifdef TLS_FUNCS
 OBJS += src/crypto/tls_gnutls.c
 LIBS += -lgnutls -lgpg-error
 endif
-OBJS += src/crypto/crypto_gnutls.c
-OBJS_p += src/crypto/crypto_gnutls.c
+OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+OBJS_p += src/crypto/crypto_$(CONFIG_CRYPTO).c
 ifdef NEED_FIPS186_2_PRF
 OBJS += src/crypto/fips_prf_internal.c
 OBJS += src/crypto/sha1-internal.c
 endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
 LIBS += -lgcrypt
 LIBS_p += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
 
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
@@ -1268,8 +1276,10 @@
 SHA1OBJS =
 ifdef NEED_SHA1
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 SHA1OBJS += src/crypto/sha1.c
 endif
+endif
 SHA1OBJS += src/crypto/sha1-prf.c
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += src/crypto/sha1-internal.c
@@ -1295,9 +1305,11 @@
 MD5OBJS =
 ifndef CONFIG_FIPS
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 MD5OBJS += src/crypto/md5.c
 endif
 endif
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += src/crypto/md5-internal.c
@@ -1335,8 +1347,10 @@
 ifdef NEED_SHA256
 L_CFLAGS += -DCONFIG_SHA256
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 SHA256OBJS += src/crypto/sha256.c
 endif
+endif
 SHA256OBJS += src/crypto/sha256-prf.c
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += src/crypto/sha256-internal.c
@@ -1369,15 +1383,19 @@
 ifdef NEED_SHA384
 L_CFLAGS += -DCONFIG_SHA384
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 OBJS += src/crypto/sha384.c
 endif
+endif
 OBJS += src/crypto/sha384-prf.c
 endif
 ifdef NEED_SHA512
 L_CFLAGS += -DCONFIG_SHA512
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
 OBJS += src/crypto/sha512.c
 endif
+endif
 OBJS += src/crypto/sha512-prf.c
 endif
 
@@ -1724,6 +1742,7 @@
 ifeq ($(WPA_SUPPLICANT_USE_HIDL), y)
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.0
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.1
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.2
 LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils libbase
 LOCAL_STATIC_LIBRARIES += libwpa_hidl
 endif
@@ -1774,7 +1793,7 @@
 LOCAL_CPPFLAGS := $(L_CPPFLAGS)
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.1
+HIDL_INTERFACE_VERSION = 1.2
 LOCAL_SRC_FILES := \
     hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
     hidl/$(HIDL_INTERFACE_VERSION)/hidl_manager.cpp \
@@ -1787,11 +1806,13 @@
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.wifi.supplicant@1.0 \
     android.hardware.wifi.supplicant@1.1 \
+    android.hardware.wifi.supplicant@1.2 \
     libbase \
     libhidlbase \
     libhidltransport \
     libutils \
-    liblog
+    liblog \
+    libssl
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
     $(LOCAL_PATH)/hidl/$(HIDL_INTERFACE_VERSION)
 include $(BUILD_STATIC_LIBRARY)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 65205d8..c2e93e2 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -246,10 +246,6 @@
 NEED_AES_OMAC1=y
 endif
 
-ifdef CONFIG_IEEE80211R_AP
-CONFIG_IEEE80211R=y
-endif
-
 ifdef CONFIG_IEEE80211R
 CFLAGS += -DCONFIG_IEEE80211R
 OBJS += ../src/rsn_supp/wpa_ft.o
@@ -709,9 +705,13 @@
 
 ifdef CONFIG_EAP_PWD
 CFLAGS += -DEAP_PWD
+ifeq ($(CONFIG_TLS), wolfssl)
+CFLAGS += -DCONFIG_ECC
+endif
 OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
 CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
+NEED_ECC=y
 endif
 
 ifdef CONFIG_EAP_EKE
@@ -966,10 +966,6 @@
 OBJS += ../src/ap/wpa_auth.o
 OBJS += ../src/ap/wpa_auth_ie.o
 OBJS += ../src/ap/pmksa_cache_auth.o
-ifdef CONFIG_IEEE80211R_AP
-CFLAGS += -DCONFIG_IEEE80211R_AP
-OBJS += ../src/ap/wpa_auth_ft.o
-endif
 endif
 
 ifdef CONFIG_ACS
@@ -1053,6 +1049,21 @@
 NEED_SHA256=y
 endif
 
+ifeq ($(CONFIG_TLS), wolfssl)
+ifdef TLS_FUNCS
+CFLAGS += -DWOLFSSL_DER_LOAD -I/usr/local/include/wolfssl
+OBJS += ../src/crypto/tls_wolfssl.o
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+OBJS_p += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+NEED_TLS_PRF_SHA256=y
+LIBS += -lwolfssl -lm
+LIBS_p += -lwolfssl -lm
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 CFLAGS += -DEAP_TLS_OPENSSL
@@ -1081,23 +1092,34 @@
 endif
 
 ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_gnutls.o
 LIBS += -lgnutls -lgpg-error
 endif
-OBJS += ../src/crypto/crypto_gnutls.o
-OBJS_p += ../src/crypto/crypto_gnutls.o
-OBJS_priv += ../src/crypto/crypto_gnutls.o
+OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
 ifdef NEED_FIPS186_2_PRF
 OBJS += ../src/crypto/fips_prf_internal.o
 SHA1OBJS += ../src/crypto/sha1-internal.o
 endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
 LIBS += -lgcrypt
 LIBS_p += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
 CONFIG_INTERNAL_DH_GROUP5=y
 endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
 
 ifeq ($(CONFIG_TLS), internal)
 ifndef CONFIG_CRYPTO
@@ -1262,8 +1284,10 @@
 endif
 
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 NEED_INTERNAL_AES_WRAP=y
 endif
+endif
 ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP
 # Seems to be needed at least with BoringSSL
 NEED_INTERNAL_AES_WRAP=y
@@ -1302,10 +1326,12 @@
 CFLAGS += -DCONFIG_OPENSSL_CMAC
 else
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-omac1.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_WRAP
 NEED_AES_ENC=y
 ifdef NEED_INTERNAL_AES_WRAP
@@ -1316,10 +1342,12 @@
 NEED_AES_ENC=y
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
 AESOBJS += ../src/crypto/aes-cbc.o
 endif
 endif
 endif
+endif
 ifdef NEED_AES_ENC
 ifdef CONFIG_INTERNAL_AES
 AESOBJS += ../src/crypto/aes-internal-enc.o
@@ -1332,9 +1360,13 @@
 ifdef NEED_SHA1
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1.o
 endif
 endif
+endif
+endif
 SHA1OBJS += ../src/crypto/sha1-prf.o
 ifdef CONFIG_INTERNAL_SHA1
 SHA1OBJS += ../src/crypto/sha1-internal.o
@@ -1346,9 +1378,11 @@
 CFLAGS += -DCONFIG_NO_PBKDF2
 else
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
 endif
 endif
+endif
 ifdef NEED_T_PRF
 SHA1OBJS += ../src/crypto/sha1-tprf.o
 endif
@@ -1360,10 +1394,14 @@
 ifndef CONFIG_FIPS
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 MD5OBJS += ../src/crypto/md5.o
 endif
 endif
 endif
+endif
+endif
 ifdef NEED_MD5
 ifdef CONFIG_INTERNAL_MD5
 MD5OBJS += ../src/crypto/md5-internal.o
@@ -1381,6 +1419,9 @@
 
 DESOBJS = # none needed when not internal
 ifdef NEED_DES
+ifndef CONFIG_FIPS
+CFLAGS += -DCONFIG_DES
+endif
 ifdef CONFIG_INTERNAL_DES
 DESOBJS += ../src/crypto/des-internal.o
 endif
@@ -1403,9 +1444,13 @@
 CFLAGS += -DCONFIG_SHA256
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 SHA256OBJS += ../src/crypto/sha256.o
 endif
 endif
+endif
+endif
 SHA256OBJS += ../src/crypto/sha256-prf.o
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += ../src/crypto/sha256-internal.o
@@ -1438,18 +1483,26 @@
 ifdef NEED_SHA384
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha384.o
 endif
 endif
+endif
+endif
 CFLAGS += -DCONFIG_SHA384
 OBJS += ../src/crypto/sha384-prf.o
 endif
 ifdef NEED_SHA512
 ifneq ($(CONFIG_TLS), openssl)
 ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
 OBJS += ../src/crypto/sha512.o
 endif
 endif
+endif
+endif
 CFLAGS += -DCONFIG_SHA512
 OBJS += ../src/crypto/sha512-prf.o
 endif
@@ -1646,9 +1699,11 @@
 ifdef CONFIG_FIPS
 CFLAGS += -DCONFIG_FIPS
 ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
 $(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
 endif
 endif
+endif
 
 OBJS += $(SHA1OBJS) $(DESOBJS)
 
@@ -1846,7 +1901,7 @@
 	@$(E) "  LD " $@
 
 wpa_passphrase: $(OBJS_p)
-	$(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+	$(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) $(LIBS)
 	@$(E) "  LD " $@
 
 wpa_cli: $(OBJS_c)
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index e4eed20..3342871 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -197,6 +197,20 @@
 #	pre-configured with the credential since the NAI Realm information
 #	may not be available or fetched.
 #
+# required_roaming_consortium: Required Roaming Consortium OI
+#	If required_roaming_consortium_len is non-zero, this field contains the
+#	Roaming Consortium OI that is required to be advertised by the AP for
+#	the credential to be considered matching.
+#
+# roaming_consortiums: Roaming Consortium OI(s) memberships
+#	This string field contains one or more comma delimited OIs (hexdump)
+#	identifying the roaming consortiums of which the provider is a member.
+#	The list is sorted from the most preferred one to the least preferred
+#	one. A match between the Roaming Consortium OIs advertised by an AP and
+#	the OIs in this list indicates that successful authentication is
+#	possible.
+#	(Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+#
 # eap: Pre-configured EAP method
 #	This optional field can be used to specify which EAP method will be
 #	used with this credential. If not set, the EAP method is selected
@@ -295,6 +309,7 @@
 #	ca_cert="/etc/wpa_supplicant/ca.pem"
 #	domain="example.com"
 #	roaming_consortium=223344
+#	roaming_consortiums="112233,4455667788,aabbcc"
 #	eap=TTLS
 #	phase2="auth=MSCHAPV2"
 #}
@@ -591,7 +606,7 @@
 Hotspot 2.0 connection with external network selection
 ------------------------------------------------------
 
-When an component controlling wpa_supplicant takes care of Interworking
+When a component controlling wpa_supplicant takes care of Interworking
 network selection, following configuration and network profile
 parameters can be used to configure a temporary network profile for a
 Hotspot 2.0 connection (e.g., with SET, ADD_NETWORK, SET_NETWORK, and
@@ -613,6 +628,7 @@
     eap=TTLS
     phase2="auth=MSCHAPV2"
     update_identifier=54321
+    roaming_consortium_selection=112233
     #ocsp=2
 }
 
@@ -628,4 +644,5 @@
 ca_cert: from the downloaded trust root based on PPS information
 eap: Credential/UsernamePassword/EAPMethod or NAI Realm list
 phase2: Credential/UsernamePassword/EAPMethod or NAI Realm list
+roaming_consortium_selection: Matching OI from HomeSP/RoamingConsortiumOI
 ocsp: Credential/CheckAAAServerCertStatus
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index fd65584..d4146db 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -32,9 +32,6 @@
 #CONFIG_DRIVER_NL80211=y
 CONFIG_LIBNL20=y
 
-# QCA vendor extensions to nl80211
-CONFIG_DRIVER_NL80211_QCA=y
-
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
@@ -366,10 +363,6 @@
 # IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
 CONFIG_IEEE80211R=y
 
-# IEEE Std 802.11r-2008 (Fast BSS Transition) for AP mode (implies
-# CONFIG_IEEE80211R).
-#CONFIG_IEEE80211R_AP=y
-
 # Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
 #CONFIG_DEBUG_FILE=y
 
@@ -550,6 +543,15 @@
 
 # Opportunistic Wireless Encryption (OWE)
 # Experimental implementation of draft-harkins-owe-07.txt
-#CONFIG_OWE=y
+CONFIG_OWE=y
+
+# Easy Connect (Device Provisioning Protocol - DPP)
+CONFIG_DPP=y
+
+# WPA3-Personal (SAE)
+CONFIG_SAE=y
+
+# WPA3-Enterprise (SuiteB-192)
+CONFIG_SUITEB192=y
 
 include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6668d58..ea846a0 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -71,6 +71,8 @@
 			goto no_vht;
 		ieee80211_freq_to_chan(ssid->vht_center_freq1,
 				       &conf->vht_oper_centr_freq_seg0_idx);
+		wpa_printf(MSG_DEBUG, "VHT seg0 index %d for AP",
+			   conf->vht_oper_centr_freq_seg0_idx);
 		return;
 	}
 
@@ -79,9 +81,15 @@
 	case VHT_CHANWIDTH_80MHZ:
 	case VHT_CHANWIDTH_80P80MHZ:
 		center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+		wpa_printf(MSG_DEBUG,
+			   "VHT center channel %u for 80 or 80+80 MHz bandwidth",
+			   center_chan);
 		break;
 	case VHT_CHANWIDTH_160MHZ:
 		center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+		wpa_printf(MSG_DEBUG,
+			   "VHT center channel %u for 160 MHz bandwidth",
+			   center_chan);
 		break;
 	default:
 		/*
@@ -91,10 +99,17 @@
 		 */
 		conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
 		center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
-		if (!center_chan) {
+		if (center_chan) {
+			wpa_printf(MSG_DEBUG,
+				   "VHT center channel %u for auto-selected 160 MHz bandwidth",
+				   center_chan);
+		} else {
 			conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
 			center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
 								channel);
+			wpa_printf(MSG_DEBUG,
+				   "VHT center channel %u for auto-selected 80 MHz bandwidth",
+				   center_chan);
 		}
 		break;
 	}
@@ -102,10 +117,15 @@
 		goto no_vht;
 
 	conf->vht_oper_centr_freq_seg0_idx = center_chan;
+	wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO",
+		   conf->vht_oper_centr_freq_seg0_idx);
 	return;
 #endif /* CONFIG_P2P */
 
 no_vht:
+	wpa_printf(MSG_DEBUG,
+		   "No VHT higher bandwidth support for the selected channel %d",
+		   conf->channel);
 	conf->vht_oper_centr_freq_seg0_idx =
 		conf->channel + conf->secondary_channel * 2;
 	conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
@@ -139,6 +159,11 @@
 	if (wpa_s->hw.modes) {
 		struct hostapd_hw_modes *mode = NULL;
 		int i, no_ht = 0;
+
+		wpa_printf(MSG_DEBUG,
+			   "Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)",
+			   ssid->frequency, conf->channel);
+
 		for (i = 0; i < wpa_s->hw.num_modes; i++) {
 			if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
 				mode = &wpa_s->hw.modes[i];
@@ -152,28 +177,45 @@
 #endif /* CONFIG_HT_OVERRIDES */
 
 		if (!ssid->ht) {
+			wpa_printf(MSG_DEBUG,
+				   "HT not enabled in network profile");
 			conf->ieee80211n = 0;
 			conf->ht_capab = 0;
 			no_ht = 1;
 		}
 
 		if (!no_ht && mode && mode->ht_capab) {
+			wpa_printf(MSG_DEBUG,
+				   "Enable HT support (p2p_group=%d 11a=%d ht40_hw_capab=%d ssid->ht40=%d)",
+				   ssid->p2p_group,
+				   conf->hw_mode == HOSTAPD_MODE_IEEE80211A,
+				   !!(mode->ht_capab &
+				      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET),
+				   ssid->ht40);
 			conf->ieee80211n = 1;
 #ifdef CONFIG_P2P
 			if (ssid->p2p_group &&
 			    conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
 			    (mode->ht_capab &
 			     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
-			    ssid->ht40)
+			    ssid->ht40) {
 				conf->secondary_channel =
 					wpas_p2p_get_ht40_mode(wpa_s, mode,
 							       conf->channel);
+				wpa_printf(MSG_DEBUG,
+					   "HT secondary channel offset %d for P2P group",
+					   conf->secondary_channel);
+			}
 #endif /* CONFIG_P2P */
 
 			if (!ssid->p2p_group &&
 			    (mode->ht_capab &
-			     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
 				conf->secondary_channel = ssid->ht40;
+				wpa_printf(MSG_DEBUG,
+					   "HT secondary channel offset %d for AP",
+					   conf->secondary_channel);
+			}
 
 			if (conf->secondary_channel)
 				conf->ht_capab |=
@@ -256,7 +298,8 @@
 	}
 #endif /* CONFIG_ACS */
 
-	if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
+	if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
+			     wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
 		conf->ieee80211h = 1;
 		conf->ieee80211d = 1;
 		conf->country[0] = wpa_s->conf->country[0];
@@ -506,6 +549,9 @@
 	else
 		bss->max_num_sta = wpa_s->conf->max_num_sta;
 
+	if (!bss->isolate)
+		bss->isolate = wpa_s->conf->ap_isolate;
+
 	bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
 
 	if (wpa_s->conf->ap_vendor_elements) {
@@ -630,9 +676,18 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
+	wpa_printf(MSG_DEBUG, "AP interface setup completed - state %s",
+		   hostapd_state_text(wpa_s->ap_iface->state));
+	if (wpa_s->ap_iface->state == HAPD_IFACE_DISABLED) {
+		wpa_supplicant_ap_deinit(wpa_s);
+		return;
+	}
+
 #ifdef CONFIG_ACS
-	if (wpa_s->current_ssid && wpa_s->current_ssid->acs)
+	if (wpa_s->current_ssid && wpa_s->current_ssid->acs) {
 		wpa_s->assoc_freq = wpa_s->ap_iface->freq;
+		wpa_s->current_ssid->frequency = wpa_s->ap_iface->freq;
+	}
 #endif /* CONFIG_ACS */
 
 	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
@@ -707,7 +762,8 @@
 	else
 		params.uapsd = -1;
 
-	if (ieee80211_is_dfs(params.freq.freq))
+	if (ieee80211_is_dfs(params.freq.freq, wpa_s->hw.modes,
+			     wpa_s->hw.num_modes))
 		params.freq.freq = 0; /* set channel after CAC */
 
 	if (params.p2p)
@@ -815,6 +871,14 @@
 	os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
 	wpa_s->assoc_freq = ssid->frequency;
 
+#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
+	if (wpa_s->p2p_go_do_acs) {
+		wpa_s->ap_iface->conf->channel = 0;
+		wpa_s->ap_iface->conf->hw_mode = wpa_s->p2p_go_acs_band;
+		ssid->acs = 1;
+	}
+#endif /* CONFIG_P2P && CONFIG_ACS */
+
 	if (hostapd_setup_interface(wpa_s->ap_iface)) {
 		wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
 		wpa_supplicant_ap_deinit(wpa_s);
@@ -1515,8 +1579,8 @@
 
 
 #ifdef NEED_AP_MLME
-void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
-				   struct dfs_event *radar)
+void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+				      struct dfs_event *radar)
 {
 	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
 		return;
@@ -1528,8 +1592,8 @@
 }
 
 
-void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
-				struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+				   struct dfs_event *radar)
 {
 	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
 		return;
@@ -1540,8 +1604,8 @@
 }
 
 
-void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
-				 struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+				    struct dfs_event *radar)
 {
 	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
 		return;
@@ -1552,8 +1616,8 @@
 }
 
 
-void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
-				struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+				   struct dfs_event *radar)
 {
 	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
 		return;
@@ -1564,8 +1628,8 @@
 }
 
 
-void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
-				     struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+					struct dfs_event *radar)
 {
 	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
 		return;
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 3fa656f..447b551 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -89,16 +89,16 @@
 				  char *buf, size_t len);
 int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd);
 
-void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+				      struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
 				   struct dfs_event *radar);
-void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
-				struct dfs_event *radar);
-void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
-				 struct dfs_event *radar);
-void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
-				struct dfs_event *radar);
-void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
-				     struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+				    struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+				   struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+					struct dfs_event *radar);
 
 void ap_periodic(struct wpa_supplicant *wpa_s);
 
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 708b58a..3a41db9 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -102,6 +102,8 @@
 	ANQP_DUP(hs20_connection_capability);
 	ANQP_DUP(hs20_operating_class);
 	ANQP_DUP(hs20_osu_providers_list);
+	ANQP_DUP(hs20_operator_icon_metadata);
+	ANQP_DUP(hs20_osu_providers_nai_list);
 #endif /* CONFIG_HS20 */
 #undef ANQP_DUP
 
@@ -185,6 +187,8 @@
 	wpabuf_free(anqp->hs20_connection_capability);
 	wpabuf_free(anqp->hs20_operating_class);
 	wpabuf_free(anqp->hs20_osu_providers_list);
+	wpabuf_free(anqp->hs20_operator_icon_metadata);
+	wpabuf_free(anqp->hs20_osu_providers_nai_list);
 #endif /* CONFIG_HS20 */
 
 	os_free(anqp);
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 37d9fb6..5251b2c 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -50,6 +50,8 @@
 	struct wpabuf *hs20_connection_capability;
 	struct wpabuf *hs20_operating_class;
 	struct wpabuf *hs20_osu_providers_list;
+	struct wpabuf *hs20_operator_icon_metadata;
+	struct wpabuf *hs20_osu_providers_nai_list;
 #endif /* CONFIG_HS20 */
 };
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a22434c..5cdc059 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -735,6 +735,10 @@
 			val |= WPA_KEY_MGMT_FT_PSK;
 		else if (os_strcmp(start, "FT-EAP") == 0)
 			val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+		else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
+			val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_IEEE80211W
 		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
@@ -892,6 +896,18 @@
 		}
 		pos += ret;
 	}
+
+#ifdef CONFIG_SHA384
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+		ret = os_snprintf(pos, end - pos, "%sFT-EAP-SHA384",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret)) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+#endif /* CONFIG_SHA384 */
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211W
@@ -2134,6 +2150,7 @@
 	{ FUNC_KEY(psk) },
 	{ INT(mem_only_psk) },
 	{ STR_KEY(sae_password) },
+	{ STR(sae_password_id) },
 	{ FUNC(proto) },
 	{ FUNC(key_mgmt) },
 	{ INT(bg_scan_period) },
@@ -2289,6 +2306,7 @@
 #endif /* CONFIG_MACSEC */
 #ifdef CONFIG_HS20
 	{ INT(update_identifier) },
+	{ STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) },
 #endif /* CONFIG_HS20 */
 	{ INT_RANGE(mac_addr, 0, 2) },
 	{ INT_RANGE(pbss, 0, 2) },
@@ -2301,6 +2319,7 @@
 	{ STR_LEN(dpp_csign) },
 #endif /* CONFIG_DPP */
 	{ INT_RANGE(owe_group, 0, 65535) },
+	{ INT_RANGE(owe_only, 0, 1) },
 };
 
 #undef OFFSET
@@ -2472,6 +2491,7 @@
 	str_clear_free(ssid->passphrase);
 	os_free(ssid->ext_psk);
 	str_clear_free(ssid->sae_password);
+	os_free(ssid->sae_password_id);
 #ifdef IEEE8021X_EAPOL
 	eap_peer_config_free(&ssid->eap);
 #endif /* IEEE8021X_EAPOL */
@@ -2488,6 +2508,9 @@
 #ifdef CONFIG_MESH
 	os_free(ssid->mesh_basic_rates);
 #endif /* CONFIG_MESH */
+#ifdef CONFIG_HS20
+	os_free(ssid->roaming_consortium_selection);
+#endif /* CONFIG_HS20 */
 	os_free(ssid->dpp_connector);
 	bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
 	os_free(ssid->dpp_csign);
@@ -3103,11 +3126,64 @@
 }
 
 
+static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred,
+						   const char *value)
+{
+	u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
+	size_t roaming_consortiums_len[MAX_ROAMING_CONS];
+	unsigned int num_roaming_consortiums = 0;
+	const char *pos, *end;
+	size_t len;
+
+	os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums));
+	os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len));
+
+	for (pos = value;;) {
+		end = os_strchr(pos, ',');
+		len = end ? (size_t) (end - pos) : os_strlen(pos);
+		if (!end && len == 0)
+			break;
+		if (len == 0 || (len & 1) != 0 ||
+		    len / 2 > MAX_ROAMING_CONS_OI_LEN ||
+		    hexstr2bin(pos,
+			       roaming_consortiums[num_roaming_consortiums],
+			       len / 2) < 0) {
+			wpa_printf(MSG_INFO,
+				   "Invalid roaming_consortiums entry: %s",
+				   pos);
+			return -1;
+		}
+		roaming_consortiums_len[num_roaming_consortiums] = len / 2;
+		num_roaming_consortiums++;
+
+		if (!end)
+			break;
+
+		if (num_roaming_consortiums >= MAX_ROAMING_CONS) {
+			wpa_printf(MSG_INFO,
+				   "Too many roaming_consortiums OIs");
+			return -1;
+		}
+
+		pos = end + 1;
+	}
+
+	os_memcpy(cred->roaming_consortiums, roaming_consortiums,
+		  sizeof(roaming_consortiums));
+	os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len,
+		  sizeof(roaming_consortiums_len));
+	cred->num_roaming_consortiums = num_roaming_consortiums;
+
+	return 0;
+}
+
+
 int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
 			const char *value, int line)
 {
 	char *val;
 	size_t len;
+	int res;
 
 	if (os_strcmp(var, "temporary") == 0) {
 		cred->temporary = atoi(value);
@@ -3330,6 +3406,16 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "roaming_consortiums") == 0) {
+		res = wpa_config_set_cred_roaming_consortiums(cred, val);
+		if (res < 0)
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid roaming_consortiums",
+				   line);
+		os_free(val);
+		return res;
+	}
+
 	if (os_strcmp(var, "excluded_ssid") == 0) {
 		struct excluded_ssid *e;
 
@@ -3641,6 +3727,31 @@
 		return buf;
 	}
 
+	if (os_strcmp(var, "roaming_consortiums") == 0) {
+		size_t buflen;
+		char *buf, *pos;
+		size_t i;
+
+		if (!cred->num_roaming_consortiums)
+			return NULL;
+		buflen = cred->num_roaming_consortiums *
+			MAX_ROAMING_CONS_OI_LEN * 2 + 1;
+		buf = os_malloc(buflen);
+		if (!buf)
+			return NULL;
+		pos = buf;
+		for (i = 0; i < cred->num_roaming_consortiums; i++) {
+			if (i > 0)
+				*pos++ = ',';
+			pos += wpa_snprintf_hex(
+				pos, buf + buflen - pos,
+				cred->roaming_consortiums[i],
+				cred->roaming_consortiums_len[i]);
+		}
+		*pos = '\0';
+		return buf;
+	}
+
 	if (os_strcmp(var, "excluded_ssid") == 0) {
 		unsigned int i;
 		char *buf, *end, *pos;
@@ -3898,6 +4009,7 @@
 	config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
 	config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
 	config->max_num_sta = DEFAULT_MAX_NUM_STA;
+	config->ap_isolate = DEFAULT_AP_ISOLATE;
 	config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
 	config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
 	config->wmm_ac_params[0] = ac_be;
@@ -4328,6 +4440,20 @@
 	return 0;
 }
 
+static int wpa_config_process_p2p_device_persistent_mac_addr(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	if (hwaddr_aton2(pos, config->p2p_device_persistent_mac_addr) < 0) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: Invalid p2p_device_persistent_mac_addr '%s'",
+			   line, pos);
+		return -1;
+	}
+
+	return 0;
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -4569,6 +4695,9 @@
 	{ IPV4(ip_addr_start), 0 },
 	{ IPV4(ip_addr_end), 0 },
 	{ INT_RANGE(p2p_cli_probe, 0, 1), 0 },
+	{ INT(p2p_device_random_mac_addr), 0 },
+	{ FUNC(p2p_device_persistent_mac_addr), 0 },
+	{ INT(p2p_interface_random_mac_addr), 0 },
 #endif /* CONFIG_P2P */
 	{ FUNC(country), CFG_CHANGED_COUNTRY },
 	{ INT(bss_max_count), 0 },
@@ -4577,6 +4706,7 @@
 	{ INT_RANGE(filter_ssids, 0, 1), 0 },
 	{ INT_RANGE(filter_rssi, -100, 0), 0 },
 	{ INT(max_num_sta), 0 },
+	{ INT_RANGE(ap_isolate, 0, 1), 0 },
 	{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
 #ifdef CONFIG_HS20
 	{ INT_RANGE(hs20, 0, 1), 0 },
@@ -4642,6 +4772,9 @@
 	{ INT(gas_rand_addr_lifetime), 0 },
 	{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
 	{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
+	{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
+	{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
+	{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 07b67e6..6eb0074 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -32,6 +32,7 @@
 #define DEFAULT_BSS_EXPIRATION_AGE 180
 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
 #define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_AP_ISOLATE 0
 #define DEFAULT_ACCESS_NETWORK_TYPE 15
 #define DEFAULT_SCAN_CUR_FREQ 0
 #define DEFAULT_P2P_SEARCH_DELAY 500
@@ -50,6 +51,9 @@
 #include "common/ieee802_11_common.h"
 
 
+#define MAX_ROAMING_CONS 36
+#define MAX_ROAMING_CONS_OI_LEN 15
+
 struct wpa_cred {
 	/**
 	 * next - Next credential in the list
@@ -224,10 +228,43 @@
 	 */
 	size_t roaming_consortium_len;
 
+	/**
+	 * required_roaming_consortium - Required Roaming Consortium OI
+	 *
+	 * If required_roaming_consortium_len is non-zero, this field contains
+	 * the Roaming Consortium OI that is required to be advertised by the AP
+	 * for the credential to be considered matching.
+	 */
 	u8 required_roaming_consortium[15];
+
+	/**
+	 * required_roaming_consortium_len - Length of required_roaming_consortium
+	 */
 	size_t required_roaming_consortium_len;
 
 	/**
+	 * roaming_consortiums - Roaming Consortium OI(s) memberships
+	 *
+	 * This field contains one or more OIs identifying the roaming
+	 * consortiums of which the provider is a member. The list is sorted
+	 * from the most preferred one to the least preferred one. A match
+	 * between the Roaming Consortium OIs advertised by an AP and the OIs
+	 * in this list indicates that successful authentication is possible.
+	 * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+	 */
+	u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
+
+	/**
+	 * roaming_consortiums_len - Length on roaming_consortiums[i]
+	 */
+	size_t roaming_consortiums_len[MAX_ROAMING_CONS];
+
+	/**
+	 * num_roaming_consortiums - Number of entries in roaming_consortiums
+	 */
+	unsigned int num_roaming_consortiums;
+
+	/**
 	 * eap_method - EAP method to use
 	 *
 	 * Pre-configured EAP method to use with this credential or %NULL to
@@ -843,6 +880,20 @@
 	unsigned int max_num_sta;
 
 	/**
+	 * ap_isolate - Whether to use client isolation feature
+	 *
+	 * Client isolation can be used to prevent low-level bridging of
+	 * frames between associated stations in the BSS. By default,
+	 * this bridging is allowed (ap_isolate=0); except in P2P GO case,
+	 * where p2p_intra_bss parameter is used to determine whether to allow
+	 * intra-BSS forwarding (ap_isolate = !p2p_intra_bss).
+	 *
+	 * 0 = do not enable AP isolation
+	 * 1 = enable AP isolation
+	 */
+	int ap_isolate;
+
+	/**
 	 * freq_list - Array of allowed scan frequencies or %NULL for all
 	 *
 	 * This is an optional zero-terminated array of frequencies in
@@ -864,7 +915,7 @@
 	unsigned int changed_parameters;
 
 	/**
-	 * disassoc_low_ack - Disassocicate stations with massive packet loss
+	 * disassoc_low_ack - Disassociate stations with massive packet loss
 	 */
 	int disassoc_low_ack;
 
@@ -1418,6 +1469,52 @@
 	 *	profile automatically
 	 */
 	int dpp_config_processing;
+
+	/**
+	 * coloc_intf_reporting - Colocated interference reporting
+	 *
+	 * dot11CoLocIntfReportingActivated
+	 * 0 = disabled (false)
+	 * 1 = enabled (true)
+	 */
+	int coloc_intf_reporting;
+
+	/**
+	 * p2p_device_random_mac_addr - P2P Device MAC address policy default
+	 *
+	 * 0 = use permanent MAC address
+	 * 1 = use random MAC address on creating the interface if there is no persistent groups.
+	 *
+	 * By default, permanent MAC address is used.
+	 */
+	int p2p_device_random_mac_addr;
+
+	/**
+	 * p2p_device_persistent_mac_addr - Record last used MAC address
+	 *
+	 * If there are saved persistent groups, P2P cannot generate another random MAC address,
+	 * and need to restore to last used MAC address.
+	 * format: aa:bb:cc:dd:ee:ff
+	 */
+	u8 p2p_device_persistent_mac_addr[ETH_ALEN];
+
+	/**
+	 * p2p_interface_random_mac_addr - P2P Interface MAC address policy default
+	 *
+	 * 0 = use permanent MAC address
+	 * 1 = use random MAC address on creating the interface.
+	 *
+	 * By default, permanent MAC address is used.
+	 */
+	int p2p_interface_random_mac_addr;
+
+	/**
+	 * bss_no_flush_when_down - Whether to flush BSS entries when the interface is disabled
+	 *
+	 * 0 = Flush BSS entries when the interface becomes disabled (Default)
+	 * 1 = Do not flush BSS entries when the interface becomes disabled
+	 */
+	int bss_no_flush_when_down;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 1fd432d..becc809 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -141,8 +141,9 @@
 		ssid->p2p_persistent_group = 1;
 
 	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
-	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
-	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+	    !(ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+				       WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256 |
+				       WPA_CIPHER_NONE))) {
 		/* Group cipher cannot be stronger than the pairwise cipher. */
 		wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
 			   " list since it was not allowed for pairwise "
@@ -464,7 +465,8 @@
 
 #ifndef WPA_IGNORE_CONFIG_ERRORS
 	if (errors) {
-		wpa_config_free(config);
+		if (config != cfgp)
+			wpa_config_free(config);
 		config = NULL;
 		head = NULL;
 	}
@@ -747,6 +749,7 @@
 	write_psk(f, ssid);
 	INT(mem_only_psk);
 	STR(sae_password);
+	STR(sae_password_id);
 	write_proto(f, ssid);
 	write_key_mgmt(f, ssid);
 	INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
@@ -855,6 +858,7 @@
 #endif /* CONFIG_MACSEC */
 #ifdef CONFIG_HS20
 	INT(update_identifier);
+	STR(roaming_consortium_selection);
 #endif /* CONFIG_HS20 */
 	write_int(f, "mac_addr", ssid->mac_addr, -1);
 #ifdef CONFIG_MESH
@@ -875,6 +879,7 @@
 	STR(dpp_csign);
 #endif /* CONFIG_DPP */
 	INT(owe_group);
+	INT(owe_only);
 #ifdef CONFIG_HT_OVERRIDES
 	INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
 	INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
@@ -1037,6 +1042,20 @@
 		fprintf(f, "\n");
 	}
 
+	if (cred->num_roaming_consortiums) {
+		size_t j;
+
+		fprintf(f, "\troaming_consortiums=\"");
+		for (i = 0; i < cred->num_roaming_consortiums; i++) {
+			if (i > 0)
+				fprintf(f, ",");
+			for (j = 0; j < cred->roaming_consortiums_len[i]; j++)
+				fprintf(f, "%02x",
+					cred->roaming_consortiums[i][j]);
+		}
+		fprintf(f, "\"\n");
+	}
+
 	if (cred->sim_num != DEFAULT_USER_SELECTED_SIM)
 		fprintf(f, "\tsim_num=%d\n", cred->sim_num);
 }
@@ -1280,6 +1299,8 @@
 		fprintf(f, "filter_rssi=%d\n", config->filter_rssi);
 	if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
 		fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
+	if (config->ap_isolate != DEFAULT_AP_ISOLATE)
+		fprintf(f, "ap_isolate=%u\n", config->ap_isolate);
 	if (config->disassoc_low_ack)
 		fprintf(f, "disassoc_low_ack=%d\n", config->disassoc_low_ack);
 #ifdef CONFIG_HS20
@@ -1490,7 +1511,21 @@
 	if (config->dpp_config_processing)
 		fprintf(f, "dpp_config_processing=%d\n",
 			config->dpp_config_processing);
-
+	if (config->coloc_intf_reporting)
+		fprintf(f, "coloc_intf_reporting=%d\n",
+			config->coloc_intf_reporting);
+	if (config->p2p_device_random_mac_addr)
+		fprintf(f, "p2p_device_random_mac_addr=%d\n",
+			config->p2p_device_random_mac_addr);
+	if (!is_zero_ether_addr(config->p2p_device_persistent_mac_addr))
+		fprintf(f, "p2p_device_persistent_mac_addr=" MACSTR "\n",
+			MAC2STR(config->p2p_device_persistent_mac_addr));
+	if (config->p2p_interface_random_mac_addr)
+		fprintf(f, "p2p_interface_random_mac_addr=%d\n",
+			config->p2p_interface_random_mac_addr);
+	if (config->bss_no_flush_when_down)
+		fprintf(f, "bss_no_flush_when_down=%d\n",
+			config->bss_no_flush_when_down);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 83d657d..d2a52d7 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -194,6 +194,14 @@
 	char *sae_password;
 
 	/**
+	 * sae_password_id - SAE password identifier
+	 *
+	 * This parameter can be used to identify a specific SAE password. If
+	 * not included, the default SAE password is used instead.
+	 */
+	char *sae_password_id;
+
+	/**
 	 * ext_psk - PSK/passphrase name in external storage
 	 *
 	 * If this is set, PSK/passphrase will be fetched from external storage
@@ -497,7 +505,7 @@
 
 	int vht;
 
-	u8 max_oper_chwidth;
+	int max_oper_chwidth;
 
 	unsigned int vht_center_freq1;
 	unsigned int vht_center_freq2;
@@ -804,6 +812,19 @@
 
 #ifdef CONFIG_HS20
 	int update_identifier;
+
+	/**
+	 * roaming_consortium_selection - Roaming Consortium Selection
+	 *
+	 * The matching Roaming Consortium OI that was used to generate this
+	 * network profile.
+	 */
+	u8 *roaming_consortium_selection;
+
+	/**
+	 * roaming_consortium_selection_len - roaming_consortium_selection len
+	 */
+	size_t roaming_consortium_selection_len;
 #endif /* CONFIG_HS20 */
 
 	unsigned int wps_run;
@@ -889,13 +910,33 @@
 	/**
 	 * owe_group - OWE DH Group
 	 *
-	 * 0 = use default (19)
+	 * 0 = use default (19) first and then try all supported groups one by
+	 *	one if AP rejects the selected group
 	 * 1-65535 DH Group to use for OWE
 	 *
 	 * Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are
 	 * currently supported.
 	 */
 	int owe_group;
+
+	/**
+	 * owe_only - OWE-only mode (disable transition mode)
+	 *
+	 * 0 = enable transition mode (allow connection to either OWE or open
+	 *	BSS)
+	 * 1 = disable transition mode (allow connection only with OWE)
+	 */
+	int owe_only;
+
+	/**
+	 * owe_transition_bss_select_count - OWE transition BSS select count
+	 *
+	 * This is an internally used variable (i.e., not used in external
+	 * configuration) to track the number of selection attempts done for
+	 * OWE BSS in transition mode. This allows fallback to an open BSS if
+	 * the selection attempts for OWE BSS exceed the configured threshold.
+	 */
+	int owe_transition_bss_select_count;
 };
 
 #endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 0ba1aa5..0ce1830 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -619,6 +619,8 @@
 				   config->filter_ssids, 0);
 	wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
 				   config->max_num_sta, DEFAULT_MAX_NUM_STA);
+	wpa_config_write_reg_dword(hk, TEXT("ap_isolate"),
+				   config->ap_isolate, DEFAULT_AP_ISOLATE);
 	wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
 				   config->disassoc_low_ack, 0);
 
@@ -871,6 +873,7 @@
 	write_bssid(netw, ssid);
 	write_psk(netw, ssid);
 	STR(sae_password);
+	STR(sae_password_id);
 	write_proto(netw, ssid);
 	write_key_mgmt(netw, ssid);
 	write_pairwise(netw, ssid);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index c4d8dfe..77a3133 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -20,6 +20,9 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#ifdef CONFIG_DPP
+#include "common/dpp.h"
+#endif /* CONFIG_DPP */
 #include "crypto/tls.h"
 #include "ap/hostapd.h"
 #include "eap_peer/eap.h"
@@ -63,28 +66,6 @@
 					char *val);
 
 
-#ifdef CONFIG_FILS
-
-static int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
-{
-	return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
-		 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
-		(!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
-		 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
-}
-
-
-#ifdef CONFIG_FILS_SK_PFS
-static int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
-{
-	return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
-		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
-}
-#endif /* CONFIG_FILS_SK_PFS */
-
-#endif /* CONFIG_FILS */
-
-
 static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
 {
 	char *pos;
@@ -604,6 +585,54 @@
 	} else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
 		os_free(wpa_s->dpp_configurator_params);
 		wpa_s->dpp_configurator_params = os_strdup(value);
+	} else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
+		wpa_s->dpp_init_max_tries = atoi(value);
+	} else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
+		wpa_s->dpp_init_retry_time = atoi(value);
+	} else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
+		wpa_s->dpp_resp_wait_time = atoi(value);
+	} else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
+		wpa_s->dpp_resp_max_tries = atoi(value);
+	} else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
+		wpa_s->dpp_resp_retry_time = atoi(value);
+#ifdef CONFIG_TESTING_OPTIONS
+	} else if (os_strcasecmp(cmd, "dpp_pkex_own_mac_override") == 0) {
+		if (hwaddr_aton(value, dpp_pkex_own_mac_override))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "dpp_pkex_peer_mac_override") == 0) {
+		if (hwaddr_aton(value, dpp_pkex_peer_mac_override))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "dpp_pkex_ephemeral_key_override") == 0) {
+		size_t hex_len = os_strlen(value);
+
+		if (hex_len >
+		    2 * sizeof(dpp_pkex_ephemeral_key_override))
+			ret = -1;
+		else if (hexstr2bin(value, dpp_pkex_ephemeral_key_override,
+				    hex_len / 2))
+			ret = -1;
+		else
+			dpp_pkex_ephemeral_key_override_len = hex_len / 2;
+	} else if (os_strcasecmp(cmd, "dpp_protocol_key_override") == 0) {
+		size_t hex_len = os_strlen(value);
+
+		if (hex_len > 2 * sizeof(dpp_protocol_key_override))
+			ret = -1;
+		else if (hexstr2bin(value, dpp_protocol_key_override,
+				    hex_len / 2))
+			ret = -1;
+		else
+			dpp_protocol_key_override_len = hex_len / 2;
+	} else if (os_strcasecmp(cmd, "dpp_nonce_override") == 0) {
+		size_t hex_len = os_strlen(value);
+
+		if (hex_len > 2 * sizeof(dpp_nonce_override))
+			ret = -1;
+		else if (hexstr2bin(value, dpp_nonce_override, hex_len / 2))
+			ret = -1;
+		else
+			dpp_nonce_override_len = hex_len / 2;
+#endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_DPP */
 #ifdef CONFIG_TESTING_OPTIONS
 	} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
@@ -645,18 +674,35 @@
 #ifdef CONFIG_DPP
 	} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
 		os_free(wpa_s->dpp_config_obj_override);
-		wpa_s->dpp_config_obj_override = os_strdup(value);
+		if (value[0] == '\0')
+			wpa_s->dpp_config_obj_override = NULL;
+		else
+			wpa_s->dpp_config_obj_override = os_strdup(value);
 	} else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
 		os_free(wpa_s->dpp_discovery_override);
-		wpa_s->dpp_discovery_override = os_strdup(value);
+		if (value[0] == '\0')
+			wpa_s->dpp_discovery_override = NULL;
+		else
+			wpa_s->dpp_discovery_override = os_strdup(value);
 	} else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
 		os_free(wpa_s->dpp_groups_override);
-		wpa_s->dpp_groups_override = os_strdup(value);
+		if (value[0] == '\0')
+			wpa_s->dpp_groups_override = NULL;
+		else
+			wpa_s->dpp_groups_override = os_strdup(value);
 	} else if (os_strcasecmp(cmd,
 				 "dpp_ignore_netaccesskey_mismatch") == 0) {
 		wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
+	} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
+		dpp_test = atoi(value);
 #endif /* CONFIG_DPP */
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_FILS
+	} else if (os_strcasecmp(cmd, "disable_fils") == 0) {
+		wpa_s->disable_fils = !!atoi(value);
+		wpa_drv_disable_fils(wpa_s, wpa_s->disable_fils);
+		wpa_supplicant_set_default_scan_ies(wpa_s);
+#endif /* CONFIG_FILS */
 #ifndef CONFIG_NO_CONFIG_BLOBS
 	} else if (os_strcmp(cmd, "blob") == 0) {
 		ret = wpas_ctrl_set_blob(wpa_s, value);
@@ -704,6 +750,15 @@
 		ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
 	} else if (os_strcasecmp(cmd, "roaming") == 0) {
 		ret = wpa_drv_roaming(wpa_s, atoi(value), NULL);
+#ifdef CONFIG_WNM
+	} else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) {
+		struct wpabuf *elems;
+
+		elems = wpabuf_parse_bin(value);
+		if (!elems)
+			return -1;
+		wnm_set_coloc_intf_elems(wpa_s, elems);
+#endif /* CONFIG_WNM */
 	} else {
 		value[-1] = '=';
 		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -2246,6 +2301,13 @@
 	}
 #endif /* CONFIG_WPS */
 
+	if (wpa_s->ieee80211ac) {
+		ret = os_snprintf(pos, end - pos, "ieee80211ac=1\n");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+
 #ifdef ANDROID
 	/*
 	 * Allow using the STATUS command with default behavior, say for debug,
@@ -4754,6 +4816,10 @@
 				   anqp->hs20_operating_class);
 		pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
 				   anqp->hs20_osu_providers_list);
+		pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata",
+				   anqp->hs20_operator_icon_metadata);
+		pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list",
+				   anqp->hs20_osu_providers_nai_list);
 #endif /* CONFIG_HS20 */
 
 		dl_list_for_each(elem, &anqp->anqp_elems,
@@ -6229,13 +6295,21 @@
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 	int max_oper_chwidth, chwidth = 0, freq2 = 0;
 	char *token, *context = NULL;
+#ifdef CONFIG_ACS
+	int acs = 0;
+#endif /* CONFIG_ACS */
 
 	while ((token = str_token(cmd, " ", &context))) {
-		if (sscanf(token, "freq=%d", &freq) == 1 ||
-		    sscanf(token, "freq2=%d", &freq2) == 1 ||
+		if (sscanf(token, "freq2=%d", &freq2) == 1 ||
 		    sscanf(token, "persistent=%d", &group_id) == 1 ||
 		    sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
 			continue;
+#ifdef CONFIG_ACS
+		} else if (os_strcmp(token, "freq=acs") == 0) {
+			acs = 1;
+#endif /* CONFIG_ACS */
+		} else if (sscanf(token, "freq=%d", &freq) == 1) {
+			continue;
 		} else if (os_strcmp(token, "ht40") == 0) {
 			ht40 = 1;
 		} else if (os_strcmp(token, "vht") == 0) {
@@ -6251,6 +6325,24 @@
 		}
 	}
 
+#ifdef CONFIG_ACS
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+	    (acs || freq == 2 || freq == 5)) {
+		if (freq == 2 && wpa_s->best_24_freq <= 0) {
+			wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211G;
+			wpa_s->p2p_go_do_acs = 1;
+			freq = 0;
+		} else if (freq == 5 && wpa_s->best_5_freq <= 0) {
+			wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211A;
+			wpa_s->p2p_go_do_acs = 1;
+			freq = 0;
+		} else {
+			wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211ANY;
+			wpa_s->p2p_go_do_acs = 1;
+		}
+	}
+#endif /* CONFIG_ACS */
+
 	max_oper_chwidth = parse_freq(chwidth, freq2);
 	if (max_oper_chwidth < 0)
 		return -1;
@@ -7354,6 +7446,22 @@
 						  list);
 }
 
+
+static int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	struct wpabuf *elems;
+	int ret;
+
+	elems = wpabuf_parse_bin(cmd);
+	if (!elems)
+		return -1;
+
+	ret = wnm_send_coloc_intf_report(wpa_s, 0, elems);
+	wpabuf_free(elems);
+	return ret;
+}
+
 #endif /* CONFIG_WNM */
 
 
@@ -7387,10 +7495,17 @@
 		pos += ret;
 	}
 
-	if (si.center_frq1 > 0 && si.center_frq2 > 0) {
-		ret = os_snprintf(pos, end - pos,
-				  "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
-				  si.center_frq1, si.center_frq2);
+	if (si.center_frq1 > 0) {
+		ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n",
+				  si.center_frq1);
+		if (os_snprintf_error(end - pos, ret))
+			return -1;
+		pos += ret;
+	}
+
+	if (si.center_frq2 > 0) {
+		ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n",
+				  si.center_frq2);
 		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
@@ -7708,6 +7823,18 @@
 
 #ifdef CONFIG_DPP
 	wpas_dpp_deinit(wpa_s);
+	wpa_s->dpp_init_max_tries = 0;
+	wpa_s->dpp_init_retry_time = 0;
+	wpa_s->dpp_resp_wait_time = 0;
+	wpa_s->dpp_resp_max_tries = 0;
+	wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+	os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
+	os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
+	dpp_pkex_ephemeral_key_override_len = 0;
+	dpp_protocol_key_override_len = 0;
+	dpp_nonce_override_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_DPP */
 
 #ifdef CONFIG_TDLS
@@ -7778,6 +7905,15 @@
 	wpa_s->get_pref_freq_list_override = NULL;
 	wpabuf_free(wpa_s->sae_commit_override);
 	wpa_s->sae_commit_override = NULL;
+#ifdef CONFIG_DPP
+	os_free(wpa_s->dpp_config_obj_override);
+	wpa_s->dpp_config_obj_override = NULL;
+	os_free(wpa_s->dpp_discovery_override);
+	wpa_s->dpp_discovery_override = NULL;
+	os_free(wpa_s->dpp_groups_override);
+	wpa_s->dpp_groups_override = NULL;
+	dpp_test = DPP_TEST_DISABLED;
+#endif /* CONFIG_DPP */
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	wpa_s->disconnected = 0;
@@ -10312,6 +10448,9 @@
 	} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
 		if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
 				reply_len = -1;
+	} else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) {
+		if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
+			reply_len = -1;
 #endif /* CONFIG_WNM */
 	} else if (os_strcmp(buf, "FLUSH") == 0) {
 		wpa_supplicant_ctrl_iface_flush(wpa_s);
@@ -10442,6 +10581,7 @@
 		if (wpas_dpp_listen(wpa_s, buf + 11) < 0)
 			reply_len = -1;
 	} else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
+		wpas_dpp_stop(wpa_s);
 		wpas_dpp_listen_stop(wpa_s);
 	} else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
 		int res;
@@ -10460,6 +10600,9 @@
 	} else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
 		if (wpas_dpp_configurator_sign(wpa_s, buf + 22) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
+		reply_len = wpas_dpp_configurator_get_key(wpa_s, atoi(buf + 25),
+							  reply, reply_size);
 	} else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
 		int res;
 
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 0dc0937..8a6057a 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -219,7 +219,7 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct ctrl_iface_priv *priv = sock_ctx;
-	char buf[256], *pos;
+	char buf[4096], *pos;
 	int res;
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
 	struct sockaddr_in6 from;
@@ -600,7 +600,7 @@
 {
 	struct wpa_global *global = eloop_ctx;
 	struct ctrl_iface_global_priv *priv = sock_ctx;
-	char buf[256], *pos;
+	char buf[4096], *pos;
 	int res;
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
 	struct sockaddr_in6 from;
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 4db712f..b88c80a 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -103,7 +103,7 @@
 					    struct sockaddr_storage *from,
 					    socklen_t fromlen, int global)
 {
-	return ctrl_iface_attach(ctrl_dst, from, fromlen);
+	return ctrl_iface_attach(ctrl_dst, from, fromlen, NULL);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 8115f77..e0f16bb 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -2027,6 +2027,9 @@
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "GroupFormationFailure");
@@ -2068,6 +2071,9 @@
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "InvitationReceived");
@@ -4266,7 +4272,13 @@
 	iface = wpa_s->global->dbus;
 
 	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL || !wpa_s->dbus_new_path)
+	if (iface == NULL)
+		return;
+
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
+	if (!wpa_s->dbus_new_path)
 		return;
 
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 564c868..a3c98fa 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -980,8 +980,21 @@
 	const struct wpa_dbus_property_desc *property_desc,
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
-	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+	const char *capabilities[8] = { NULL, NULL, NULL, NULL, NULL, NULL,
+					NULL, NULL };
 	size_t num_items = 0;
+#ifdef CONFIG_FILS
+	struct wpa_global *global = user_data;
+	struct wpa_supplicant *wpa_s;
+	int fils_supported = 0, fils_sk_pfs_supported = 0;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		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 */
 
 #ifdef CONFIG_AP
 	capabilities[num_items++] = "ap";
@@ -998,6 +1011,15 @@
 #ifdef CONFIG_IEEE80211W
 	capabilities[num_items++] = "pmf";
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_MESH
+	capabilities[num_items++] = "mesh";
+#endif /* CONFIG_MESH */
+#ifdef CONFIG_FILS
+	if (fils_supported)
+		capabilities[num_items++] = "fils";
+	if (fils_sk_pfs_supported)
+		capabilities[num_items++] = "fils_sk_pfs";
+#endif /* CONFIG_FILS */
 
 	return wpas_dbus_simple_array_property_getter(iter,
 						      DBUS_TYPE_STRING,
@@ -4094,7 +4116,7 @@
 	DBusMessageIter iter_dict, variant_iter;
 	const char *group;
 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
-	const char *key_mgmt[9]; /* max 9 key managements may be supported */
+	const char *key_mgmt[13]; /* max 13 key managements may be supported */
 	int n;
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4126,6 +4148,16 @@
 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
 		key_mgmt[n++] = "wpa-eap-suite-b-192";
 #endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
+		key_mgmt[n++] = "wpa-fils-sha256";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
+		key_mgmt[n++] = "wpa-fils-sha384";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+		key_mgmt[n++] = "wpa-ft-fils-sha256";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+		key_mgmt[n++] = "wpa-ft-fils-sha384";
+#endif /* CONFIG_FILS */
 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
 		key_mgmt[n++] = "wpa-none";
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index a04783d..9305b9a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -146,8 +146,11 @@
 
 	wpa_s = wpa_s->global->p2p_init_wpa_s;
 
-	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
-		      NULL, 0, 0, NULL, freq);
+	if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
+			  req_dev_types, NULL, 0, 0, NULL, freq))
+		reply = wpas_dbus_error_unknown_error(
+			message, "Could not start P2P find");
+
 	os_free(req_dev_types);
 	return reply;
 
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 450023e..08f5857 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -73,6 +73,12 @@
 # Driver interface for wired Ethernet drivers
 CONFIG_DRIVER_WIRED=y
 
+# Driver interface for MACsec capable Qualcomm Atheros drivers
+#CONFIG_DRIVER_MACSEC_QCA=y
+
+# Driver interface for Linux MACsec drivers
+#CONFIG_DRIVER_MACSEC_LINUX=y
+
 # Driver interface for the Broadcom RoboSwitch family
 #CONFIG_DRIVER_ROBOSWITCH=y
 
@@ -83,8 +89,8 @@
 #LIBS += -lsocket -ldlpi -lnsl
 #LIBS_c += -lsocket
 
-# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
-# included)
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or
+# MACsec is included)
 CONFIG_IEEE8021X_EAPOL=y
 
 # EAP-MD5
@@ -166,6 +172,9 @@
 # EAP-EKE
 #CONFIG_EAP_EKE=y
 
+# MACsec
+#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)
 CONFIG_PKCS12=y
@@ -375,10 +384,6 @@
 # IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
 #CONFIG_IEEE80211R=y
 
-# IEEE Std 802.11r-2008 (Fast BSS Transition) for AP mode (implies
-# CONFIG_IEEE80211R).
-#CONFIG_IEEE80211R_AP=y
-
 # Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
 #CONFIG_DEBUG_FILE=y
 
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index bf29f19..22ba902 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1,6 +1,7 @@
 /*
  * wpa_supplicant - DPP
  * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -24,6 +25,7 @@
 #include "scan.h"
 #include "notify.h"
 #include "dpp_supplicant.h"
+#include "hidl.h"
 
 
 static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
@@ -35,6 +37,14 @@
 			       const u8 *src, const u8 *bssid,
 			       const u8 *data, size_t data_len,
 			       enum offchannel_send_action_result result);
+static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s);
+static void
+wpas_dpp_tx_pkex_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);
 
 static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -93,6 +103,10 @@
 	    dpp_notify_new_qr_code(auth, bi) == 1) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Sending out pending authentication response");
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+			" freq=%u type=%d",
+			MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+			DPP_PA_AUTHENTICATION_RESP);
 		offchannel_send_action(wpa_s, auth->curr_freq,
 				       auth->peer_mac_addr, wpa_s->own_addr,
 				       broadcast,
@@ -294,18 +308,79 @@
 }
 
 
+static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+	if (!auth || !auth->resp_msg)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Retry Authentication Response after timeout");
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+		" freq=%u type=%d",
+		MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+		DPP_PA_AUTHENTICATION_RESP);
+	offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
+			       wpa_s->own_addr, broadcast,
+			       wpabuf_head(auth->resp_msg),
+			       wpabuf_len(auth->resp_msg),
+			       500, wpas_dpp_tx_status, 0);
+}
+
+
+static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
+{
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+	unsigned int wait_time, max_tries;
+
+	if (!auth || !auth->resp_msg)
+		return;
+
+	if (wpa_s->dpp_resp_max_tries)
+		max_tries = wpa_s->dpp_resp_max_tries;
+	else
+		max_tries = 5;
+	auth->auth_resp_tries++;
+	if (auth->auth_resp_tries >= max_tries) {
+		wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
+		offchannel_send_action_done(wpa_s);
+		dpp_auth_deinit(wpa_s->dpp_auth);
+		wpa_s->dpp_auth = NULL;
+		return;
+	}
+
+	if (wpa_s->dpp_resp_retry_time)
+		wait_time = wpa_s->dpp_resp_retry_time;
+	else
+		wait_time = 1000;
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Schedule retransmission of Authentication Response frame in %u ms",
+		wait_time);
+	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+	eloop_register_timeout(wait_time / 1000,
+			       (wait_time % 1000) * 1000,
+			       wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+}
+
+
 static void wpas_dpp_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)
 {
+	const char *res_txt;
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+		 "FAILED");
 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
-		   " result=%s",
-		   freq, MAC2STR(dst),
-		   result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
-		   (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
-		    "FAILED"));
+		   " result=%s", freq, MAC2STR(dst), res_txt);
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
 
 	if (!wpa_s->dpp_auth) {
 		wpa_printf(MSG_DEBUG,
@@ -316,7 +391,10 @@
 	if (wpa_s->dpp_auth->remove_on_tx_status) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Terminate authentication exchange due to an earlier error");
+		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+				     NULL);
 		offchannel_send_action_done(wpa_s);
 		dpp_auth_deinit(wpa_s->dpp_auth);
 		wpa_s->dpp_auth = NULL;
@@ -330,21 +408,105 @@
 	    result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Unicast DPP Action frame was not ACKed");
-		/* TODO: In case of DPP Authentication Request frame, move to
-		 * the next channel immediately */
+		if (auth->waiting_auth_resp) {
+			/* In case of DPP Authentication Request frame, move to
+			 * the next channel immediately. */
+			offchannel_send_action_done(wpa_s);
+			wpas_dpp_auth_init_next(wpa_s);
+			return;
+		}
+		if (auth->waiting_auth_conf) {
+			wpas_dpp_auth_resp_retry(wpa_s);
+			return;
+		}
 	}
+
+	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
+	    result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+		/* Allow timeout handling to stop iteration if no response is
+		 * received from a peer that has ACKed a request. */
+		auth->auth_req_ack = 1;
+	}
+
+	if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
+	    wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
+			   wpa_s->dpp_auth->curr_freq,
+			   wpa_s->dpp_auth->neg_freq);
+		offchannel_send_action_done(wpa_s);
+		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq);
+	}
+
+	if (wpa_s->dpp_auth_ok_on_ack)
+		wpa_s->dpp_auth_ok_on_ack = 0;
 }
 
 
 static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+	unsigned int freq;
+	struct os_reltime now, diff;
+	unsigned int wait_time, diff_ms;
 
-	if (!wpa_s->dpp_auth)
+	if (!auth || !auth->waiting_auth_resp)
 		return;
-	wpa_printf(MSG_DEBUG, "DPP: Continue reply wait on channel %u MHz",
-		   wpa_s->dpp_auth->curr_freq);
-	wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->curr_freq);
+
+	wait_time = wpa_s->dpp_resp_wait_time ?
+		wpa_s->dpp_resp_wait_time : 2000;
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff);
+	diff_ms = diff.sec * 1000 + diff.usec / 1000;
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
+		   wait_time, diff_ms);
+
+	if (auth->auth_req_ack && diff_ms >= wait_time) {
+		/* Peer ACK'ed Authentication Request frame, but did not reply
+		 * with Authentication Response frame within two seconds. */
+		wpa_printf(MSG_INFO,
+			   "DPP: No response received from responder - stopping initiation attempt");
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+		wpas_notify_dpp_timeout(wpa_s);
+		offchannel_send_action_done(wpa_s);
+		wpas_dpp_listen_stop(wpa_s);
+		dpp_auth_deinit(auth);
+		wpa_s->dpp_auth = NULL;
+		return;
+	}
+
+	if (diff_ms >= wait_time) {
+		/* Authentication Request frame was not ACK'ed and no reply
+		 * was receiving within two seconds. */
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Continue Initiator channel iteration");
+		offchannel_send_action_done(wpa_s);
+		wpas_dpp_listen_stop(wpa_s);
+		wpas_dpp_auth_init_next(wpa_s);
+		return;
+	}
+
+	/* Driver did not support 2000 ms long wait_time with TX command, so
+	 * schedule listen operation to continue waiting for the response.
+	 *
+	 * DPP listen operations continue until stopped, so simply schedule a
+	 * new call to this function at the point when the two second reply
+	 * wait has expired. */
+	wait_time -= diff_ms;
+
+	freq = auth->curr_freq;
+	if (auth->neg_freq > 0)
+		freq = auth->neg_freq;
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Continue reply wait on channel %u MHz for %u ms",
+		   freq, wait_time);
+	wpa_s->dpp_in_response_listen = 1;
+	wpas_dpp_listen_start(wpa_s, freq);
+
+	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+			       wpas_dpp_reply_wait_timeout, wpa_s, NULL);
 }
 
 
@@ -380,6 +542,7 @@
 	size_t pass_len = 0;
 	u8 psk[PMK_LEN];
 	int psk_set = 0;
+	char *group_id = NULL;
 
 	if (!cmd)
 		return;
@@ -415,14 +578,35 @@
 		psk_set = 1;
 	}
 
+	pos = os_strstr(cmd, " group_id=");
+	if (pos) {
+		size_t group_id_len;
+
+		pos += 10;
+		end = os_strchr(pos, ' ');
+		group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
+		group_id = os_malloc(group_id_len + 1);
+		if (!group_id)
+			goto fail;
+		os_memcpy(group_id, pos, group_id_len);
+		group_id[group_id_len] = '\0';
+	}
+
 	if (os_strstr(cmd, " conf=sta-")) {
 		conf_sta = os_zalloc(sizeof(struct dpp_configuration));
 		if (!conf_sta)
 			goto fail;
 		os_memcpy(conf_sta->ssid, ssid, ssid_len);
 		conf_sta->ssid_len = ssid_len;
-		if (os_strstr(cmd, " conf=sta-psk")) {
-			conf_sta->dpp = 0;
+		if (os_strstr(cmd, " conf=sta-psk") ||
+		    os_strstr(cmd, " conf=sta-sae") ||
+		    os_strstr(cmd, " conf=sta-psk-sae")) {
+			if (os_strstr(cmd, " conf=sta-psk-sae"))
+				conf_sta->akm = DPP_AKM_PSK_SAE;
+			else if (os_strstr(cmd, " conf=sta-sae"))
+				conf_sta->akm = DPP_AKM_SAE;
+			else
+				conf_sta->akm = DPP_AKM_PSK;
 			if (psk_set) {
 				os_memcpy(conf_sta->psk, psk, PMK_LEN);
 			} else {
@@ -431,10 +615,14 @@
 					goto fail;
 			}
 		} else if (os_strstr(cmd, " conf=sta-dpp")) {
-			conf_sta->dpp = 1;
+			conf_sta->akm = DPP_AKM_DPP;
 		} else {
 			goto fail;
 		}
+		if (os_strstr(cmd, " group_id=")) {
+			conf_sta->group_id = group_id;
+			group_id = NULL;
+		}
 	}
 
 	if (os_strstr(cmd, " conf=ap-")) {
@@ -443,8 +631,15 @@
 			goto fail;
 		os_memcpy(conf_ap->ssid, ssid, ssid_len);
 		conf_ap->ssid_len = ssid_len;
-		if (os_strstr(cmd, " conf=ap-psk")) {
-			conf_ap->dpp = 0;
+		if (os_strstr(cmd, " conf=ap-psk") ||
+		    os_strstr(cmd, " conf=ap-sae") ||
+		    os_strstr(cmd, " conf=ap-psk-sae")) {
+			if (os_strstr(cmd, " conf=ap-psk-sae"))
+				conf_ap->akm = DPP_AKM_PSK_SAE;
+			else if (os_strstr(cmd, " conf=ap-sae"))
+				conf_ap->akm = DPP_AKM_SAE;
+			else
+				conf_ap->akm = DPP_AKM_PSK;
 			if (psk_set) {
 				os_memcpy(conf_ap->psk, psk, PMK_LEN);
 			} else {
@@ -453,10 +648,14 @@
 					goto fail;
 			}
 		} else if (os_strstr(cmd, " conf=ap-dpp")) {
-			conf_ap->dpp = 1;
+			conf_ap->akm = DPP_AKM_DPP;
 		} else {
 			goto fail;
 		}
+		if (os_strstr(cmd, " group_id=")) {
+			conf_ap->group_id = group_id;
+			group_id = NULL;
+		}
 	}
 
 	pos = os_strstr(cmd, " expiry=");
@@ -486,12 +685,114 @@
 	auth->conf_sta = conf_sta;
 	auth->conf_ap = conf_ap;
 	auth->conf = conf;
+	os_free(group_id);
 	return;
 
 fail:
 	wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
 	dpp_configuration_free(conf_sta);
 	dpp_configuration_free(conf_ap);
+	os_free(group_id);
+}
+
+
+static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (!wpa_s->dpp_auth)
+		return;
+	wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
+	wpas_dpp_auth_init_next(wpa_s);
+}
+
+
+static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
+{
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+	const u8 *dst;
+	unsigned int wait_time, max_wait_time, freq, max_tries, used;
+	struct os_reltime now, diff;
+
+	wpa_s->dpp_in_response_listen = 0;
+	if (!auth)
+		return -1;
+
+	if (auth->freq_idx == 0)
+		os_get_reltime(&wpa_s->dpp_init_iter_start);
+
+	if (auth->freq_idx >= auth->num_freq) {
+		auth->num_freq_iters++;
+		if (wpa_s->dpp_init_max_tries)
+			max_tries = wpa_s->dpp_init_max_tries;
+		else
+			max_tries = 5;
+		if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
+			wpa_printf(MSG_INFO,
+				   "DPP: No response received from responder - stopping initiation attempt");
+			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+			wpas_notify_dpp_timeout(wpa_s);
+			eloop_cancel_timeout(wpas_dpp_reply_wait_timeout,
+					     wpa_s, NULL);
+			offchannel_send_action_done(wpa_s);
+			dpp_auth_deinit(wpa_s->dpp_auth);
+			wpa_s->dpp_auth = NULL;
+			return -1;
+		}
+		auth->freq_idx = 0;
+		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+		if (wpa_s->dpp_init_retry_time)
+			wait_time = wpa_s->dpp_init_retry_time;
+		else
+			wait_time = 10000;
+		os_get_reltime(&now);
+		os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff);
+		used = diff.sec * 1000 + diff.usec / 1000;
+		if (used > wait_time)
+			wait_time = 0;
+		else
+			wait_time -= used;
+		wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
+			   wait_time);
+		eloop_register_timeout(wait_time / 1000,
+				       (wait_time % 1000) * 1000,
+				       wpas_dpp_init_timeout, wpa_s,
+				       NULL);
+		return 0;
+	}
+	freq = auth->freq[auth->freq_idx++];
+	auth->curr_freq = freq;
+
+	if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+		dst = broadcast;
+	else
+		dst = auth->peer_bi->mac_addr;
+	wpa_s->dpp_auth_ok_on_ack = 0;
+	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+	wait_time = wpa_s->max_remain_on_chan;
+	max_wait_time = wpa_s->dpp_resp_wait_time ?
+		wpa_s->dpp_resp_wait_time : 2000;
+	if (wait_time > max_wait_time)
+		wait_time = max_wait_time;
+	wait_time += 10; /* give the driver some extra time to complete */
+	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+			       wpas_dpp_reply_wait_timeout,
+			       wpa_s, NULL);
+	wait_time -= 10;
+	if (auth->neg_freq > 0 && freq != auth->neg_freq) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
+			   freq, auth->neg_freq);
+	}
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
+	auth->auth_req_ack = 0;
+	os_get_reltime(&wpa_s->dpp_last_init);
+	return offchannel_send_action(wpa_s, freq, dst,
+				      wpa_s->own_addr, broadcast,
+				      wpabuf_head(auth->req_msg),
+				      wpabuf_len(auth->req_msg),
+				      wait_time, wpas_dpp_tx_status, 0);
 }
 
 
@@ -499,10 +800,8 @@
 {
 	const char *pos;
 	struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
-	const u8 *dst;
-	int res;
-	int configurator = 1;
-	unsigned int wait_time;
+	u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+	unsigned int neg_freq = 0;
 
 	wpa_s->dpp_gas_client = 0;
 
@@ -539,9 +838,12 @@
 	if (pos) {
 		pos += 6;
 		if (os_strncmp(pos, "configurator", 12) == 0)
-			configurator = 1;
+			allowed_roles = DPP_CAPAB_CONFIGURATOR;
 		else if (os_strncmp(pos, "enrollee", 8) == 0)
-			configurator = 0;
+			allowed_roles = DPP_CAPAB_ENROLLEE;
+		else if (os_strncmp(pos, "either", 6) == 0)
+			allowed_roles = DPP_CAPAB_CONFIGURATOR |
+				DPP_CAPAB_ENROLLEE;
 		else
 			goto fail;
 	}
@@ -552,47 +854,33 @@
 		wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
 	}
 
+	pos = os_strstr(cmd, " neg_freq=");
+	if (pos)
+		neg_freq = atoi(pos + 10);
+
 	if (wpa_s->dpp_auth) {
+		eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
 		eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+		eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+				     NULL);
 		offchannel_send_action_done(wpa_s);
 		dpp_auth_deinit(wpa_s->dpp_auth);
 	}
-	wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, configurator);
+	wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles,
+					neg_freq,
+					wpa_s->hw.modes, wpa_s->hw.num_modes);
 	if (!wpa_s->dpp_auth)
 		goto fail;
 	wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
 	wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, cmd);
 
-	/* TODO: Support iteration over all frequencies and filtering of
-	 * frequencies based on locally enabled channels that allow initiation
-	 * of transmission. */
-	if (peer_bi->num_freq > 0)
-		wpa_s->dpp_auth->curr_freq = peer_bi->freq[0];
-	else
-		wpa_s->dpp_auth->curr_freq = 2412;
+	wpa_s->dpp_auth->neg_freq = neg_freq;
 
-	if (is_zero_ether_addr(peer_bi->mac_addr)) {
-		dst = broadcast;
-	} else {
-		dst = peer_bi->mac_addr;
+	if (!is_zero_ether_addr(peer_bi->mac_addr))
 		os_memcpy(wpa_s->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
 			  ETH_ALEN);
-	}
-	wpa_s->dpp_auth_ok_on_ack = 0;
-	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
-	wait_time = wpa_s->max_remain_on_chan;
-	if (wait_time > 2000)
-		wait_time = 2000;
-	eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
-			       wpas_dpp_reply_wait_timeout,
-			       wpa_s, NULL);
-	res = offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
-				     dst, wpa_s->own_addr, broadcast,
-				     wpabuf_head(wpa_s->dpp_auth->req_msg),
-				     wpabuf_len(wpa_s->dpp_auth->req_msg),
-				     wait_time, wpas_dpp_tx_status, 0);
 
-	return res;
+	return wpas_dpp_auth_init_next(wpa_s);
 fail:
 	return -1;
 }
@@ -718,6 +1006,7 @@
 
 void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
 {
+	wpa_s->dpp_in_response_listen = 0;
 	if (!wpa_s->dpp_listen_freq)
 		return;
 
@@ -757,12 +1046,18 @@
 {
 	wpas_dpp_listen_work_done(wpa_s);
 
-	if (wpa_s->dpp_auth && !wpa_s->dpp_gas_client) {
+	if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
+		unsigned int new_freq;
+
 		/* Continue listen with a new remain-on-channel */
+		if (wpa_s->dpp_auth->neg_freq > 0)
+			new_freq = wpa_s->dpp_auth->neg_freq;
+		else
+			new_freq = wpa_s->dpp_auth->curr_freq;
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
-			   wpa_s->dpp_auth->curr_freq);
-		wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->curr_freq);
+			   new_freq);
+		wpas_dpp_listen_start(wpa_s, new_freq);
 		return;
 	}
 
@@ -777,29 +1072,18 @@
 				 const u8 *hdr, const u8 *buf, size_t len,
 				 unsigned int freq)
 {
-	const u8 *r_bootstrap, *i_bootstrap, *wrapped_data;
-	u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len;
+	const u8 *r_bootstrap, *i_bootstrap;
+	u16 r_bootstrap_len, i_bootstrap_len;
 	struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
 
 	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
 		   MAC2STR(src));
 
-	wrapped_data = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA,
-				    &wrapped_data_len);
-	if (!wrapped_data) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing required Wrapped data attribute");
-		return;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped data",
-		    wrapped_data, wrapped_data_len);
-
 	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
 				   &r_bootstrap_len);
-	if (!r_bootstrap || r_bootstrap > wrapped_data ||
-	    r_bootstrap_len != SHA256_MAC_LEN) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+	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",
@@ -807,10 +1091,9 @@
 
 	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
 				   &i_bootstrap_len);
-	if (!i_bootstrap || i_bootstrap > wrapped_data ||
-	    i_bootstrap_len != SHA256_MAC_LEN) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Initiator Bootstrapping Key Hash attribute");
 		return;
 	}
 	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
@@ -841,14 +1124,14 @@
 	}
 
 	if (!own_bi) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No matching own bootstrapping key found - ignore message");
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+			"No matching own bootstrapping key found - ignore message");
 		return;
 	}
 
 	if (wpa_s->dpp_auth) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Already in DPP authentication exchange - ignore new one");
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+			"Already in DPP authentication exchange - ignore new one");
 		return;
 	}
 
@@ -856,8 +1139,7 @@
 	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_qr_mutual,
-					  peer_bi, own_bi, freq, hdr, buf,
-					  wrapped_data, wrapped_data_len);
+					  peer_bi, own_bi, freq, hdr, buf, len);
 	if (!wpa_s->dpp_auth) {
 		wpa_printf(MSG_DEBUG, "DPP: No response generated");
 		return;
@@ -867,6 +1149,17 @@
 				  wpa_s->dpp_configurator_params);
 	os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
 
+	if (wpa_s->dpp_listen_freq &&
+	    wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Stop listen on %u MHz to allow response on the request %u MHz",
+			   wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
+		wpas_dpp_listen_stop(wpa_s);
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), wpa_s->dpp_auth->curr_freq,
+		DPP_PA_AUTHENTICATION_RESP);
 	offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
 			       src, wpa_s->own_addr, broadcast,
 			       wpabuf_head(wpa_s->dpp_auth->resp_msg),
@@ -901,6 +1194,7 @@
 
 	if (auth->connector) {
 		ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+		ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
 		ssid->dpp_connector = os_strdup(auth->connector);
 		if (!ssid->dpp_connector)
 			goto fail;
@@ -928,7 +1222,14 @@
 	}
 
 	if (!auth->connector) {
-		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+		ssid->key_mgmt = 0;
+		if (auth->akm == DPP_AKM_PSK || auth->akm == DPP_AKM_PSK_SAE)
+			ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
+				WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
+		if (auth->akm == DPP_AKM_SAE || auth->akm == DPP_AKM_PSK_SAE)
+			ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
+				WPA_KEY_MGMT_FT_SAE;
+		ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
 		if (auth->passphrase[0]) {
 			if (wpa_config_set_quoted(ssid, "psk",
 						  auth->passphrase) < 0)
@@ -962,8 +1263,12 @@
 		return;
 
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
-	if (wpa_s->conf->dpp_config_processing < 2)
+
+	wpas_notify_dpp_config_received(wpa_s, ssid);
+
+	if (wpa_s->conf->dpp_config_processing < 2) {
 		return;
+	}
 
 	wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
 	ssid->disabled = 0;
@@ -1042,6 +1347,8 @@
 	const u8 *pos;
 	struct dpp_authentication *auth = wpa_s->dpp_auth;
 
+	wpa_s->dpp_gas_dialog_token = -1;
+
 	if (!auth || !auth->auth_success) {
 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
 		return;
@@ -1082,6 +1389,7 @@
 
 fail:
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+	wpas_notify_dpp_configuration_failure(wpa_s);
 	dpp_auth_deinit(wpa_s->dpp_auth);
 	wpa_s->dpp_auth = NULL;
 }
@@ -1100,6 +1408,12 @@
 		    "\"wi-fi_tech\":\"infra\","
 		    "\"netRole\":\"%s\"}",
 		    wpa_s->dpp_netrole_ap ? "ap" : "sta");
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+		json[29] = 'k'; /* replace "infra" with "knfra" */
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
 
 	offchannel_send_action_done(wpa_s);
@@ -1137,13 +1451,14 @@
 		   MAC2STR(auth->peer_mac_addr), auth->curr_freq);
 
 	res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
-			    buf, wpas_dpp_gas_resp_cb, wpa_s);
+			    1, buf, wpas_dpp_gas_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
 		wpabuf_free(buf);
 	} else {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: GAS query started with dialog token %u", res);
+		wpa_s->dpp_gas_dialog_token = res;
 	}
 }
 
@@ -1152,6 +1467,18 @@
 {
 	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
+	wpas_notify_dpp_auth_success(wpa_s);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+		wpa_printf(MSG_INFO,
+			   "DPP: TESTING - stop at Authentication Confirm");
+		if (wpa_s->dpp_auth->configurator) {
+			/* Prevent GAS response */
+			wpa_s->dpp_auth->auth_success = 0;
+		}
+		return;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	if (wpa_s->dpp_auth->configurator)
 		wpas_dpp_start_gas_server(wpa_s);
@@ -1161,13 +1488,14 @@
 
 
 static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
-				  const u8 *hdr, const u8 *buf, size_t len)
+				  const u8 *hdr, const u8 *buf, size_t len,
+				  unsigned int freq)
 {
 	struct dpp_authentication *auth = wpa_s->dpp_auth;
 	struct wpabuf *msg;
 
-	wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR,
-		   MAC2STR(src));
+	wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR
+		   " (freq %u MHz)", MAC2STR(src), freq);
 
 	if (!auth) {
 		wpa_printf(MSG_DEBUG,
@@ -1184,11 +1512,19 @@
 
 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
 
+	if (auth->curr_freq != freq && auth->neg_freq == freq) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Responder accepted request for different negotiation channel");
+		auth->curr_freq = freq;
+	}
+
+	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
 	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
 	if (!msg) {
 		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
 			wpa_printf(MSG_DEBUG,
 				   "DPP: Start wait for full response");
+			wpas_notify_dpp_resp_pending(wpa_s);
 			offchannel_send_action_done(wpa_s);
 			wpas_dpp_listen_start(wpa_s, auth->curr_freq);
 			return;
@@ -1198,6 +1534,8 @@
 	}
 	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
 
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
 	offchannel_send_action(wpa_s, auth->curr_freq,
 			       src, wpa_s->own_addr, broadcast,
 			       wpabuf_head(msg), wpabuf_len(msg),
@@ -1229,6 +1567,7 @@
 
 	if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+		wpas_notify_dpp_auth_failure(wpa_s);
 		return;
 	}
 
@@ -1241,14 +1580,15 @@
 				       const u8 *buf, size_t len)
 {
 	struct wpa_ssid *ssid;
-	const u8 *connector, *trans_id;
-	u16 connector_len, trans_id_len;
+	const u8 *connector, *trans_id, *status;
+	u16 connector_len, trans_id_len, status_len;
 	struct dpp_introduction intro;
 	struct rsn_pmksa_cache_entry *entry;
 	struct os_time now;
 	struct os_reltime rnow;
 	os_time_t expiry;
 	unsigned int seconds;
+	enum dpp_status_error res;
 
 	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR,
 		   MAC2STR(src));
@@ -1276,12 +1616,32 @@
 	if (!trans_id || trans_id_len != 1) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Peer did not include Transaction ID");
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+			" fail=missing_transaction_id", MAC2STR(src));
 		goto fail;
 	}
 	if (trans_id[0] != TRANSACTION_ID) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Ignore frame with unexpected Transaction ID %u",
 			   trans_id[0]);
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+			" fail=transaction_id_mismatch", MAC2STR(src));
+		goto fail;
+	}
+
+	status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len);
+	if (!status || status_len != 1) {
+		wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status");
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+			" fail=missing_status", MAC2STR(src));
+		goto fail;
+	}
+	if (status[0] != DPP_STATUS_OK) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Peer rejected network introduction: Status %u",
+			   status[0]);
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+			" status=%u", MAC2STR(src), status[0]);
 		goto fail;
 	}
 
@@ -1289,17 +1649,22 @@
 	if (!connector) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Peer did not include its Connector");
-		return;
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+			" fail=missing_connector", MAC2STR(src));
+		goto fail;
 	}
 
-	if (dpp_peer_intro(&intro, ssid->dpp_connector,
-			   ssid->dpp_netaccesskey,
-			   ssid->dpp_netaccesskey_len,
-			   ssid->dpp_csign,
-			   ssid->dpp_csign_len,
-			   connector, connector_len, &expiry) < 0) {
+	res = dpp_peer_intro(&intro, ssid->dpp_connector,
+			     ssid->dpp_netaccesskey,
+			     ssid->dpp_netaccesskey_len,
+			     ssid->dpp_csign,
+			     ssid->dpp_csign_len,
+			     connector, connector_len, &expiry);
+	if (res != DPP_STATUS_OK) {
 		wpa_printf(MSG_INFO,
 			   "DPP: Network Introduction protocol resulted in failure");
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+			" fail=peer_connector_validation_failed", MAC2STR(src));
 		goto fail;
 	}
 
@@ -1323,6 +1688,9 @@
 	entry->network_ctx = ssid;
 	wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
 
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+		" status=%u", MAC2STR(src), status[0]);
+
 	wpa_printf(MSG_DEBUG,
 		   "DPP: Try connection again after successful network introduction");
 	if (wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -1334,6 +1702,94 @@
 }
 
 
+static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq)
+{
+	int i, j;
+
+	if (!wpa_s->hw.modes)
+		return -1;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+
+		for (j = 0; j < mode->num_channels; j++) {
+			struct hostapd_channel_data *chan = &mode->channels[j];
+
+			if (chan->freq != (int) freq)
+				continue;
+
+			if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+					  HOSTAPD_CHAN_NO_IR |
+					  HOSTAPD_CHAN_RADAR))
+				continue;
+
+			return 1;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
+		   freq);
+
+	return 0;
+}
+
+
+static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
+				      struct dpp_pkex *pkex)
+{
+	if (pkex->freq == 2437)
+		pkex->freq = 5745;
+	else if (pkex->freq == 5745)
+		pkex->freq = 5220;
+	else if (pkex->freq == 5220)
+		pkex->freq = 60480;
+	else
+		return -1; /* no more channels to try */
+
+	if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) {
+		wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
+			   pkex->freq);
+		return 0;
+	}
+
+	/* Could not use this channel - try the next one */
+	return wpas_dpp_pkex_next_channel(wpa_s, pkex);
+}
+
+
+static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+
+	if (!pkex || !pkex->exchange_req)
+		return;
+	if (pkex->exch_req_tries >= 5) {
+		if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
+			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+				"No response from PKEX peer");
+			dpp_pkex_free(pkex);
+			wpa_s->dpp_pkex = NULL;
+			return;
+		}
+		pkex->exch_req_tries = 0;
+	}
+
+	pkex->exch_req_tries++;
+	wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
+		   pkex->exch_req_tries);
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ);
+	offchannel_send_action(wpa_s, pkex->freq, broadcast,
+			       wpa_s->own_addr, broadcast,
+			       wpabuf_head(pkex->exchange_req),
+			       wpabuf_len(pkex->exchange_req),
+			       pkex->exch_req_wait_time,
+			       wpas_dpp_tx_pkex_status, 0);
+}
+
+
 static void
 wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
 			unsigned int freq, const u8 *dst,
@@ -1341,13 +1797,43 @@
 			const u8 *data, size_t data_len,
 			enum offchannel_send_action_result result)
 {
+	const char *res_txt;
+	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+
+	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+		 "FAILED");
 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
 		   " result=%s (PKEX)",
-		   freq, MAC2STR(dst),
-		   result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
-		   (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
-		    "FAILED"));
-	/* TODO: Time out wait for response more quickly in error cases? */
+		   freq, MAC2STR(dst), res_txt);
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
+
+	if (!pkex) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Ignore TX status since there is no ongoing PKEX exchange");
+		return;
+	}
+
+	if (pkex->failed) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Terminate PKEX exchange due to an earlier error");
+		if (pkex->t > pkex->own_bi->pkex_t)
+			pkex->own_bi->pkex_t = pkex->t;
+		dpp_pkex_free(pkex);
+		wpa_s->dpp_pkex = NULL;
+		return;
+	}
+
+	if (pkex->exch_req_wait_time && pkex->exchange_req) {
+		/* Wait for PKEX Exchange Response frame and retry request if
+		 * no response is seen. */
+		eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
+		eloop_register_timeout(pkex->exch_req_wait_time / 1000,
+				       (pkex->exch_req_wait_time % 1000) * 1000,
+				       wpas_dpp_pkex_retry_timeout, wpa_s,
+				       NULL);
+	}
 }
 
 
@@ -1377,7 +1863,7 @@
 		return;
 	}
 
-	wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s->dpp_pkex_bi,
+	wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi,
 						   wpa_s->own_addr, src,
 						   wpa_s->dpp_pkex_identifier,
 						   wpa_s->dpp_pkex_code,
@@ -1392,6 +1878,8 @@
 	wait_time = wpa_s->max_remain_on_chan;
 	if (wait_time > 2000)
 		wait_time = 2000;
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP);
 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
 			       broadcast,
 			       wpabuf_head(msg), wpabuf_len(msg),
@@ -1418,8 +1906,10 @@
 		return;
 	}
 
-	os_memcpy(wpa_s->dpp_pkex->peer_mac, src, ETH_ALEN);
-	msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, buf, len);
+	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
+	wpa_s->dpp_pkex->exch_req_wait_time = 0;
+
+	msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len);
 	if (!msg) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
 		return;
@@ -1431,6 +1921,8 @@
 	wait_time = wpa_s->max_remain_on_chan;
 	if (wait_time > 2000)
 		wait_time = 2000;
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ);
 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
 			       broadcast,
 			       wpabuf_head(msg), wpabuf_len(msg),
@@ -1439,6 +1931,35 @@
 }
 
 
+static struct dpp_bootstrap_info *
+wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
+		     unsigned int freq)
+{
+	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+	struct dpp_bootstrap_info *bi;
+
+	bi = os_zalloc(sizeof(*bi));
+	if (!bi)
+		return NULL;
+	bi->id = wpas_dpp_next_id(wpa_s);
+	bi->type = DPP_BOOTSTRAP_PKEX;
+	os_memcpy(bi->mac_addr, peer, ETH_ALEN);
+	bi->num_freq = 1;
+	bi->freq[0] = freq;
+	bi->curve = pkex->own_bi->curve;
+	bi->pubkey = pkex->peer_bootstrap_key;
+	pkex->peer_bootstrap_key = NULL;
+	dpp_pkex_free(pkex);
+	wpa_s->dpp_pkex = NULL;
+	if (dpp_bootstrap_key_hash(bi) < 0) {
+		dpp_bootstrap_info_free(bi);
+		return NULL;
+	}
+	dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
+	return bi;
+}
+
+
 static void
 wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
 				   const u8 *hdr, const u8 *buf, size_t len,
@@ -1447,7 +1968,6 @@
 	struct wpabuf *msg;
 	unsigned int wait_time;
 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
-	struct dpp_bootstrap_info *bi;
 
 	wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
 		   MAC2STR(src));
@@ -1460,6 +1980,13 @@
 	msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
 	if (!msg) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
+		if (pkex->failed) {
+			wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+			if (pkex->t > pkex->own_bi->pkex_t)
+				pkex->own_bi->pkex_t = pkex->t;
+			dpp_pkex_free(wpa_s->dpp_pkex);
+			wpa_s->dpp_pkex = NULL;
+		}
 		return;
 	}
 
@@ -1469,30 +1996,15 @@
 	wait_time = wpa_s->max_remain_on_chan;
 	if (wait_time > 2000)
 		wait_time = 2000;
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP);
 	offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
 			       broadcast,
 			       wpabuf_head(msg), wpabuf_len(msg),
 			       wait_time, wpas_dpp_tx_pkex_status, 0);
 	wpabuf_free(msg);
 
-	bi = os_zalloc(sizeof(*bi));
-	if (!bi)
-		return;
-	bi->id = wpas_dpp_next_id(wpa_s);
-	bi->type = DPP_BOOTSTRAP_PKEX;
-	os_memcpy(bi->mac_addr, src, ETH_ALEN);
-	bi->num_freq = 1;
-	bi->freq[0] = freq;
-	bi->curve = pkex->own_bi->curve;
-	bi->pubkey = pkex->peer_bootstrap_key;
-	pkex->peer_bootstrap_key = NULL;
-	dpp_pkex_free(pkex);
-	wpa_s->dpp_pkex = NULL;
-	if (dpp_bootstrap_key_hash(bi) < 0) {
-		dpp_bootstrap_info_free(bi);
-		return;
-	}
-	dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
+	wpas_dpp_pkex_finish(wpa_s, src, freq);
 }
 
 
@@ -1502,7 +2014,7 @@
 				    unsigned int freq)
 {
 	int res;
-	struct dpp_bootstrap_info *bi, *own_bi;
+	struct dpp_bootstrap_info *bi;
 	struct dpp_pkex *pkex = wpa_s->dpp_pkex;
 	char cmd[500];
 
@@ -1520,26 +2032,9 @@
 		return;
 	}
 
-	own_bi = pkex->own_bi;
-
-	bi = os_zalloc(sizeof(*bi));
+	bi = wpas_dpp_pkex_finish(wpa_s, src, freq);
 	if (!bi)
 		return;
-	bi->id = wpas_dpp_next_id(wpa_s);
-	bi->type = DPP_BOOTSTRAP_PKEX;
-	os_memcpy(bi->mac_addr, src, ETH_ALEN);
-	bi->num_freq = 1;
-	bi->freq[0] = freq;
-	bi->curve = own_bi->curve;
-	bi->pubkey = pkex->peer_bootstrap_key;
-	pkex->peer_bootstrap_key = NULL;
-	dpp_pkex_free(pkex);
-	wpa_s->dpp_pkex = NULL;
-	if (dpp_bootstrap_key_hash(bi) < 0) {
-		dpp_bootstrap_info_free(bi);
-		return;
-	}
-	dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
 
 	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
 		    bi->id,
@@ -1561,6 +2056,7 @@
 	u8 crypto_suite;
 	enum dpp_public_action_frame_type type;
 	const u8 *hdr;
+	unsigned int pkex_t;
 
 	if (len < DPP_HDR_LEN)
 		return;
@@ -1580,18 +2076,27 @@
 	if (crypto_suite != 1) {
 		wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
 			   crypto_suite);
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+			" freq=%u type=%d ignore=unsupported-crypto-suite",
+			MAC2STR(src), freq, type);
 		return;
 	}
 	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
-	if (dpp_check_attrs(buf, len) < 0)
+	if (dpp_check_attrs(buf, len) < 0) {
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+			" freq=%u type=%d ignore=invalid-attributes",
+			MAC2STR(src), freq, type);
 		return;
+	}
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d",
+		MAC2STR(src), freq, type);
 
 	switch (type) {
 	case DPP_PA_AUTHENTICATION_REQ:
 		wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq);
 		break;
 	case DPP_PA_AUTHENTICATION_RESP:
-		wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len);
+		wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq);
 		break;
 	case DPP_PA_AUTHENTICATION_CONF:
 		wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);
@@ -1618,6 +2123,17 @@
 			   "DPP: Ignored unsupported frame subtype %d", type);
 		break;
 	}
+
+	if (wpa_s->dpp_pkex)
+		pkex_t = wpa_s->dpp_pkex->t;
+	else if (wpa_s->dpp_pkex_bi)
+		pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
+	else
+		pkex_t = 0;
+	if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+		wpas_dpp_pkex_remove(wpa_s, "*");
+	}
 }
 
 
@@ -1639,9 +2155,14 @@
 	wpa_hexdump(MSG_DEBUG,
 		    "DPP: Received Configuration Request (GAS Query Request)",
 		    query, query_len);
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
+		MAC2STR(sa));
 	resp = dpp_conf_req_rx(auth, query, query_len);
-	if (!resp)
+	if (!resp) {
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+		wpas_notify_dpp_configuration_failure(wpa_s);
+	}
+	auth->conf_resp = resp;
 	return resp;
 }
 
@@ -1656,16 +2177,28 @@
 		wpabuf_free(resp);
 		return;
 	}
+	if (auth->conf_resp != resp) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Ignore GAS status report (ok=%d) for unknown response",
+			ok);
+		wpabuf_free(resp);
+		return;
+	}
 
 	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
 		   ok);
 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
 	offchannel_send_action_done(wpa_s);
 	wpas_dpp_listen_stop(wpa_s);
-	if (ok)
+	if (ok) {
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
-	else
+		wpas_notify_dpp_config_sent(wpa_s);
+	}
+	else {
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+		wpas_notify_dpp_configuration_failure(wpa_s);
+	}
 	dpp_auth_deinit(wpa_s->dpp_auth);
 	wpa_s->dpp_auth = NULL;
 	wpabuf_free(resp);
@@ -1772,7 +2305,7 @@
 	curve = get_param(cmd, " curve=");
 	wpas_dpp_set_configurator(wpa_s, auth, cmd);
 
-	if (dpp_configurator_own_config(auth, curve) == 0) {
+	if (dpp_configurator_own_config(auth, curve, 0) == 0) {
 		wpas_dpp_handle_config_obj(wpa_s, auth);
 		ret = 0;
 	}
@@ -1784,6 +2317,19 @@
 }
 
 
+int wpas_dpp_configurator_get_key(struct wpa_supplicant *wpa_s, unsigned int id,
+				  char *buf, size_t buflen)
+{
+	struct dpp_configurator *conf;
+
+	conf = dpp_configurator_get_id(wpa_s, id);
+	if (!conf)
+		return -1;
+
+	return dpp_configurator_get_key(conf, buf, buflen);
+}
+
+
 static void
 wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s,
 				unsigned int freq, const u8 *dst,
@@ -1791,12 +2337,16 @@
 				const u8 *data, size_t data_len,
 				enum offchannel_send_action_result result)
 {
+	const char *res_txt;
+
+	res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+		(result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+		 "FAILED");
 	wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
 		   " result=%s (DPP Peer Discovery Request)",
-		   freq, MAC2STR(dst),
-		   result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
-		   (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
-		    "FAILED"));
+		   freq, MAC2STR(dst), res_txt);
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+		" freq=%u result=%s", MAC2STR(dst), freq, res_txt);
 	/* TODO: Time out wait for response more quickly in error cases? */
 }
 
@@ -1826,7 +2376,7 @@
 	os_get_time(&now);
 
 	if (ssid->dpp_netaccesskey_expiry &&
-	    ssid->dpp_netaccesskey_expiry < now.sec) {
+	    (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) {
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
 			"netAccessKey expired");
 		return -1;
@@ -1841,20 +2391,63 @@
 	if (!msg)
 		return -1;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
+		goto skip_trans_id;
+	}
+	if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
+		wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+		wpabuf_put_le16(msg, 0);
+		goto skip_trans_id;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* Transaction ID */
 	wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
 	wpabuf_put_le16(msg, 1);
 	wpabuf_put_u8(msg, TRANSACTION_ID);
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_trans_id:
+	if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
+		goto skip_connector;
+	}
+	if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) {
+		char *connector;
+
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
+		connector = dpp_corrupt_connector_signature(
+			ssid->dpp_connector);
+		if (!connector) {
+			wpabuf_free(msg);
+			return -1;
+		}
+		wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+		wpabuf_put_le16(msg, os_strlen(connector));
+		wpabuf_put_str(msg, connector);
+		os_free(connector);
+		goto skip_connector;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* DPP Connector */
 	wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
 	wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector));
 	wpabuf_put_str(msg, ssid->dpp_connector);
 
+#ifdef CONFIG_TESTING_OPTIONS
+skip_connector:
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	/* TODO: Timeout on AP response */
 	wait_time = wpa_s->max_remain_on_chan;
 	if (wait_time > 2000)
 		wait_time = 2000;
+	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+		MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ);
 	offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
 			       broadcast,
 			       wpabuf_head(msg), wpabuf_len(msg),
@@ -1891,6 +2484,7 @@
 		return -1;
 	}
 	wpa_s->dpp_pkex_bi = own_bi;
+	own_bi->pkex_t = 0; /* clear pending errors on new code */
 
 	os_free(wpa_s->dpp_pkex_identifier);
 	wpa_s->dpp_pkex_identifier = NULL;
@@ -1916,25 +2510,35 @@
 		return -1;
 
 	if (os_strstr(cmd, " init=1")) {
+		struct dpp_pkex *pkex;
 		struct wpabuf *msg;
 
 		wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
 		dpp_pkex_free(wpa_s->dpp_pkex);
-		wpa_s->dpp_pkex = dpp_pkex_init(own_bi, wpa_s->own_addr,
+		wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
 						wpa_s->dpp_pkex_identifier,
 						wpa_s->dpp_pkex_code);
-		if (!wpa_s->dpp_pkex)
+		pkex = wpa_s->dpp_pkex;
+		if (!pkex)
 			return -1;
 
-		msg = wpa_s->dpp_pkex->exchange_req;
+		msg = pkex->exchange_req;
 		wait_time = wpa_s->max_remain_on_chan;
 		if (wait_time > 2000)
 			wait_time = 2000;
-		/* TODO: Which channel to use? */
-		offchannel_send_action(wpa_s, 2437, broadcast, wpa_s->own_addr,
-				       broadcast,
+		pkex->freq = 2437;
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+			" freq=%u type=%d",
+			MAC2STR(broadcast), pkex->freq,
+			DPP_PA_PKEX_EXCHANGE_REQ);
+		offchannel_send_action(wpa_s, pkex->freq, broadcast,
+				       wpa_s->own_addr, broadcast,
 				       wpabuf_head(msg), wpabuf_len(msg),
 				       wait_time, wpas_dpp_tx_pkex_status, 0);
+		if (wait_time == 0)
+			wait_time = 2000;
+		pkex->exch_req_wait_time = wait_time;
+		pkex->exch_req_tries = 1;
 	}
 
 	/* TODO: Support multiple PKEX info entries */
@@ -1976,6 +2580,17 @@
 }
 
 
+void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
+{
+	dpp_auth_deinit(wpa_s->dpp_auth);
+	wpa_s->dpp_auth = NULL;
+	dpp_pkex_free(wpa_s->dpp_pkex);
+	wpa_s->dpp_pkex = NULL;
+	if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
+		gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
+}
+
+
 int wpas_dpp_init(struct wpa_supplicant *wpa_s)
 {
 	u8 adv_proto_id[7];
@@ -2010,15 +2625,16 @@
 #endif /* CONFIG_TESTING_OPTIONS */
 	if (!wpa_s->dpp_init_done)
 		return;
+	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
 	offchannel_send_action_done(wpa_s);
 	wpas_dpp_listen_stop(wpa_s);
 	dpp_bootstrap_del(wpa_s, 0);
 	dpp_configurator_del(wpa_s, 0);
-	dpp_auth_deinit(wpa_s->dpp_auth);
-	wpa_s->dpp_auth = NULL;
+	wpas_dpp_stop(wpa_s);
 	wpas_dpp_pkex_remove(wpa_s, "*");
-	wpa_s->dpp_pkex = NULL;
 	os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
 	os_free(wpa_s->dpp_configurator_params);
 	wpa_s->dpp_configurator_params = NULL;
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 05a466d..9b539df 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -28,8 +28,11 @@
 int wpas_dpp_configurator_add(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_dpp_configurator_remove(struct wpa_supplicant *wpa_s, const char *id);
 int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_configurator_get_key(struct wpa_supplicant *wpa_s, unsigned int id,
+				  char *buf, size_t buflen);
 int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id);
+void wpas_dpp_stop(struct wpa_supplicant *wpa_s);
 int wpas_dpp_init(struct wpa_supplicant *wpa_s);
 void wpas_dpp_deinit(struct wpa_supplicant *wpa_s);
 int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index e131653..078de23 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -689,6 +689,14 @@
 	return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid);
 }
 
+static inline int wpa_drv_disable_fils(struct wpa_supplicant *wpa_s,
+				       int disable)
+{
+	if (!wpa_s->driver->disable_fils)
+		return -1;
+	return wpa_s->driver->disable_fils(wpa_s->drv_priv, disable);
+}
+
 static inline int wpa_drv_set_mac_addr(struct wpa_supplicant *wpa_s,
 				       const u8 *addr)
 {
@@ -1028,4 +1036,14 @@
 						    mask);
 }
 
+static inline int
+wpa_drv_send_external_auth_status(struct wpa_supplicant *wpa_s,
+				  struct external_auth *params)
+{
+	if (!wpa_s->driver->send_external_auth_status)
+		return -1;
+	return wpa_s->driver->send_external_auth_status(wpa_s->drv_priv,
+							params);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 63cf773..ef28ffe 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -50,6 +50,9 @@
 #include "dpp_supplicant.h"
 
 
+#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5
+
+
 #ifndef CONFIG_NO_SCAN_PROCESSING
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
 					      int new_scan, int own_request);
@@ -314,11 +317,13 @@
 
 	wpas_rrm_reset(wpa_s);
 	wpa_s->wnmsleep_used = 0;
+	wnm_clear_coloc_intf_reporting(wpa_s);
 
 #ifdef CONFIG_TESTING_OPTIONS
 	wpa_s->last_tk_alg = WPA_ALG_NONE;
 	os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
 #endif /* CONFIG_TESTING_OPTIONS */
+	wpa_s->ieee80211ac = 0;
 }
 
 
@@ -335,7 +340,7 @@
 	for (i = 0; i < ie.num_pmkid; i++) {
 		pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
 						    ie.pmkid + i * PMKID_LEN,
-						    NULL, NULL, 0, NULL);
+						    NULL, NULL, 0, NULL, 0);
 		if (pmksa_set == 0) {
 			eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
 			break;
@@ -487,6 +492,11 @@
 		return 1;
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_OWE
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only)
+		return 1;
+#endif /* CONFIG_OWE */
+
 	if (has_wep_key(ssid))
 		privacy = 1;
 
@@ -530,7 +540,7 @@
 		 (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
 
 	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
+	while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
 		proto_match++;
 
 		if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
@@ -549,7 +559,8 @@
 			return 1;
 		}
 
-		if (!(ie.proto & ssid->proto)) {
+		if (!(ie.proto & ssid->proto) &&
+		    !(ssid->proto & WPA_PROTO_OSEN)) {
 			if (debug_print)
 				wpa_dbg(wpa_s, MSG_DEBUG,
 					"   skip RSN IE - proto mismatch");
@@ -622,7 +633,8 @@
 	}
 
 #ifdef CONFIG_IEEE80211W
-	if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+	if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
+	    (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
 		if (debug_print)
 			wpa_dbg(wpa_s, MSG_DEBUG,
 				"   skip - MFP Required but network not MFP Capable");
@@ -692,6 +704,29 @@
 		return 1;
 	}
 
+#ifdef CONFIG_OWE
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only &&
+	    !wpa_ie && !rsn_ie) {
+		if (wpa_s->owe_transition_select &&
+		    wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE) &&
+		    ssid->owe_transition_bss_select_count + 1 <=
+		    MAX_OWE_TRANSITION_BSS_SELECT_COUNT) {
+			ssid->owe_transition_bss_select_count++;
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip OWE transition BSS (selection count %d does not exceed %d)",
+					ssid->owe_transition_bss_select_count,
+					MAX_OWE_TRANSITION_BSS_SELECT_COUNT);
+			wpa_s->owe_transition_search = 1;
+			return 0;
+		}
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   allow in OWE transition mode");
+		return 1;
+	}
+#endif /* CONFIG_OWE */
+
 	if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
 	    wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
 		if (debug_print)
@@ -968,18 +1003,22 @@
 	struct wpa_blacklist *e;
 	const u8 *ie;
 	struct wpa_ssid *ssid;
-	int osen;
+	int osen, rsn_osen = 0;
 #ifdef CONFIG_MBO
 	const u8 *assoc_disallow;
 #endif /* CONFIG_MBO */
 	const u8 *match_ssid;
 	size_t match_ssid_len;
+	struct wpa_ie_data data;
 
 	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
 	wpa_ie_len = ie ? ie[1] : 0;
 
 	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 	rsn_ie_len = ie ? ie[1] : 0;
+	if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+	    (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+		rsn_osen = 1;
 
 	ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
 	osen = ie != NULL;
@@ -1137,6 +1176,7 @@
 		if (!osen && !wpa &&
 		    !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
 		    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+		    !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
 		    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
 			if (debug_print)
 				wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1152,7 +1192,8 @@
 			continue;
 		}
 
-		if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
+		if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
+		    !rsn_osen) {
 			if (debug_print)
 				wpa_dbg(wpa_s, MSG_DEBUG,
 					"   skip - non-OSEN network not allowed");
@@ -1363,8 +1404,11 @@
 
 	for (i = 0; i < wpa_s->last_scan_res_used; i++) {
 		struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+		wpa_s->owe_transition_select = 1;
 		*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
 						    only_first_ssid, 1);
+		wpa_s->owe_transition_select = 0;
 		if (!*selected_ssid)
 			continue;
 		wpa_dbg(wpa_s, MSG_DEBUG, "   selected BSS " MACSTR
@@ -1911,6 +1955,7 @@
 	if (wpa_s->p2p_mgmt)
 		return 0; /* no normal connection on p2p_mgmt interface */
 
+	wpa_s->owe_transition_search = 0;
 	selected = wpa_supplicant_pick_network(wpa_s, &ssid);
 
 #ifdef CONFIG_MESH
@@ -2012,6 +2057,17 @@
 				return 0;
 			}
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_OWE
+			if (wpa_s->owe_transition_search) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"OWE: Use shorter wait during transition mode search");
+				timeout_sec = 0;
+				timeout_usec = 500000;
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
+				return 0;
+			}
+#endif /* CONFIG_OWE */
 			if (wpa_supplicant_req_sched_scan(wpa_s))
 				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
 							    timeout_usec);
@@ -2260,9 +2316,9 @@
 {
 	int l, len, found = 0, wpa_found, rsn_found;
 	const u8 *p;
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
 	u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
 	if (data->assoc_info.req_ies)
@@ -2283,6 +2339,10 @@
 		interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
 						data->assoc_info.resp_ies_len);
 #endif /* CONFIG_INTERWORKING */
+		if (wpa_s->hw_capab == CAPAB_VHT &&
+		    get_ie(data->assoc_info.resp_ies,
+			   data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
+			wpa_s->ieee80211ac = 1;
 	}
 	if (data->assoc_info.beacon_ies)
 		wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -3743,18 +3803,101 @@
 }
 
 
-static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
-					    union wpa_event_data *data)
+static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
 {
-	wpa_dbg(wpa_s, MSG_DEBUG,
-		"Connection authorized by device, previous state %d",
-		wpa_s->wpa_state);
 	if (wpa_s->wpa_state == WPA_ASSOCIATED) {
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
 		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
 		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
 	}
+}
+
+
+static unsigned int wpas_event_cac_ms(const struct wpa_supplicant *wpa_s,
+				      int freq)
+{
+	size_t i;
+	int j;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		const struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+
+		for (j = 0; j < mode->num_channels; j++) {
+			const struct hostapd_channel_data *chan;
+
+			chan = &mode->channels[j];
+			if (chan->freq == freq)
+				return chan->dfs_cac_ms;
+		}
+	}
+
+	return 0;
+}
+
+
+static void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+				       struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+	if (wpa_s->ap_iface) {
+		wpas_ap_event_dfs_cac_started(wpa_s, radar);
+	} else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+	{
+		unsigned int cac_time = wpas_event_cac_ms(wpa_s, radar->freq);
+
+		cac_time /= 1000; /* convert from ms to sec */
+		if (!cac_time)
+			cac_time = 10 * 60; /* max timeout: 10 minutes */
+
+		/* Restart auth timeout: CAC time added to initial timeout */
+		wpas_auth_timeout_restart(wpa_s, cac_time);
+	}
+}
+
+
+static void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+					struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+	if (wpa_s->ap_iface) {
+		wpas_ap_event_dfs_cac_finished(wpa_s, radar);
+	} else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+	{
+		/* Restart auth timeout with original value after CAC is
+		 * finished */
+		wpas_auth_timeout_restart(wpa_s, 0);
+	}
+}
+
+
+static void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+				       struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+	if (wpa_s->ap_iface) {
+		wpas_ap_event_dfs_cac_aborted(wpa_s, radar);
+	} else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+	{
+		/* Restart auth timeout with original value after CAC is
+		 * aborted */
+		wpas_auth_timeout_restart(wpa_s, 0);
+	}
+}
+
+
+static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
+					    union wpa_event_data *data)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Connection authorized by device, previous state %d",
+		wpa_s->wpa_state);
+
+	wpa_supplicant_event_port_authorized(wpa_s);
+
 	wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
 	wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
 			       data->assoc_info.ptk_kck_len,
@@ -3780,13 +3923,110 @@
 			/* Update the current PMKSA used for this connection */
 			pmksa_cache_set_current(wpa_s->wpa,
 						data->assoc_info.fils_pmkid,
-						NULL, NULL, 0, NULL);
+						NULL, NULL, 0, NULL, 0);
 		}
 	}
 #endif /* CONFIG_FILS */
 }
 
 
+static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
+				    union wpa_event_data *data)
+{
+	const u8 *bssid = data->assoc_reject.bssid;
+
+	if (!bssid || is_zero_ether_addr(bssid))
+		bssid = wpa_s->pending_bssid;
+
+	if (data->assoc_reject.bssid)
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+			"bssid=" MACSTR	" status_code=%u%s%s%s",
+			MAC2STR(data->assoc_reject.bssid),
+			data->assoc_reject.status_code,
+			data->assoc_reject.timed_out ? " timeout" : "",
+			data->assoc_reject.timeout_reason ? "=" : "",
+			data->assoc_reject.timeout_reason ?
+			data->assoc_reject.timeout_reason : "");
+	else
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+			"status_code=%u%s%s%s",
+			data->assoc_reject.status_code,
+			data->assoc_reject.timed_out ? " timeout" : "",
+			data->assoc_reject.timeout_reason ? "=" : "",
+			data->assoc_reject.timeout_reason ?
+			data->assoc_reject.timeout_reason : "");
+	wpa_s->assoc_status_code = data->assoc_reject.status_code;
+	wpa_s->assoc_timed_out = data->assoc_reject.timed_out;
+	wpas_notify_assoc_status_code(wpa_s);
+
+#ifdef CONFIG_OWE
+	if (data->assoc_reject.status_code ==
+	    WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+	    wpa_s->current_ssid &&
+	    wpa_s->current_ssid->owe_group == 0 &&
+	    wpa_s->last_owe_group != 21) {
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+		struct wpa_bss *bss = wpa_s->current_bss;
+
+		if (!bss) {
+			bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+			if (!bss) {
+				wpas_connection_failed(wpa_s, bssid);
+				wpa_supplicant_mark_disassoc(wpa_s);
+				return;
+			}
+		}
+		wpa_printf(MSG_DEBUG, "OWE: Try next supported DH group");
+		wpas_connect_work_done(wpa_s);
+		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_connect(wpa_s, bss, ssid);
+		return;
+	}
+#endif /* CONFIG_OWE */
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+		sme_event_assoc_reject(wpa_s, data);
+		return;
+	}
+
+	/* Driver-based SME cases */
+
+#ifdef CONFIG_SAE
+	if (wpa_s->current_ssid &&
+	    wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt) &&
+	    !data->assoc_reject.timed_out) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SAE: Drop PMKSA cache entry");
+		wpa_sm_aborted_cached(wpa_s->wpa);
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+	}
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_DPP
+	if (wpa_s->current_ssid &&
+	    wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+	    !data->assoc_reject.timed_out) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "DPP: Drop PMKSA cache entry");
+		wpa_sm_aborted_cached(wpa_s->wpa);
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+	}
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_FILS
+	/* Update ERP next sequence number */
+	if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) {
+		eapol_sm_update_erp_next_seq_num(
+			wpa_s->eapol,
+			data->assoc_reject.fils_erp_next_seq_num);
+		fils_connection_failure(wpa_s);
+	}
+#endif /* CONFIG_FILS */
+
+	wpas_connection_failed(wpa_s, bssid);
+	wpa_supplicant_mark_disassoc(wpa_s);
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -3967,44 +4207,7 @@
 		break;
 #endif /* CONFIG_IBSS_RSN */
 	case EVENT_ASSOC_REJECT:
-		if (data->assoc_reject.bssid)
-			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-				"bssid=" MACSTR	" status_code=%u%s%s%s",
-				MAC2STR(data->assoc_reject.bssid),
-				data->assoc_reject.status_code,
-				data->assoc_reject.timed_out ? " timeout" : "",
-				data->assoc_reject.timeout_reason ? "=" : "",
-				data->assoc_reject.timeout_reason ?
-				data->assoc_reject.timeout_reason : "");
-		else
-			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-				"status_code=%u%s%s%s",
-				data->assoc_reject.status_code,
-				data->assoc_reject.timed_out ? " timeout" : "",
-				data->assoc_reject.timeout_reason ? "=" : "",
-				data->assoc_reject.timeout_reason ?
-				data->assoc_reject.timeout_reason : "");
-		wpa_s->assoc_status_code = data->assoc_reject.status_code;
-		wpa_s->assoc_timed_out = data->assoc_reject.timed_out;
-		wpas_notify_assoc_status_code(wpa_s);
-		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
-			sme_event_assoc_reject(wpa_s, data);
-		else {
-			const u8 *bssid = data->assoc_reject.bssid;
-
-#ifdef CONFIG_FILS
-			/* Update ERP next sequence number */
-			if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS)
-				eapol_sm_update_erp_next_seq_num(
-				      wpa_s->eapol,
-				      data->assoc_reject.fils_erp_next_seq_num);
-#endif /* CONFIG_FILS */
-
-			if (bssid == NULL || is_zero_ether_addr(bssid))
-				bssid = wpa_s->pending_bssid;
-			wpas_connection_failed(wpa_s, bssid);
-			wpa_supplicant_mark_disassoc(wpa_s);
-		}
+		wpas_event_assoc_reject(wpa_s, data);
 		break;
 	case EVENT_AUTH_TIMED_OUT:
 		/* It is possible to get this event from earlier connection */
@@ -4106,6 +4309,7 @@
 		ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
 				       data->rx_from_unknown.wds);
 		break;
+#endif /* CONFIG_AP */
 	case EVENT_CH_SWITCH:
 		if (!data || !wpa_s->current_ssid)
 			break;
@@ -4122,6 +4326,7 @@
 		wpa_s->assoc_freq = data->ch_switch.freq;
 		wpa_s->current_ssid->frequency = data->ch_switch.freq;
 
+#ifdef CONFIG_AP
 		if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
 		    wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
 		    wpa_s->current_ssid->mode ==
@@ -4133,14 +4338,25 @@
 					  data->ch_switch.cf1,
 					  data->ch_switch.cf2);
 		}
+#endif /* CONFIG_AP */
 
 		wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
+		wnm_clear_coloc_intf_reporting(wpa_s);
 		break;
+#ifdef CONFIG_AP
 #ifdef NEED_AP_MLME
 	case EVENT_DFS_RADAR_DETECTED:
 		if (data)
-			wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event);
+			wpas_ap_event_dfs_radar_detected(wpa_s,
+							 &data->dfs_event);
 		break;
+	case EVENT_DFS_NOP_FINISHED:
+		if (data)
+			wpas_ap_event_dfs_cac_nop_finished(wpa_s,
+							   &data->dfs_event);
+		break;
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_AP */
 	case EVENT_DFS_CAC_STARTED:
 		if (data)
 			wpas_event_dfs_cac_started(wpa_s, &data->dfs_event);
@@ -4153,13 +4369,6 @@
 		if (data)
 			wpas_event_dfs_cac_aborted(wpa_s, &data->dfs_event);
 		break;
-	case EVENT_DFS_NOP_FINISHED:
-		if (data)
-			wpas_event_dfs_cac_nop_finished(wpa_s,
-							&data->dfs_event);
-		break;
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_AP */
 	case EVENT_RX_MGMT: {
 		u16 fc, stype;
 		const struct ieee80211_mgmt *mgmt;
@@ -4231,6 +4440,16 @@
 				break;
 			}
 
+#ifdef CONFIG_SAE
+			if (stype == WLAN_FC_STYPE_AUTH &&
+			    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+			    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+				sme_external_auth_mgmt_rx(
+					wpa_s, data->rx_mgmt.frame,
+					data->rx_mgmt.frame_len);
+				break;
+			}
+#endif /* CONFIG_SAE */
 			wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
 				"management frame in non-AP mode");
 			break;
@@ -4320,6 +4539,9 @@
 			data->signal_change.current_noise,
 			data->signal_change.current_txrate);
 		break;
+	case EVENT_INTERFACE_MAC_CHANGED:
+		wpa_supplicant_update_mac_addr(wpa_s);
+		break;
 	case EVENT_INTERFACE_ENABLED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
@@ -4390,7 +4612,8 @@
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
 		}
 		wpa_supplicant_mark_disassoc(wpa_s);
-		wpa_bss_flush(wpa_s);
+		if (!wpa_s->conf->bss_no_flush_when_down)
+			wpa_bss_flush(wpa_s);
 		radio_remove_works(wpa_s, NULL, 0);
 
 		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -4543,6 +4766,30 @@
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS);
 		bgscan_notify_beacon_loss(wpa_s);
 		break;
+	case EVENT_EXTERNAL_AUTH:
+#ifdef CONFIG_SAE
+		if (!wpa_s->current_ssid) {
+			wpa_printf(MSG_DEBUG, "SAE: current_ssid is NULL");
+			break;
+		}
+		sme_external_auth_trigger(wpa_s, data);
+#endif /* CONFIG_SAE */
+		break;
+	case EVENT_PORT_AUTHORIZED:
+		wpa_supplicant_event_port_authorized(wpa_s);
+		break;
+	case EVENT_STATION_OPMODE_CHANGED:
+#ifdef CONFIG_AP
+		if (!wpa_s->ap_iface || !data)
+			break;
+
+		hostapd_event_sta_opmode_changed(wpa_s->ap_iface->bss[0],
+						 data->sta_opmode.addr,
+						 data->sta_opmode.smps_mode,
+						 data->sta_opmode.chan_width,
+						 data->sta_opmode.rx_nss);
+#endif /* CONFIG_AP */
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 91cf19a..f4f60c5 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -42,6 +42,7 @@
 	unsigned int wait_comeback:1;
 	unsigned int offchannel_tx_started:1;
 	unsigned int retry:1;
+	unsigned int wildcard_bssid:1;
 	int freq;
 	u16 status_code;
 	struct wpabuf *req;
@@ -121,6 +122,8 @@
 		return "PEER_ERROR";
 	case GAS_QUERY_INTERNAL_ERROR:
 		return "INTERNAL_ERROR";
+	case GAS_QUERY_STOPPED:
+		return "STOPPED";
 	case GAS_QUERY_DELETED_AT_DEINIT:
 		return "DELETED_AT_DEINIT";
 	}
@@ -300,10 +303,11 @@
 	if (gas->wpa_s->max_remain_on_chan &&
 	    wait_time > gas->wpa_s->max_remain_on_chan)
 		wait_time = gas->wpa_s->max_remain_on_chan;
-	if (!gas->wpa_s->conf->gas_address3 ||
-	    (gas->wpa_s->current_ssid &&
-	     gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
-	     os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))
+	if (!query->wildcard_bssid &&
+	    (!gas->wpa_s->conf->gas_address3 ||
+	     (gas->wpa_s->current_ssid &&
+	      gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
+	      os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0)))
 		bssid = query->addr;
 	else
 		bssid = wildcard_bssid;
@@ -803,7 +807,7 @@
  * Returns: dialog token (>= 0) on success or -1 on failure
  */
 int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
-		  struct wpabuf *req,
+		  int wildcard_bssid, struct wpabuf *req,
 		  void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
 			     enum gas_query_result result,
 			     const struct wpabuf *adv_proto,
@@ -831,6 +835,7 @@
 	}
 	os_memcpy(query->addr, dst, ETH_ALEN);
 	query->dialog_token = dialog_token;
+	query->wildcard_bssid = !!wildcard_bssid;
 	query->freq = freq;
 	query->cb = cb;
 	query->ctx = ctx;
@@ -852,3 +857,27 @@
 
 	return dialog_token;
 }
+
+
+int gas_query_stop(struct gas_query *gas, u8 dialog_token)
+{
+	struct gas_query_pending *query;
+
+	dl_list_for_each(query, &gas->pending, struct gas_query_pending, list) {
+		if (query->dialog_token == dialog_token) {
+			if (!gas->work) {
+				/* The pending radio work has not yet been
+				 * started, but the pending entry has a
+				 * reference to the soon to be freed query.
+				 * Need to remove that radio work now to avoid
+				 * leaving behind a reference to freed memory.
+				 */
+				radio_remove_pending_work(gas->wpa_s, query);
+			}
+			gas_query_done(gas, query, GAS_QUERY_STOPPED);
+			return 0;
+		}
+	}
+
+	return -1;
+}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index ef82097..982c0f7 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -29,16 +29,18 @@
 	GAS_QUERY_TIMEOUT,
 	GAS_QUERY_PEER_ERROR,
 	GAS_QUERY_INTERNAL_ERROR,
+	GAS_QUERY_STOPPED,
 	GAS_QUERY_DELETED_AT_DEINIT
 };
 
 int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
-		  struct wpabuf *req,
+		  int wildcard_bssid, struct wpabuf *req,
 		  void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
 			     enum gas_query_result result,
 			     const struct wpabuf *adv_proto,
 			     const struct wpabuf *resp, u16 status_code),
 		  void *ctx);
+int gas_query_stop(struct gas_query *gas, u8 dialog_token);
 
 #else /* CONFIG_GAS */
 
diff --git a/wpa_supplicant/hidl/1.0/hidl.cpp b/wpa_supplicant/hidl/1.0/hidl.cpp
deleted file mode 100644
index ce8a459..0000000
--- a/wpa_supplicant/hidl/1.0/hidl.cpp
+++ /dev/null
@@ -1,627 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include <hwbinder/IPCThreadState.h>
-
-#include <hidl/HidlTransportSupport.h>
-#include "hidl_manager.h"
-
-extern "C" {
-#include "hidl.h"
-#include "hidl_i.h"
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/includes.h"
-}
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::setupTransportPolling;
-using android::hardware::handleTransportPoll;
-using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager;
-
-void wpas_hidl_sock_handler(
-    int sock, void * /* eloop_ctx */, void * /* sock_ctx */)
-{
-	handleTransportPoll(sock);
-}
-
-struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global)
-{
-	struct wpas_hidl_priv *priv;
-	HidlManager *hidl_manager;
-
-	priv = (wpas_hidl_priv *)os_zalloc(sizeof(*priv));
-	if (!priv)
-		return NULL;
-	priv->global = global;
-
-	wpa_printf(MSG_DEBUG, "Initing hidl control");
-
-	configureRpcThreadpool(1, true /* callerWillJoin */);
-	priv->hidl_fd = setupTransportPolling();
-	if (priv->hidl_fd < 0)
-		goto err;
-
-	wpa_printf(MSG_INFO, "Processing hidl events on FD %d", priv->hidl_fd);
-	// Look for read events from the hidl socket in the eloop.
-	if (eloop_register_read_sock(
-		priv->hidl_fd, wpas_hidl_sock_handler, global, priv) < 0)
-		goto err;
-
-	hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		goto err;
-	hidl_manager->registerHidlService(global);
-	// We may not need to store this hidl manager reference in the
-	// global data strucure because we've made it a singleton class.
-	priv->hidl_manager = (void *)hidl_manager;
-
-	return priv;
-err:
-	wpas_hidl_deinit(priv);
-	return NULL;
-}
-
-void wpas_hidl_deinit(struct wpas_hidl_priv *priv)
-{
-	if (!priv)
-		return;
-
-	wpa_printf(MSG_DEBUG, "Deiniting hidl control");
-
-	HidlManager::destroyInstance();
-	eloop_unregister_read_sock(priv->hidl_fd);
-	os_free(priv);
-}
-
-int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s || !wpa_s->global->hidl)
-		return 1;
-
-	wpa_printf(
-	    MSG_DEBUG, "Registering interface to hidl control: %s",
-	    wpa_s->ifname);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return 1;
-
-	return hidl_manager->registerInterface(wpa_s);
-}
-
-int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s || !wpa_s->global->hidl)
-		return 1;
-
-	wpa_printf(
-	    MSG_DEBUG, "Deregistering interface from hidl control: %s",
-	    wpa_s->ifname);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return 1;
-
-	return hidl_manager->unregisterInterface(wpa_s);
-}
-
-int wpas_hidl_register_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	if (!wpa_s || !wpa_s->global->hidl || !ssid)
-		return 1;
-
-	wpa_printf(
-	    MSG_DEBUG, "Registering network to hidl control: %d", ssid->id);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return 1;
-
-	return hidl_manager->registerNetwork(wpa_s, ssid);
-}
-
-int wpas_hidl_unregister_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	if (!wpa_s || !wpa_s->global->hidl || !ssid)
-		return 1;
-
-	wpa_printf(
-	    MSG_DEBUG, "Deregistering network from hidl control: %d", ssid->id);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return 1;
-
-	return hidl_manager->unregisterNetwork(wpa_s, ssid);
-}
-
-int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s || !wpa_s->global->hidl)
-		return 1;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying state change event to hidl control: %d",
-	    wpa_s->wpa_state);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return 1;
-
-	return hidl_manager->notifyStateChange(wpa_s);
-}
-
-int wpas_hidl_notify_network_request(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
-    enum wpa_ctrl_req_type rtype, const char *default_txt)
-{
-	if (!wpa_s || !wpa_s->global->hidl || !ssid)
-		return 1;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying network request to hidl control: %d",
-	    ssid->id);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return 1;
-
-	return hidl_manager->notifyNetworkRequest(
-	    wpa_s, ssid, rtype, default_txt);
-}
-
-void wpas_hidl_notify_anqp_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
-    const struct wpa_bss_anqp *anqp)
-{
-	if (!wpa_s || !wpa_s->global->hidl || !bssid || !result || !anqp)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying ANQP query done to hidl control: " MACSTR "result: %s",
-	    MAC2STR(bssid), result);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyAnqpQueryDone(wpa_s, bssid, result, anqp);
-}
-
-void wpas_hidl_notify_hs20_icon_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
-    const u8 *image, u32 image_length)
-{
-	if (!wpa_s || !wpa_s->global->hidl || !bssid || !file_name || !image)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying HS20 icon query done to hidl control: " MACSTR
-		       "file_name: %s",
-	    MAC2STR(bssid), file_name);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyHs20IconQueryDone(
-	    wpa_s, bssid, file_name, image, image_length);
-}
-
-void wpas_hidl_notify_hs20_rx_subscription_remediation(
-    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
-	if (!wpa_s || !wpa_s->global->hidl || !url)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying HS20 subscription remediation rx to hidl control: %s",
-	    url);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyHs20RxSubscriptionRemediation(
-	    wpa_s, url, osu_method);
-}
-
-void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
-    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
-{
-	if (!wpa_s || !wpa_s->global->hidl || !url)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying HS20 deauth imminent notice rx to hidl control: %s",
-	    url);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyHs20RxDeauthImminentNotice(
-	    wpa_s, code, reauth_delay, url);
-}
-
-void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying disconnect reason to hidl control: %d",
-	    wpa_s->disconnect_reason);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyDisconnectReason(wpa_s);
-}
-
-void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying assoc reject to hidl control: %d",
-	    wpa_s->assoc_status_code);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyAssocReject(wpa_s);
-}
-
-void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	wpa_printf(MSG_DEBUG, "Notifying auth timeout to hidl control");
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyAuthTimeout(wpa_s);
-}
-
-void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	wpa_printf(MSG_DEBUG, "Notifying bssid changed to hidl control");
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyBssidChanged(wpa_s);
-}
-
-void wpas_hidl_notify_wps_event_fail(
-    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
-    uint16_t error_indication)
-{
-	if (!wpa_s || !peer_macaddr)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying Wps event fail to hidl control: %d, %d",
-	    config_error, error_indication);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyWpsEventFail(
-	    wpa_s, peer_macaddr, config_error, error_indication);
-}
-
-void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	wpa_printf(MSG_DEBUG, "Notifying Wps event success to hidl control");
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyWpsEventSuccess(wpa_s);
-}
-
-void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying Wps event PBC overlap to hidl control");
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyWpsEventPbcOverlap(wpa_s);
-}
-
-void wpas_hidl_notify_p2p_device_found(
-    struct wpa_supplicant *wpa_s, const u8 *addr,
-    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
-    u8 peer_wfd_device_info_len)
-{
-	if (!wpa_s || !addr || !info)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying P2P device found to hidl control " MACSTR,
-	    MAC2STR(info->p2p_device_addr));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pDeviceFound(
-	    wpa_s, addr, info, peer_wfd_device_info, peer_wfd_device_info_len);
-}
-
-void wpas_hidl_notify_p2p_device_lost(
-    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
-	if (!wpa_s || !p2p_device_addr)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying P2P device lost to hidl control " MACSTR,
-	    MAC2STR(p2p_device_addr));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pDeviceLost(wpa_s, p2p_device_addr);
-}
-
-void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	wpa_printf(MSG_DEBUG, "Notifying P2P find stop to hidl control");
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pFindStopped(wpa_s);
-}
-
-void wpas_hidl_notify_p2p_go_neg_req(
-    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
-    u8 go_intent)
-{
-	if (!wpa_s || !src_addr)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P GO negotiation request to hidl control " MACSTR,
-	    MAC2STR(src_addr));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pGoNegReq(
-	    wpa_s, src_addr, dev_passwd_id, go_intent);
-}
-
-void wpas_hidl_notify_p2p_go_neg_completed(
-    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
-	if (!wpa_s || !res)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P GO negotiation completed to hidl control: %d",
-	    res->status);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pGoNegCompleted(wpa_s, res);
-}
-
-void wpas_hidl_notify_p2p_group_formation_failure(
-    struct wpa_supplicant *wpa_s, const char *reason)
-{
-	if (!wpa_s || !reason)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P Group formation failure to hidl control: %s",
-	    reason);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pGroupFormationFailure(wpa_s, reason);
-}
-
-void wpas_hidl_notify_p2p_group_started(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
-    int client)
-{
-	if (!wpa_s || !ssid)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying P2P Group start to hidl control: %d",
-	    ssid->id);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pGroupStarted(wpa_s, ssid, persistent, client);
-}
-
-void wpas_hidl_notify_p2p_group_removed(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
-{
-	if (!wpa_s || !ssid || !role)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG, "Notifying P2P Group removed to hidl control: %d",
-	    ssid->id);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pGroupRemoved(wpa_s, ssid, role);
-}
-
-void wpas_hidl_notify_p2p_invitation_received(
-    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
-    const u8 *bssid, int id, int op_freq)
-{
-	if (!wpa_s || !sa || !go_dev_addr || !bssid)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P invitation received to hidl control: %d " MACSTR, id,
-	    MAC2STR(bssid));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pInvitationReceived(
-	    wpa_s, sa, go_dev_addr, bssid, id, op_freq);
-}
-
-void wpas_hidl_notify_p2p_invitation_result(
-    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
-	if (!wpa_s)
-		return;
-	if (bssid) {
-		wpa_printf(
-			MSG_DEBUG,
-			"Notifying P2P invitation result to hidl control: " MACSTR,
-			MAC2STR(bssid));
-	} else {
-		wpa_printf(
-			MSG_DEBUG,
-			"Notifying P2P invitation result to hidl control: NULL bssid");
-	}
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pInvitationResult(wpa_s, status, bssid);
-}
-
-void wpas_hidl_notify_p2p_provision_discovery(
-    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
-    enum p2p_prov_disc_status status, u16 config_methods,
-    unsigned int generated_pin)
-{
-	if (!wpa_s || !dev_addr)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P provision discovery to hidl control " MACSTR,
-	    MAC2STR(dev_addr));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pProvisionDiscovery(
-	    wpa_s, dev_addr, request, status, config_methods, generated_pin);
-}
-
-void wpas_hidl_notify_p2p_sd_response(
-    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
-    const u8 *tlvs, size_t tlvs_len)
-{
-	if (!wpa_s || !sa || !tlvs)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P service discovery response to hidl control " MACSTR,
-	    MAC2STR(sa));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyP2pSdResponse(
-	    wpa_s, sa, update_indic, tlvs, tlvs_len);
-}
-
-void wpas_hidl_notify_ap_sta_authorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-	if (!wpa_s || !sta)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P AP STA authorized to hidl control " MACSTR,
-	    MAC2STR(sta));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyApStaAuthorized(wpa_s, sta, p2p_dev_addr);
-}
-
-void wpas_hidl_notify_ap_sta_deauthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-	if (!wpa_s || !sta)
-		return;
-
-	wpa_printf(
-	    MSG_DEBUG,
-	    "Notifying P2P AP STA deauthorized to hidl control " MACSTR,
-	    MAC2STR(sta));
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager)
-		return;
-
-	hidl_manager->notifyApStaDeauthorized(wpa_s, sta, p2p_dev_addr);
-}
diff --git a/wpa_supplicant/hidl/1.0/hidl.h b/wpa_supplicant/hidl/1.0/hidl.h
deleted file mode 100644
index 96631f2..0000000
--- a/wpa_supplicant/hidl/1.0/hidl.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_H
-#define WPA_SUPPLICANT_HIDL_HIDL_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif  // _cplusplus
-
-/**
- * This is the hidl RPC interface entry point to the wpa_supplicant core.
- * This initializes the hidl driver & HidlManager instance and then forwards
- * all the notifcations from the supplicant core to the HidlManager.
- */
-struct wpas_hidl_priv;
-struct wpa_global;
-
-struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global);
-void wpas_hidl_deinit(struct wpas_hidl_priv *priv);
-
-#ifdef CONFIG_CTRL_IFACE_HIDL
-int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_register_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_unregister_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s);
-int wpas_hidl_notify_network_request(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
-    enum wpa_ctrl_req_type rtype, const char *default_txt);
-void wpas_hidl_notify_anqp_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
-    const struct wpa_bss_anqp *anqp);
-void wpas_hidl_notify_hs20_icon_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
-    const u8 *image, u32 image_length);
-void wpas_hidl_notify_hs20_rx_subscription_remediation(
-    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
-void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
-    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url);
-void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_fail(
-    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
-    uint16_t error_indication);
-void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_device_found(
-    struct wpa_supplicant *wpa_s, const u8 *addr,
-    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
-    u8 peer_wfd_device_info_len);
-void wpas_hidl_notify_p2p_device_lost(
-    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
-void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_go_neg_req(
-    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
-    u8 go_intent);
-void wpas_hidl_notify_p2p_go_neg_completed(
-    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
-void wpas_hidl_notify_p2p_group_formation_failure(
-    struct wpa_supplicant *wpa_s, const char *reason);
-void wpas_hidl_notify_p2p_group_started(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
-    int client);
-void wpas_hidl_notify_p2p_group_removed(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
-    const char *role);
-void wpas_hidl_notify_p2p_invitation_received(
-    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
-    const u8 *bssid, int id, int op_freq);
-void wpas_hidl_notify_p2p_invitation_result(
-    struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
-void wpas_hidl_notify_p2p_provision_discovery(
-    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
-    enum p2p_prov_disc_status status, u16 config_methods,
-    unsigned int generated_pin);
-void wpas_hidl_notify_p2p_sd_response(
-    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
-    const u8 *tlvs, size_t tlvs_len);
-void wpas_hidl_notify_ap_sta_authorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-void wpas_hidl_notify_ap_sta_deauthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-#else   // CONFIG_CTRL_IFACE_HIDL
-static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-static inline int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-static inline int wpas_hidl_register_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	return 0;
-}
-static inline int wpas_hidl_unregister_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	return 0;
-}
-static inline int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-static inline int wpas_hidl_notify_network_request(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
-    enum wpa_ctrl_req_type rtype, const char *default_txt)
-{
-	return 0;
-}
-static void wpas_hidl_notify_anqp_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
-    const struct wpa_bss_anqp *anqp)
-{
-}
-static void wpas_hidl_notify_hs20_icon_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
-    const u8 *image, u32 image_length)
-{
-}
-static void wpas_hidl_notify_hs20_rx_subscription_remediation(
-    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
-}
-static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
-    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
-{
-}
-static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_fail(
-    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
-    uint16_t error_indication)
-{
-}
-static void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
-{
-}
-static void wpas_hidl_notify_p2p_device_found(
-    struct wpa_supplicant *wpa_s, const u8 *addr,
-    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
-    u8 peer_wfd_device_info_len);
-{
-}
-static void wpas_hidl_notify_p2p_device_lost(
-    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
-}
-static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_p2p_go_neg_req(
-    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
-    u8 go_intent)
-{
-}
-static void wpas_hidl_notify_p2p_go_neg_completed(
-    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
-}
-static void wpas_hidl_notify_p2p_group_formation_failure(
-    struct wpa_supplicant *wpa_s, const char *reason)
-{
-}
-static void wpas_hidl_notify_p2p_group_started(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
-    int client)
-{
-}
-static void wpas_hidl_notify_p2p_group_removed(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_received(
-    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
-    const u8 *bssid, int id, int op_freq)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_result(
-    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
-}
-static void wpas_hidl_notify_p2p_provision_discovery(
-    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
-    enum p2p_prov_disc_status status, u16 config_methods,
-    unsigned int generated_pin)
-{
-}
-static void wpas_hidl_notify_p2p_sd_response(
-    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
-    const u8 *tlvs, size_t tlvs_len)
-{
-}
-static void wpas_hidl_notify_ap_sta_authorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-static void wpas_hidl_notify_ap_sta_deauthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-#endif  // CONFIG_CTRL_IFACE_HIDL
-
-#ifdef _cplusplus
-}
-#endif  // _cplusplus
-
-#endif  // WPA_SUPPLICANT_HIDL_HIDL_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_manager.cpp b/wpa_supplicant/hidl/1.0/hidl_manager.cpp
deleted file mode 100644
index 4655da2..0000000
--- a/wpa_supplicant/hidl/1.0/hidl_manager.cpp
+++ /dev/null
@@ -1,1777 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include <algorithm>
-#include <regex>
-
-#include "hidl_manager.h"
-#include "misc_utils.h"
-
-extern "C" {
-#include "src/eap_common/eap_sim_common.h"
-}
-
-namespace {
-using android::hardware::hidl_array;
-
-constexpr uint8_t kWfdDeviceInfoLen = 6;
-// GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
-constexpr char kGsmAuthRegex2[] = "GSM-AUTH:([0-9a-f]+):([0-9a-f]+)";
-constexpr char kGsmAuthRegex3[] =
-    "GSM-AUTH:([0-9a-f]+):([0-9a-f]+):([0-9a-f]+)";
-// UMTS-AUTH:<RAND>:<AUTN>
-constexpr char kUmtsAuthRegex[] = "UMTS-AUTH:([0-9a-f]+):([0-9a-f]+)";
-constexpr size_t kGsmRandLenBytes = GSM_RAND_LEN;
-constexpr size_t kUmtsRandLenBytes = EAP_AKA_RAND_LEN;
-constexpr size_t kUmtsAutnLenBytes = EAP_AKA_AUTN_LEN;
-constexpr u8 kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
-/**
- * Check if the provided |wpa_supplicant| structure represents a P2P iface or
- * not.
- */
-constexpr bool isP2pIface(const struct wpa_supplicant *wpa_s)
-{
-	return (wpa_s->global->p2p_init_wpa_s == wpa_s);
-}
-
-/**
- * Creates a unique key for the network using the provided |ifname| and
- * |network_id| to be used in the internal map of |ISupplicantNetwork| objects.
- * This is of the form |ifname|_|network_id|. For ex: "wlan0_1".
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- */
-const std::string getNetworkObjectMapKey(
-    const std::string &ifname, int network_id)
-{
-	return ifname + "_" + std::to_string(network_id);
-}
-
-/**
- * Add callback to the corresponding list after linking to death on the
- * corresponding hidl object reference.
- */
-template <class CallbackType>
-int registerForDeathAndAddCallbackHidlObjectToList(
-    const android::sp<CallbackType> &callback,
-    const std::function<void(const android::sp<CallbackType> &)>
-	&on_hidl_died_fctor,
-    std::vector<android::sp<CallbackType>> &callback_list)
-{
-#if 0   // TODO(b/31632518): HIDL object death notifications.
-	auto death_notifier = new CallbackObjectDeathNotifier<CallbackType>(
-	    callback, on_hidl_died_fctor);
-	// Use the |callback.get()| as cookie so that we don't need to
-	// store a reference to this |CallbackObjectDeathNotifier| instance
-	// to use in |unlinkToDeath| later.
-	// NOTE: This may cause an immediate callback if the object is already
-	// dead, so add it to the list before we register for callback!
-	if (android::hardware::IInterface::asBinder(callback)->linkToDeath(
-		death_notifier, callback.get()) != android::OK) {
-		wpa_printf(
-		    MSG_ERROR,
-		    "Error registering for death notification for "
-		    "supplicant callback object");
-		callback_list.erase(
-		    std::remove(
-			callback_list.begin(), callback_list.end(), callback),
-		    callback_list.end());
-		return 1;
-	}
-#endif  // TODO(b/31632518): HIDL object death notifications.
-	callback_list.push_back(callback);
-	return 0;
-}
-
-template <class ObjectType>
-int addHidlObjectToMap(
-    const std::string &key, const android::sp<ObjectType> object,
-    std::map<const std::string, android::sp<ObjectType>> &object_map)
-{
-	// Return failure if we already have an object for that |key|.
-	if (object_map.find(key) != object_map.end())
-		return 1;
-	object_map[key] = object;
-	if (!object_map[key].get())
-		return 1;
-	return 0;
-}
-
-template <class ObjectType>
-int removeHidlObjectFromMap(
-    const std::string &key,
-    std::map<const std::string, android::sp<ObjectType>> &object_map)
-{
-	// Return failure if we dont have an object for that |key|.
-	const auto &object_iter = object_map.find(key);
-	if (object_iter == object_map.end())
-		return 1;
-	object_iter->second->invalidate();
-	object_map.erase(object_iter);
-	return 0;
-}
-
-template <class CallbackType>
-int addIfaceCallbackHidlObjectToMap(
-    const std::string &ifname, const android::sp<CallbackType> &callback,
-    const std::function<void(const android::sp<CallbackType> &)>
-	&on_hidl_died_fctor,
-    std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	if (ifname.empty())
-		return 1;
-
-	auto iface_callback_map_iter = callbacks_map.find(ifname);
-	if (iface_callback_map_iter == callbacks_map.end())
-		return 1;
-	auto &iface_callback_list = iface_callback_map_iter->second;
-
-	// Register for death notification before we add it to our list.
-	return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
-	    callback, on_hidl_died_fctor, iface_callback_list);
-}
-
-template <class CallbackType>
-int addNetworkCallbackHidlObjectToMap(
-    const std::string &ifname, int network_id,
-    const android::sp<CallbackType> &callback,
-    const std::function<void(const android::sp<CallbackType> &)>
-	&on_hidl_died_fctor,
-    std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	if (ifname.empty() || network_id < 0)
-		return 1;
-
-	// Generate the key to be used to lookup the network.
-	const std::string network_key =
-	    getNetworkObjectMapKey(ifname, network_id);
-	auto network_callback_map_iter = callbacks_map.find(network_key);
-	if (network_callback_map_iter == callbacks_map.end())
-		return 1;
-	auto &network_callback_list = network_callback_map_iter->second;
-
-	// Register for death notification before we add it to our list.
-	return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
-	    callback, on_hidl_died_fctor, network_callback_list);
-}
-
-template <class CallbackType>
-int removeAllIfaceCallbackHidlObjectsFromMap(
-    const std::string &ifname,
-    std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	auto iface_callback_map_iter = callbacks_map.find(ifname);
-	if (iface_callback_map_iter == callbacks_map.end())
-		return 1;
-#if 0   // TODO(b/31632518): HIDL object death notifications.
-	const auto &iface_callback_list = iface_callback_map_iter->second;
-	for (const auto &callback : iface_callback_list) {
-		if (android::hardware::IInterface::asBinder(callback)
-			->unlinkToDeath(nullptr, callback.get()) !=
-		    android::OK) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Error deregistering for death notification for "
-			    "iface callback object");
-		}
-	}
-#endif  // TODO(b/31632518): HIDL object death notifications.
-	callbacks_map.erase(iface_callback_map_iter);
-	return 0;
-}
-
-template <class CallbackType>
-int removeAllNetworkCallbackHidlObjectsFromMap(
-    const std::string &network_key,
-    std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	auto network_callback_map_iter = callbacks_map.find(network_key);
-	if (network_callback_map_iter == callbacks_map.end())
-		return 1;
-#if 0   // TODO(b/31632518): HIDL object death notifications.
-	const auto &network_callback_list = network_callback_map_iter->second;
-	for (const auto &callback : network_callback_list) {
-		if (android::hardware::IInterface::asBinder(callback)
-			->unlinkToDeath(nullptr, callback.get()) !=
-		    android::OK) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Error deregistering for death "
-			    "notification for "
-			    "network callback object");
-		}
-	}
-#endif  // TODO(b/31632518): HIDL object death notifications.
-	callbacks_map.erase(network_callback_map_iter);
-	return 0;
-}
-
-template <class CallbackType>
-void removeIfaceCallbackHidlObjectFromMap(
-    const std::string &ifname, const android::sp<CallbackType> &callback,
-    std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	if (ifname.empty())
-		return;
-
-	auto iface_callback_map_iter = callbacks_map.find(ifname);
-	if (iface_callback_map_iter == callbacks_map.end())
-		return;
-
-	auto &iface_callback_list = iface_callback_map_iter->second;
-	iface_callback_list.erase(
-	    std::remove(
-		iface_callback_list.begin(), iface_callback_list.end(),
-		callback),
-	    iface_callback_list.end());
-}
-
-template <class CallbackType>
-void removeNetworkCallbackHidlObjectFromMap(
-    const std::string &ifname, int network_id,
-    const android::sp<CallbackType> &callback,
-    std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	if (ifname.empty() || network_id < 0)
-		return;
-
-	// Generate the key to be used to lookup the network.
-	const std::string network_key =
-	    getNetworkObjectMapKey(ifname, network_id);
-
-	auto network_callback_map_iter = callbacks_map.find(network_key);
-	if (network_callback_map_iter == callbacks_map.end())
-		return;
-
-	auto &network_callback_list = network_callback_map_iter->second;
-	network_callback_list.erase(
-	    std::remove(
-		network_callback_list.begin(), network_callback_list.end(),
-		callback),
-	    network_callback_list.end());
-}
-
-template <class CallbackType>
-void callWithEachIfaceCallback(
-    const std::string &ifname,
-    const std::function<
-	android::hardware::Return<void>(android::sp<CallbackType>)> &method,
-    const std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	if (ifname.empty())
-		return;
-
-	auto iface_callback_map_iter = callbacks_map.find(ifname);
-	if (iface_callback_map_iter == callbacks_map.end())
-		return;
-	const auto &iface_callback_list = iface_callback_map_iter->second;
-	for (const auto &callback : iface_callback_list) {
-		if (!method(callback).isOk()) {
-			wpa_printf(
-			    MSG_ERROR, "Failed to invoke HIDL iface callback");
-		}
-	}
-}
-
-template <class CallbackType>
-void callWithEachNetworkCallback(
-    const std::string &ifname, int network_id,
-    const std::function<
-	android::hardware::Return<void>(android::sp<CallbackType>)> &method,
-    const std::map<const std::string, std::vector<android::sp<CallbackType>>>
-	&callbacks_map)
-{
-	if (ifname.empty() || network_id < 0)
-		return;
-
-	// Generate the key to be used to lookup the network.
-	const std::string network_key =
-	    getNetworkObjectMapKey(ifname, network_id);
-	auto network_callback_map_iter = callbacks_map.find(network_key);
-	if (network_callback_map_iter == callbacks_map.end())
-		return;
-	const auto &network_callback_list = network_callback_map_iter->second;
-	for (const auto &callback : network_callback_list) {
-		if (!method(callback).isOk()) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to invoke HIDL network callback");
-		}
-	}
-}
-
-int parseGsmAuthNetworkRequest(
-    const std::string &params_str,
-    std::vector<hidl_array<uint8_t, kGsmRandLenBytes>> *out_rands)
-{
-	std::smatch matches;
-	std::regex params_gsm_regex2(kGsmAuthRegex2);
-	std::regex params_gsm_regex3(kGsmAuthRegex3);
-	if (!std::regex_match(params_str, matches, params_gsm_regex3) &&
-	    !std::regex_match(params_str, matches, params_gsm_regex2)) {
-		return 1;
-	}
-	for (uint32_t i = 1; i < matches.size(); i++) {
-		hidl_array<uint8_t, kGsmRandLenBytes> rand;
-		const auto &match = matches[i];
-		WPA_ASSERT(match.size() >= 2 * rand.size());
-		if (hexstr2bin(match.str().c_str(), rand.data(), rand.size())) {
-			wpa_printf(
-			    MSG_ERROR, "Failed to parse GSM auth params");
-			return 1;
-		}
-		out_rands->push_back(rand);
-	}
-	return 0;
-}
-
-int parseUmtsAuthNetworkRequest(
-    const std::string &params_str,
-    hidl_array<uint8_t, kUmtsRandLenBytes> *out_rand,
-    hidl_array<uint8_t, kUmtsAutnLenBytes> *out_autn)
-{
-	std::smatch matches;
-	std::regex params_umts_regex(kUmtsAuthRegex);
-	if (!std::regex_match(params_str, matches, params_umts_regex)) {
-		return 1;
-	}
-	WPA_ASSERT(matches[1].size() >= 2 * out_rand->size());
-	if (hexstr2bin(
-		matches[1].str().c_str(), out_rand->data(), out_rand->size())) {
-		wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
-		return 1;
-	}
-	WPA_ASSERT(matches[2].size() >= 2 * out_autn->size());
-	if (hexstr2bin(
-		matches[2].str().c_str(), out_autn->data(), out_autn->size())) {
-		wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
-		return 1;
-	}
-	return 0;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-HidlManager *HidlManager::instance_ = NULL;
-
-HidlManager *HidlManager::getInstance()
-{
-	if (!instance_)
-		instance_ = new HidlManager();
-	return instance_;
-}
-
-void HidlManager::destroyInstance()
-{
-	if (instance_)
-		delete instance_;
-	instance_ = NULL;
-}
-
-int HidlManager::registerHidlService(struct wpa_global *global)
-{
-	// Create the main hidl service object and register it.
-	supplicant_object_ = new Supplicant(global);
-	if (supplicant_object_->registerAsService() != android::NO_ERROR) {
-		return 1;
-	}
-	if (!supplicant_object_->ensureConfigFileExists()) {
-		// If config file does not exist, we cannot start supplicant.
-		return 1;
-	}
-	return 0;
-}
-
-/**
- * Register an interface to hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::registerInterface(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return 1;
-
-	if (isP2pIface(wpa_s)) {
-		if (addHidlObjectToMap<P2pIface>(
-			wpa_s->ifname,
-			new P2pIface(wpa_s->global, wpa_s->ifname),
-			p2p_iface_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to register P2P interface with HIDL "
-			    "control: %s",
-			    wpa_s->ifname);
-			return 1;
-		}
-		p2p_iface_callbacks_map_[wpa_s->ifname] =
-		    std::vector<android::sp<ISupplicantP2pIfaceCallback>>();
-	} else {
-		if (addHidlObjectToMap<StaIface>(
-			wpa_s->ifname,
-			new StaIface(wpa_s->global, wpa_s->ifname),
-			sta_iface_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to register STA interface with HIDL "
-			    "control: %s",
-			    wpa_s->ifname);
-			return 1;
-		}
-		sta_iface_callbacks_map_[wpa_s->ifname] =
-		    std::vector<android::sp<ISupplicantStaIfaceCallback>>();
-	}
-
-	// Invoke the |onInterfaceCreated| method on all registered callbacks.
-	callWithEachSupplicantCallback(std::bind(
-	    &ISupplicantCallback::onInterfaceCreated, std::placeholders::_1,
-	    wpa_s->ifname));
-	return 0;
-}
-
-/**
- * Unregister an interface from hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::unregisterInterface(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return 1;
-
-	if (isP2pIface(wpa_s)) {
-		if (removeHidlObjectFromMap(
-			wpa_s->ifname, p2p_iface_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to unregister P2P interface with HIDL "
-			    "control: %s",
-			    wpa_s->ifname);
-			return 1;
-		}
-		if (removeAllIfaceCallbackHidlObjectsFromMap(
-			wpa_s->ifname, p2p_iface_callbacks_map_)) {
-			return 1;
-		}
-	} else {
-		if (removeHidlObjectFromMap(
-			wpa_s->ifname, sta_iface_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to unregister STA interface with HIDL "
-			    "control: %s",
-			    wpa_s->ifname);
-			return 1;
-		}
-		if (removeAllIfaceCallbackHidlObjectsFromMap(
-			wpa_s->ifname, sta_iface_callbacks_map_)) {
-			return 1;
-		}
-	}
-
-	// Invoke the |onInterfaceRemoved| method on all registered callbacks.
-	callWithEachSupplicantCallback(std::bind(
-	    &ISupplicantCallback::onInterfaceRemoved, std::placeholders::_1,
-	    wpa_s->ifname));
-	return 0;
-}
-
-/**
- * Register a network to hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is added.
- * @param ssid |wpa_ssid| struct corresponding to the network being added.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::registerNetwork(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	if (!wpa_s || !ssid)
-		return 1;
-
-	// Generate the key to be used to lookup the network.
-	const std::string network_key =
-	    getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
-
-	if (isP2pIface(wpa_s)) {
-		if (addHidlObjectToMap<P2pNetwork>(
-			network_key,
-			new P2pNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
-			p2p_network_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to register P2P network with HIDL "
-			    "control: %d",
-			    ssid->id);
-			return 1;
-		}
-		p2p_network_callbacks_map_[network_key] =
-		    std::vector<android::sp<ISupplicantP2pNetworkCallback>>();
-		// Invoke the |onNetworkAdded| method on all registered
-		// callbacks.
-		callWithEachP2pIfaceCallback(
-		    wpa_s->ifname,
-		    std::bind(
-			&ISupplicantP2pIfaceCallback::onNetworkAdded,
-			std::placeholders::_1, ssid->id));
-	} else {
-		if (addHidlObjectToMap<StaNetwork>(
-			network_key,
-			new StaNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
-			sta_network_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to register STA network with HIDL "
-			    "control: %d",
-			    ssid->id);
-			return 1;
-		}
-		sta_network_callbacks_map_[network_key] =
-		    std::vector<android::sp<ISupplicantStaNetworkCallback>>();
-		// Invoke the |onNetworkAdded| method on all registered
-		// callbacks.
-		callWithEachStaIfaceCallback(
-		    wpa_s->ifname,
-		    std::bind(
-			&ISupplicantStaIfaceCallback::onNetworkAdded,
-			std::placeholders::_1, ssid->id));
-	}
-	return 0;
-}
-
-/**
- * Unregister a network from hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is added.
- * @param ssid |wpa_ssid| struct corresponding to the network being added.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::unregisterNetwork(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	if (!wpa_s || !ssid)
-		return 1;
-
-	// Generate the key to be used to lookup the network.
-	const std::string network_key =
-	    getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
-
-	if (isP2pIface(wpa_s)) {
-		if (removeHidlObjectFromMap(
-			network_key, p2p_network_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to unregister P2P network with HIDL "
-			    "control: %d",
-			    ssid->id);
-			return 1;
-		}
-		if (removeAllNetworkCallbackHidlObjectsFromMap(
-			network_key, p2p_network_callbacks_map_))
-			return 1;
-
-		// Invoke the |onNetworkRemoved| method on all registered
-		// callbacks.
-		callWithEachP2pIfaceCallback(
-		    wpa_s->ifname,
-		    std::bind(
-			&ISupplicantP2pIfaceCallback::onNetworkRemoved,
-			std::placeholders::_1, ssid->id));
-	} else {
-		if (removeHidlObjectFromMap(
-			network_key, sta_network_object_map_)) {
-			wpa_printf(
-			    MSG_ERROR,
-			    "Failed to unregister STA network with HIDL "
-			    "control: %d",
-			    ssid->id);
-			return 1;
-		}
-		if (removeAllNetworkCallbackHidlObjectsFromMap(
-			network_key, sta_network_callbacks_map_))
-			return 1;
-
-		// Invoke the |onNetworkRemoved| method on all registered
-		// callbacks.
-		callWithEachStaIfaceCallback(
-		    wpa_s->ifname,
-		    std::bind(
-			&ISupplicantStaIfaceCallback::onNetworkRemoved,
-			std::placeholders::_1, ssid->id));
-	}
-	return 0;
-}
-
-/**
- * Notify all listeners about any state changes on a particular interface.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the state change event occured.
- */
-int HidlManager::notifyStateChange(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return 1;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return 1;
-
-	// Invoke the |onStateChanged| method on all registered callbacks.
-	uint32_t hidl_network_id = UINT32_MAX;
-	std::vector<uint8_t> hidl_ssid;
-	if (wpa_s->current_ssid) {
-		hidl_network_id = wpa_s->current_ssid->id;
-		hidl_ssid.assign(
-		    wpa_s->current_ssid->ssid,
-		    wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
-	}
-	uint8_t *bssid;
-	// wpa_supplicant sets the |pending_bssid| field when it starts a
-	// connection. Only after association state does it update the |bssid|
-	// field. So, in the HIDL callback send the appropriate bssid.
-	if (wpa_s->wpa_state <= WPA_ASSOCIATED) {
-		bssid = wpa_s->pending_bssid;
-	} else {
-		bssid = wpa_s->bssid;
-	}
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantStaIfaceCallback::onStateChanged,
-			       std::placeholders::_1,
-			       static_cast<ISupplicantStaIfaceCallback::State>(
-				   wpa_s->wpa_state),
-			       bssid, hidl_network_id, hidl_ssid));
-	return 0;
-}
-
-/**
- * Notify all listeners about a request on a particular network.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is present.
- * @param ssid |wpa_ssid| struct corresponding to the network.
- * @param type type of request.
- * @param param addition params associated with the request.
- */
-int HidlManager::notifyNetworkRequest(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
-    const char *param)
-{
-	if (!wpa_s || !ssid)
-		return 1;
-
-	const std::string network_key =
-	    getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
-	if (sta_network_object_map_.find(network_key) ==
-	    sta_network_object_map_.end())
-		return 1;
-
-	if (type == WPA_CTRL_REQ_EAP_IDENTITY) {
-		callWithEachStaNetworkCallback(
-		    wpa_s->ifname, ssid->id,
-		    std::bind(
-			&ISupplicantStaNetworkCallback::
-			    onNetworkEapIdentityRequest,
-			std::placeholders::_1));
-		return 0;
-	}
-	if (type == WPA_CTRL_REQ_SIM) {
-		std::vector<hidl_array<uint8_t, 16>> gsm_rands;
-		hidl_array<uint8_t, 16> umts_rand;
-		hidl_array<uint8_t, 16> umts_autn;
-		if (!parseGsmAuthNetworkRequest(param, &gsm_rands)) {
-			ISupplicantStaNetworkCallback::
-			    NetworkRequestEapSimGsmAuthParams hidl_params;
-			hidl_params.rands = gsm_rands;
-			callWithEachStaNetworkCallback(
-			    wpa_s->ifname, ssid->id,
-			    std::bind(
-				&ISupplicantStaNetworkCallback::
-				    onNetworkEapSimGsmAuthRequest,
-				std::placeholders::_1, hidl_params));
-			return 0;
-		}
-		if (!parseUmtsAuthNetworkRequest(
-			param, &umts_rand, &umts_autn)) {
-			ISupplicantStaNetworkCallback::
-			    NetworkRequestEapSimUmtsAuthParams hidl_params;
-			hidl_params.rand = umts_rand;
-			hidl_params.autn = umts_autn;
-			callWithEachStaNetworkCallback(
-			    wpa_s->ifname, ssid->id,
-			    std::bind(
-				&ISupplicantStaNetworkCallback::
-				    onNetworkEapSimUmtsAuthRequest,
-				std::placeholders::_1, hidl_params));
-			return 0;
-		}
-	}
-	return 1;
-}
-
-/**
- * Notify all listeners about the end of an ANQP query.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- * @param bssid BSSID of the access point.
- * @param result Result of the operation ("SUCCESS" or "FAILURE").
- * @param anqp |wpa_bss_anqp| ANQP data fetched.
- */
-void HidlManager::notifyAnqpQueryDone(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
-    const struct wpa_bss_anqp *anqp)
-{
-	if (!wpa_s || !bssid || !result || !anqp)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	ISupplicantStaIfaceCallback::AnqpData hidl_anqp_data;
-	ISupplicantStaIfaceCallback::Hs20AnqpData hidl_hs20_anqp_data;
-	if (std::string(result) == "SUCCESS") {
-		hidl_anqp_data.venueName =
-		    misc_utils::convertWpaBufToVector(anqp->venue_name);
-		hidl_anqp_data.roamingConsortium =
-		    misc_utils::convertWpaBufToVector(anqp->roaming_consortium);
-		hidl_anqp_data.ipAddrTypeAvailability =
-		    misc_utils::convertWpaBufToVector(
-			anqp->ip_addr_type_availability);
-		hidl_anqp_data.naiRealm =
-		    misc_utils::convertWpaBufToVector(anqp->nai_realm);
-		hidl_anqp_data.anqp3gppCellularNetwork =
-		    misc_utils::convertWpaBufToVector(anqp->anqp_3gpp);
-		hidl_anqp_data.domainName =
-		    misc_utils::convertWpaBufToVector(anqp->domain_name);
-
-		hidl_hs20_anqp_data.operatorFriendlyName =
-		    misc_utils::convertWpaBufToVector(
-			anqp->hs20_operator_friendly_name);
-		hidl_hs20_anqp_data.wanMetrics =
-		    misc_utils::convertWpaBufToVector(anqp->hs20_wan_metrics);
-		hidl_hs20_anqp_data.connectionCapability =
-		    misc_utils::convertWpaBufToVector(
-			anqp->hs20_connection_capability);
-		hidl_hs20_anqp_data.osuProvidersList =
-		    misc_utils::convertWpaBufToVector(
-			anqp->hs20_osu_providers_list);
-	}
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantStaIfaceCallback::onAnqpQueryDone,
-			       std::placeholders::_1, bssid, hidl_anqp_data,
-			       hidl_hs20_anqp_data));
-}
-
-/**
- * Notify all listeners about the end of an HS20 icon query.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- * @param bssid BSSID of the access point.
- * @param file_name Name of the icon file.
- * @param image Raw bytes of the icon file.
- * @param image_length Size of the the icon file.
- */
-void HidlManager::notifyHs20IconQueryDone(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
-    const u8 *image, u32 image_length)
-{
-	if (!wpa_s || !bssid || !file_name || !image)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onHs20IconQueryDone,
-		std::placeholders::_1, bssid, file_name,
-		std::vector<uint8_t>(image, image + image_length)));
-}
-
-/**
- * Notify all listeners about the reception of HS20 subscription
- * remediation notification from the server.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- * @param url URL of the server.
- * @param osu_method OSU method (OMA_DM or SOAP_XML_SPP).
- */
-void HidlManager::notifyHs20RxSubscriptionRemediation(
-    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
-	if (!wpa_s || !url)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	ISupplicantStaIfaceCallback::OsuMethod hidl_osu_method = {};
-	if (osu_method & 0x1) {
-		hidl_osu_method =
-		    ISupplicantStaIfaceCallback::OsuMethod::OMA_DM;
-	} else if (osu_method & 0x2) {
-		hidl_osu_method =
-		    ISupplicantStaIfaceCallback::OsuMethod::SOAP_XML_SPP;
-	}
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onHs20SubscriptionRemediation,
-		std::placeholders::_1, wpa_s->bssid, hidl_osu_method, url));
-}
-
-/**
- * Notify all listeners about the reception of HS20 immient deauth
- * notification from the server.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- * @param code Deauth reason code sent from server.
- * @param reauth_delay Reauthentication delay in seconds sent from server.
- * @param url URL of the server.
- */
-void HidlManager::notifyHs20RxDeauthImminentNotice(
-    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
-{
-	if (!wpa_s || !url)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onHs20DeauthImminentNotice,
-		std::placeholders::_1, wpa_s->bssid, code, reauth_delay, url));
-}
-
-/**
- * Notify all listeners about the reason code for disconnection from the
- * currently connected network.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is present.
- */
-void HidlManager::notifyDisconnectReason(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	const u8 *bssid = wpa_s->bssid;
-	if (is_zero_ether_addr(bssid)) {
-		bssid = wpa_s->pending_bssid;
-	}
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onDisconnected,
-		std::placeholders::_1, bssid, wpa_s->disconnect_reason < 0,
-		static_cast<ISupplicantStaIfaceCallback::ReasonCode>(
-		    abs(wpa_s->disconnect_reason))));
-}
-
-/**
- * Notify all listeners about association reject from the access point to which
- * we are attempting to connect.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is present.
- */
-void HidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	const u8 *bssid = wpa_s->bssid;
-	if (is_zero_ether_addr(bssid)) {
-		bssid = wpa_s->pending_bssid;
-	}
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onAssociationRejected,
-		std::placeholders::_1, bssid,
-		static_cast<ISupplicantStaIfaceCallback::StatusCode>(
-		    wpa_s->assoc_status_code),
-		wpa_s->assoc_timed_out == 1));
-}
-
-void HidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
-		return;
-
-	const u8 *bssid = wpa_s->bssid;
-	if (is_zero_ether_addr(bssid)) {
-		bssid = wpa_s->pending_bssid;
-	}
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onAuthenticationTimeout,
-		std::placeholders::_1, bssid));
-}
-
-void HidlManager::notifyBssidChanged(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	const std::string ifname(wpa_s->ifname);
-	if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
-		return;
-
-	// wpa_supplicant does not explicitly give us the reason for bssid
-	// change, but we figure that out from what is set out of |wpa_s->bssid|
-	// & |wpa_s->pending_bssid|.
-	const u8 *bssid;
-	ISupplicantStaIfaceCallback::BssidChangeReason reason;
-	if (is_zero_ether_addr(wpa_s->bssid) &&
-	    !is_zero_ether_addr(wpa_s->pending_bssid)) {
-		bssid = wpa_s->pending_bssid;
-		reason =
-		    ISupplicantStaIfaceCallback::BssidChangeReason::ASSOC_START;
-	} else if (
-	    !is_zero_ether_addr(wpa_s->bssid) &&
-	    is_zero_ether_addr(wpa_s->pending_bssid)) {
-		bssid = wpa_s->bssid;
-		reason = ISupplicantStaIfaceCallback::BssidChangeReason::
-		    ASSOC_COMPLETE;
-	} else if (
-	    is_zero_ether_addr(wpa_s->bssid) &&
-	    is_zero_ether_addr(wpa_s->pending_bssid)) {
-		bssid = wpa_s->pending_bssid;
-		reason =
-		    ISupplicantStaIfaceCallback::BssidChangeReason::DISASSOC;
-	} else {
-		wpa_printf(MSG_ERROR, "Unknown bssid change reason");
-		return;
-	}
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantStaIfaceCallback::onBssidChanged,
-			       std::placeholders::_1, reason, bssid));
-}
-
-void HidlManager::notifyWpsEventFail(
-    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
-    uint16_t error_indication)
-{
-	if (!wpa_s || !peer_macaddr)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onWpsEventFail,
-		std::placeholders::_1, peer_macaddr,
-		static_cast<ISupplicantStaIfaceCallback::WpsConfigError>(
-		    config_error),
-		static_cast<ISupplicantStaIfaceCallback::WpsErrorIndication>(
-		    error_indication)));
-}
-
-void HidlManager::notifyWpsEventSuccess(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantStaIfaceCallback::onWpsEventSuccess,
-			       std::placeholders::_1));
-}
-
-void HidlManager::notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onWpsEventPbcOverlap,
-		std::placeholders::_1));
-}
-
-void HidlManager::notifyP2pDeviceFound(
-    struct wpa_supplicant *wpa_s, const u8 *addr,
-    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
-    u8 peer_wfd_device_info_len)
-{
-	if (!wpa_s || !addr || !info)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	std::array<uint8_t, kWfdDeviceInfoLen> hidl_peer_wfd_device_info{};
-	if (peer_wfd_device_info) {
-		if (peer_wfd_device_info_len != kWfdDeviceInfoLen) {
-			wpa_printf(
-			    MSG_ERROR, "Unexpected WFD device info len: %d",
-			    peer_wfd_device_info_len);
-		} else {
-			os_memcpy(
-			    hidl_peer_wfd_device_info.data(),
-			    peer_wfd_device_info, kWfdDeviceInfoLen);
-		}
-	}
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onDeviceFound,
-		std::placeholders::_1, addr, info->p2p_device_addr,
-		info->pri_dev_type, info->device_name, info->config_methods,
-		info->dev_capab, info->group_capab, hidl_peer_wfd_device_info));
-}
-
-void HidlManager::notifyP2pDeviceLost(
-    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
-	if (!wpa_s || !p2p_device_addr)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantP2pIfaceCallback::onDeviceLost,
-			       std::placeholders::_1, p2p_device_addr));
-}
-
-void HidlManager::notifyP2pFindStopped(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantP2pIfaceCallback::onFindStopped,
-			       std::placeholders::_1));
-}
-
-void HidlManager::notifyP2pGoNegReq(
-    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
-    u8 /* go_intent */)
-{
-	if (!wpa_s || !src_addr)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onGoNegotiationRequest,
-		std::placeholders::_1, src_addr,
-		static_cast<ISupplicantP2pIfaceCallback::WpsDevPasswordId>(
-		    dev_passwd_id)));
-}
-
-void HidlManager::notifyP2pGoNegCompleted(
-    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
-	if (!wpa_s || !res)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onGoNegotiationCompleted,
-		std::placeholders::_1,
-		static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
-		    res->status)));
-}
-
-void HidlManager::notifyP2pGroupFormationFailure(
-    struct wpa_supplicant *wpa_s, const char *reason)
-{
-	if (!wpa_s || !reason)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onGroupFormationFailure,
-		std::placeholders::_1, reason));
-}
-
-void HidlManager::notifyP2pGroupStarted(
-    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid, int persistent, int client)
-{
-	if (!wpa_group_s || !wpa_group_s->parent || !ssid)
-		return;
-
-	// For group notifications, need to use the parent iface for callbacks.
-	struct wpa_supplicant *wpa_s = wpa_group_s->parent;
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	uint32_t hidl_freq = wpa_group_s->current_bss
-				 ? wpa_group_s->current_bss->freq
-				 : wpa_group_s->assoc_freq;
-	std::array<uint8_t, 32> hidl_psk;
-	if (ssid->psk_set) {
-		os_memcpy(hidl_psk.data(), ssid->psk, 32);
-	}
-	bool hidl_is_go = (client == 0 ? true : false);
-	bool hidl_is_persistent = (persistent == 1 ? true : false);
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onGroupStarted,
-		std::placeholders::_1, wpa_group_s->ifname, hidl_is_go,
-		std::vector<uint8_t>{ssid->ssid, ssid->ssid + ssid->ssid_len},
-		hidl_freq, hidl_psk, ssid->passphrase, wpa_group_s->go_dev_addr,
-		hidl_is_persistent));
-}
-
-void HidlManager::notifyP2pGroupRemoved(
-    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
-    const char *role)
-{
-	if (!wpa_group_s || !wpa_group_s->parent || !ssid || !role)
-		return;
-
-	// For group notifications, need to use the parent iface for callbacks.
-	struct wpa_supplicant *wpa_s = wpa_group_s->parent;
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	bool hidl_is_go = (std::string(role) == "GO");
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onGroupRemoved,
-		std::placeholders::_1, wpa_group_s->ifname, hidl_is_go));
-}
-
-void HidlManager::notifyP2pInvitationReceived(
-    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
-    const u8 *bssid, int id, int op_freq)
-{
-	if (!wpa_s || !sa || !go_dev_addr || !bssid)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	SupplicantNetworkId hidl_network_id;
-	if (id < 0) {
-		hidl_network_id = UINT32_MAX;
-	}
-	hidl_network_id = id;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onInvitationReceived,
-		std::placeholders::_1, sa, go_dev_addr, bssid, hidl_network_id,
-		op_freq));
-}
-
-void HidlManager::notifyP2pInvitationResult(
-    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
-	if (!wpa_s)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onInvitationResult,
-		std::placeholders::_1, bssid ? bssid : kZeroBssid,
-		static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
-		    status)));
-}
-
-void HidlManager::notifyP2pProvisionDiscovery(
-    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
-    enum p2p_prov_disc_status status, u16 config_methods,
-    unsigned int generated_pin)
-{
-	if (!wpa_s || !dev_addr)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	std::string hidl_generated_pin;
-	if (generated_pin > 0) {
-		hidl_generated_pin =
-		    misc_utils::convertWpsPinToString(generated_pin);
-	}
-	bool hidl_is_request = (request == 1 ? true : false);
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompleted,
-		std::placeholders::_1, dev_addr, hidl_is_request,
-		static_cast<ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode>(
-		    status),
-		config_methods, hidl_generated_pin));
-}
-
-void HidlManager::notifyP2pSdResponse(
-    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
-    const u8 *tlvs, size_t tlvs_len)
-{
-	if (!wpa_s || !sa || !tlvs)
-		return;
-
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantP2pIfaceCallback::onServiceDiscoveryResponse,
-		std::placeholders::_1, sa, update_indic,
-		std::vector<uint8_t>{tlvs, tlvs + tlvs_len}));
-}
-
-void HidlManager::notifyApStaAuthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-	if (!wpa_s || !wpa_s->parent || !sta)
-		return;
-	if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-	callWithEachP2pIfaceCallback(
-	    wpa_s->parent->ifname, std::bind(
-			       &ISupplicantP2pIfaceCallback::onStaAuthorized,
-			       std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
-}
-
-void HidlManager::notifyApStaDeauthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-	if (!wpa_s || !wpa_s->parent || !sta)
-		return;
-	if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
-	    p2p_iface_object_map_.end())
-		return;
-
-	callWithEachP2pIfaceCallback(
-	    wpa_s->parent->ifname, std::bind(
-			       &ISupplicantP2pIfaceCallback::onStaDeauthorized,
-			       std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
-}
-
-void HidlManager::notifyExtRadioWorkStart(
-    struct wpa_supplicant *wpa_s, uint32_t id)
-{
-	if (!wpa_s)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onExtRadioWorkStart,
-		std::placeholders::_1, id));
-}
-
-void HidlManager::notifyExtRadioWorkTimeout(
-    struct wpa_supplicant *wpa_s, uint32_t id)
-{
-	if (!wpa_s)
-		return;
-
-	if (sta_iface_object_map_.find(wpa_s->ifname) ==
-	    sta_iface_object_map_.end())
-		return;
-
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname,
-	    std::bind(
-		&ISupplicantStaIfaceCallback::onExtRadioWorkTimeout,
-		std::placeholders::_1, id));
-}
-
-/**
- * Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
- * ifname.
- *
- * @param ifname Name of the corresponding interface.
- * @param iface_object Hidl reference corresponding to the iface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getP2pIfaceHidlObjectByIfname(
-    const std::string &ifname, android::sp<ISupplicantP2pIface> *iface_object)
-{
-	if (ifname.empty() || !iface_object)
-		return 1;
-
-	auto iface_object_iter = p2p_iface_object_map_.find(ifname);
-	if (iface_object_iter == p2p_iface_object_map_.end())
-		return 1;
-
-	*iface_object = iface_object_iter->second;
-	return 0;
-}
-
-/**
- * Retrieve the |ISupplicantStaIface| hidl object reference using the provided
- * ifname.
- *
- * @param ifname Name of the corresponding interface.
- * @param iface_object Hidl reference corresponding to the iface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getStaIfaceHidlObjectByIfname(
-    const std::string &ifname, android::sp<ISupplicantStaIface> *iface_object)
-{
-	if (ifname.empty() || !iface_object)
-		return 1;
-
-	auto iface_object_iter = sta_iface_object_map_.find(ifname);
-	if (iface_object_iter == sta_iface_object_map_.end())
-		return 1;
-
-	*iface_object = iface_object_iter->second;
-	return 0;
-}
-
-/**
- * Retrieve the |ISupplicantP2pNetwork| hidl object reference using the provided
- * ifname and network_id.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param network_object Hidl reference corresponding to the network.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getP2pNetworkHidlObjectByIfnameAndNetworkId(
-    const std::string &ifname, int network_id,
-    android::sp<ISupplicantP2pNetwork> *network_object)
-{
-	if (ifname.empty() || network_id < 0 || !network_object)
-		return 1;
-
-	// Generate the key to be used to lookup the network.
-	const std::string network_key =
-	    getNetworkObjectMapKey(ifname, network_id);
-
-	auto network_object_iter = p2p_network_object_map_.find(network_key);
-	if (network_object_iter == p2p_network_object_map_.end())
-		return 1;
-
-	*network_object = network_object_iter->second;
-	return 0;
-}
-
-/**
- * Retrieve the |ISupplicantStaNetwork| hidl object reference using the provided
- * ifname and network_id.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param network_object Hidl reference corresponding to the network.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getStaNetworkHidlObjectByIfnameAndNetworkId(
-    const std::string &ifname, int network_id,
-    android::sp<ISupplicantStaNetwork> *network_object)
-{
-	if (ifname.empty() || network_id < 0 || !network_object)
-		return 1;
-
-	// Generate the key to be used to lookup the network.
-	const std::string network_key =
-	    getNetworkObjectMapKey(ifname, network_id);
-
-	auto network_object_iter = sta_network_object_map_.find(network_key);
-	if (network_object_iter == sta_network_object_map_.end())
-		return 1;
-
-	*network_object = network_object_iter->second;
-	return 0;
-}
-
-/**
- * Add a new |ISupplicantCallback| hidl object reference to our
- * global callback list.
- *
- * @param callback Hidl reference of the |ISupplicantCallback| object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addSupplicantCallbackHidlObject(
-    const android::sp<ISupplicantCallback> &callback)
-{
-	// Register for death notification before we add it to our list.
-	auto on_hidl_died_fctor = std::bind(
-	    &HidlManager::removeSupplicantCallbackHidlObject, this,
-	    std::placeholders::_1);
-	return registerForDeathAndAddCallbackHidlObjectToList<
-	    ISupplicantCallback>(
-	    callback, on_hidl_died_fctor, supplicant_callbacks_);
-}
-
-/**
- * Add a new iface callback hidl object reference to our
- * interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addP2pIfaceCallbackHidlObject(
-    const std::string &ifname,
-    const android::sp<ISupplicantP2pIfaceCallback> &callback)
-{
-	const std::function<void(
-	    const android::sp<ISupplicantP2pIfaceCallback> &)>
-	    on_hidl_died_fctor = std::bind(
-		&HidlManager::removeP2pIfaceCallbackHidlObject, this, ifname,
-		std::placeholders::_1);
-	return addIfaceCallbackHidlObjectToMap(
-	    ifname, callback, on_hidl_died_fctor, p2p_iface_callbacks_map_);
-}
-
-/**
- * Add a new iface callback hidl object reference to our
- * interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addStaIfaceCallbackHidlObject(
-    const std::string &ifname,
-    const android::sp<ISupplicantStaIfaceCallback> &callback)
-{
-	const std::function<void(
-	    const android::sp<ISupplicantStaIfaceCallback> &)>
-	    on_hidl_died_fctor = std::bind(
-		&HidlManager::removeStaIfaceCallbackHidlObject, this, ifname,
-		std::placeholders::_1);
-	return addIfaceCallbackHidlObjectToMap(
-	    ifname, callback, on_hidl_died_fctor, sta_iface_callbacks_map_);
-}
-
-/**
- * Add a new network callback hidl object reference to our network callback
- * list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addP2pNetworkCallbackHidlObject(
-    const std::string &ifname, int network_id,
-    const android::sp<ISupplicantP2pNetworkCallback> &callback)
-{
-	const std::function<void(
-	    const android::sp<ISupplicantP2pNetworkCallback> &)>
-	    on_hidl_died_fctor = std::bind(
-		&HidlManager::removeP2pNetworkCallbackHidlObject, this, ifname,
-		network_id, std::placeholders::_1);
-	return addNetworkCallbackHidlObjectToMap(
-	    ifname, network_id, callback, on_hidl_died_fctor,
-	    p2p_network_callbacks_map_);
-}
-
-/**
- * Add a new network callback hidl object reference to our network callback
- * list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addStaNetworkCallbackHidlObject(
-    const std::string &ifname, int network_id,
-    const android::sp<ISupplicantStaNetworkCallback> &callback)
-{
-	const std::function<void(
-	    const android::sp<ISupplicantStaNetworkCallback> &)>
-	    on_hidl_died_fctor = std::bind(
-		&HidlManager::removeStaNetworkCallbackHidlObject, this, ifname,
-		network_id, std::placeholders::_1);
-	return addNetworkCallbackHidlObjectToMap(
-	    ifname, network_id, callback, on_hidl_died_fctor,
-	    sta_network_callbacks_map_);
-}
-
-/**
- * Removes the provided |ISupplicantCallback| hidl object reference
- * from our global callback list.
- *
- * @param callback Hidl reference of the |ISupplicantCallback| object.
- */
-void HidlManager::removeSupplicantCallbackHidlObject(
-    const android::sp<ISupplicantCallback> &callback)
-{
-	supplicant_callbacks_.erase(
-	    std::remove(
-		supplicant_callbacks_.begin(), supplicant_callbacks_.end(),
-		callback),
-	    supplicant_callbacks_.end());
-}
-
-/**
- * Removes the provided iface callback hidl object reference from
- * our interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeP2pIfaceCallbackHidlObject(
-    const std::string &ifname,
-    const android::sp<ISupplicantP2pIfaceCallback> &callback)
-{
-	return removeIfaceCallbackHidlObjectFromMap(
-	    ifname, callback, p2p_iface_callbacks_map_);
-}
-
-/**
- * Removes the provided iface callback hidl object reference from
- * our interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeStaIfaceCallbackHidlObject(
-    const std::string &ifname,
-    const android::sp<ISupplicantStaIfaceCallback> &callback)
-{
-	return removeIfaceCallbackHidlObjectFromMap(
-	    ifname, callback, sta_iface_callbacks_map_);
-}
-
-/**
- * Removes the provided network callback hidl object reference from
- * our network callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeP2pNetworkCallbackHidlObject(
-    const std::string &ifname, int network_id,
-    const android::sp<ISupplicantP2pNetworkCallback> &callback)
-{
-	return removeNetworkCallbackHidlObjectFromMap(
-	    ifname, network_id, callback, p2p_network_callbacks_map_);
-}
-
-/**
- * Removes the provided network callback hidl object reference from
- * our network callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeStaNetworkCallbackHidlObject(
-    const std::string &ifname, int network_id,
-    const android::sp<ISupplicantStaNetworkCallback> &callback)
-{
-	return removeNetworkCallbackHidlObjectFromMap(
-	    ifname, network_id, callback, sta_network_callbacks_map_);
-}
-
-/**
- * Helper function to invoke the provided callback method on all the
- * registered |ISupplicantCallback| callback hidl objects.
- *
- * @param method Pointer to the required hidl method from
- * |ISupplicantCallback|.
- */
-void HidlManager::callWithEachSupplicantCallback(
-    const std::function<Return<void>(android::sp<ISupplicantCallback>)> &method)
-{
-	for (const auto &callback : supplicant_callbacks_) {
-		if (!method(callback).isOk()) {
-			wpa_printf(MSG_ERROR, "Failed to invoke HIDL callback");
-		}
-	}
-}
-
-/**
- * Helper fucntion to invoke the provided callback method on all the
- * registered iface callback hidl objects for the specified
- * |ifname|.
- *
- * @param ifname Name of the corresponding interface.
- * @param method Pointer to the required hidl method from
- * |ISupplicantIfaceCallback|.
- */
-void HidlManager::callWithEachP2pIfaceCallback(
-    const std::string &ifname,
-    const std::function<Return<void>(android::sp<ISupplicantP2pIfaceCallback>)>
-	&method)
-{
-	callWithEachIfaceCallback(ifname, method, p2p_iface_callbacks_map_);
-}
-
-/**
- * Helper fucntion to invoke the provided callback method on all the
- * registered iface callback hidl objects for the specified
- * |ifname|.
- *
- * @param ifname Name of the corresponding interface.
- * @param method Pointer to the required hidl method from
- * |ISupplicantIfaceCallback|.
- */
-void HidlManager::callWithEachStaIfaceCallback(
-    const std::string &ifname,
-    const std::function<Return<void>(android::sp<ISupplicantStaIfaceCallback>)>
-	&method)
-{
-	callWithEachIfaceCallback(ifname, method, sta_iface_callbacks_map_);
-}
-
-/**
- * Helper function to invoke the provided callback method on all the
- * registered network callback hidl objects for the specified
- * |ifname| & |network_id|.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param method Pointer to the required hidl method from
- * |ISupplicantP2pNetworkCallback| or |ISupplicantStaNetworkCallback| .
- */
-void HidlManager::callWithEachP2pNetworkCallback(
-    const std::string &ifname, int network_id,
-    const std::function<
-	Return<void>(android::sp<ISupplicantP2pNetworkCallback>)> &method)
-{
-	callWithEachNetworkCallback(
-	    ifname, network_id, method, p2p_network_callbacks_map_);
-}
-
-/**
- * Helper function to invoke the provided callback method on all the
- * registered network callback hidl objects for the specified
- * |ifname| & |network_id|.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param method Pointer to the required hidl method from
- * |ISupplicantP2pNetworkCallback| or |ISupplicantStaNetworkCallback| .
- */
-void HidlManager::callWithEachStaNetworkCallback(
-    const std::string &ifname, int network_id,
-    const std::function<
-	Return<void>(android::sp<ISupplicantStaNetworkCallback>)> &method)
-{
-	callWithEachNetworkCallback(
-	    ifname, network_id, method, sta_network_callbacks_map_);
-}
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
diff --git a/wpa_supplicant/hidl/1.0/hidl_manager.h b/wpa_supplicant/hidl/1.0/hidl_manager.h
deleted file mode 100644
index 9d9527c..0000000
--- a/wpa_supplicant/hidl/1.0/hidl_manager.h
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
-#define WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
-
-#include <map>
-#include <string>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
-
-#include "p2p_iface.h"
-#include "p2p_network.h"
-#include "sta_iface.h"
-#include "sta_network.h"
-#include "supplicant.h"
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * HidlManager is responsible for managing the lifetime of all
- * hidl objects created by wpa_supplicant. This is a singleton
- * class which is created by the supplicant core and can be used
- * to get references to the hidl objects.
- */
-class HidlManager
-{
-public:
-	static HidlManager *getInstance();
-	static void destroyInstance();
-
-	// Methods called from wpa_supplicant core.
-	int registerHidlService(struct wpa_global *global);
-	int registerInterface(struct wpa_supplicant *wpa_s);
-	int unregisterInterface(struct wpa_supplicant *wpa_s);
-	int registerNetwork(
-	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-	int unregisterNetwork(
-	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-	int notifyStateChange(struct wpa_supplicant *wpa_s);
-	int notifyNetworkRequest(
-	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
-	    const char *param);
-	void notifyAnqpQueryDone(
-	    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
-	    const struct wpa_bss_anqp *anqp);
-	void notifyHs20IconQueryDone(
-	    struct wpa_supplicant *wpa_s, const u8 *bssid,
-	    const char *file_name, const u8 *image, u32 image_length);
-	void notifyHs20RxSubscriptionRemediation(
-	    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
-	void notifyHs20RxDeauthImminentNotice(
-	    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
-	    const char *url);
-	void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
-	void notifyAssocReject(struct wpa_supplicant *wpa_s);
-	void notifyAuthTimeout(struct wpa_supplicant *wpa_s);
-	void notifyBssidChanged(struct wpa_supplicant *wpa_s);
-	void notifyWpsEventFail(
-	    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr,
-	    uint16_t config_error, uint16_t error_indication);
-	void notifyWpsEventSuccess(struct wpa_supplicant *wpa_s);
-	void notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s);
-	void notifyP2pDeviceFound(
-	    struct wpa_supplicant *wpa_s, const u8 *addr,
-	    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
-	    u8 peer_wfd_device_info_len);
-	void notifyP2pDeviceLost(
-	    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
-	void notifyP2pFindStopped(struct wpa_supplicant *wpa_s);
-	void notifyP2pGoNegReq(
-	    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
-	    u8 go_intent);
-	void notifyP2pGoNegCompleted(
-	    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
-	void notifyP2pGroupFormationFailure(
-	    struct wpa_supplicant *wpa_s, const char *reason);
-	void notifyP2pGroupStarted(
-	    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
-	    int persistent, int client);
-	void notifyP2pGroupRemoved(
-	    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
-	    const char *role);
-	void notifyP2pInvitationReceived(
-	    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
-	    const u8 *bssid, int id, int op_freq);
-	void notifyP2pInvitationResult(
-	    struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
-	void notifyP2pProvisionDiscovery(
-	    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
-	    enum p2p_prov_disc_status status, u16 config_methods,
-	    unsigned int generated_pin);
-	void notifyP2pSdResponse(
-	    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
-	    const u8 *tlvs, size_t tlvs_len);
-	void notifyApStaAuthorized(
-	    struct wpa_supplicant *wpa_s, const u8 *sta,
-	    const u8 *p2p_dev_addr);
-	void notifyApStaDeauthorized(
-	    struct wpa_supplicant *wpa_s, const u8 *sta,
-	    const u8 *p2p_dev_addr);
-
-	// Methods called from hidl objects.
-	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
-	void notifyExtRadioWorkTimeout(
-	    struct wpa_supplicant *wpa_s, uint32_t id);
-
-	int getP2pIfaceHidlObjectByIfname(
-	    const std::string &ifname,
-	    android::sp<ISupplicantP2pIface> *iface_object);
-	int getStaIfaceHidlObjectByIfname(
-	    const std::string &ifname,
-	    android::sp<ISupplicantStaIface> *iface_object);
-	int getP2pNetworkHidlObjectByIfnameAndNetworkId(
-	    const std::string &ifname, int network_id,
-	    android::sp<ISupplicantP2pNetwork> *network_object);
-	int getStaNetworkHidlObjectByIfnameAndNetworkId(
-	    const std::string &ifname, int network_id,
-	    android::sp<ISupplicantStaNetwork> *network_object);
-	int addSupplicantCallbackHidlObject(
-	    const android::sp<ISupplicantCallback> &callback);
-	int addP2pIfaceCallbackHidlObject(
-	    const std::string &ifname,
-	    const android::sp<ISupplicantP2pIfaceCallback> &callback);
-	int addStaIfaceCallbackHidlObject(
-	    const std::string &ifname,
-	    const android::sp<ISupplicantStaIfaceCallback> &callback);
-	int addP2pNetworkCallbackHidlObject(
-	    const std::string &ifname, int network_id,
-	    const android::sp<ISupplicantP2pNetworkCallback> &callback);
-	int addStaNetworkCallbackHidlObject(
-	    const std::string &ifname, int network_id,
-	    const android::sp<ISupplicantStaNetworkCallback> &callback);
-
-private:
-	HidlManager() = default;
-	~HidlManager() = default;
-	HidlManager(const HidlManager &) = default;
-	HidlManager &operator=(const HidlManager &) = default;
-
-	void removeSupplicantCallbackHidlObject(
-	    const android::sp<ISupplicantCallback> &callback);
-	void removeP2pIfaceCallbackHidlObject(
-	    const std::string &ifname,
-	    const android::sp<ISupplicantP2pIfaceCallback> &callback);
-	void removeStaIfaceCallbackHidlObject(
-	    const std::string &ifname,
-	    const android::sp<ISupplicantStaIfaceCallback> &callback);
-	void removeP2pNetworkCallbackHidlObject(
-	    const std::string &ifname, int network_id,
-	    const android::sp<ISupplicantP2pNetworkCallback> &callback);
-	void removeStaNetworkCallbackHidlObject(
-	    const std::string &ifname, int network_id,
-	    const android::sp<ISupplicantStaNetworkCallback> &callback);
-
-	void callWithEachSupplicantCallback(
-	    const std::function<android::hardware::Return<void>(
-		android::sp<ISupplicantCallback>)> &method);
-	void callWithEachP2pIfaceCallback(
-	    const std::string &ifname,
-	    const std::function<android::hardware::Return<void>(
-		android::sp<ISupplicantP2pIfaceCallback>)> &method);
-	void callWithEachStaIfaceCallback(
-	    const std::string &ifname,
-	    const std::function<android::hardware::Return<void>(
-		android::sp<ISupplicantStaIfaceCallback>)> &method);
-	void callWithEachP2pNetworkCallback(
-	    const std::string &ifname, int network_id,
-	    const std::function<android::hardware::Return<void>(
-		android::sp<ISupplicantP2pNetworkCallback>)> &method);
-	void callWithEachStaNetworkCallback(
-	    const std::string &ifname, int network_id,
-	    const std::function<android::hardware::Return<void>(
-		android::sp<ISupplicantStaNetworkCallback>)> &method);
-
-	// Singleton instance of this class.
-	static HidlManager *instance_;
-	// The main hidl service object.
-	android::sp<Supplicant> supplicant_object_;
-	// Map of all the P2P interface specific hidl objects controlled by
-	// wpa_supplicant. This map is keyed in by the corresponding
-	// |ifname|.
-	std::map<const std::string, android::sp<P2pIface>>
-	    p2p_iface_object_map_;
-	// Map of all the STA interface specific hidl objects controlled by
-	// wpa_supplicant. This map is keyed in by the corresponding
-	// |ifname|.
-	std::map<const std::string, android::sp<StaIface>>
-	    sta_iface_object_map_;
-	// Map of all the P2P network specific hidl objects controlled by
-	// wpa_supplicant. This map is keyed in by the corresponding
-	// |ifname| & |network_id|.
-	std::map<const std::string, android::sp<P2pNetwork>>
-	    p2p_network_object_map_;
-	// Map of all the STA network specific hidl objects controlled by
-	// wpa_supplicant. This map is keyed in by the corresponding
-	// |ifname| & |network_id|.
-	std::map<const std::string, android::sp<StaNetwork>>
-	    sta_network_object_map_;
-
-	// Callback registered for the main hidl service object.
-	std::vector<android::sp<ISupplicantCallback>> supplicant_callbacks_;
-	// Map of all the callbacks registered for P2P interface specific
-	// hidl objects controlled by wpa_supplicant.  This map is keyed in by
-	// the corresponding |ifname|.
-	std::map<
-	    const std::string,
-	    std::vector<android::sp<ISupplicantP2pIfaceCallback>>>
-	    p2p_iface_callbacks_map_;
-	// Map of all the callbacks registered for STA interface specific
-	// hidl objects controlled by wpa_supplicant.  This map is keyed in by
-	// the corresponding |ifname|.
-	std::map<
-	    const std::string,
-	    std::vector<android::sp<ISupplicantStaIfaceCallback>>>
-	    sta_iface_callbacks_map_;
-	// Map of all the callbacks registered for P2P network specific
-	// hidl objects controlled by wpa_supplicant.  This map is keyed in by
-	// the corresponding |ifname| & |network_id|.
-	std::map<
-	    const std::string,
-	    std::vector<android::sp<ISupplicantP2pNetworkCallback>>>
-	    p2p_network_callbacks_map_;
-	// Map of all the callbacks registered for STA network specific
-	// hidl objects controlled by wpa_supplicant.  This map is keyed in by
-	// the corresponding |ifname| & |network_id|.
-	std::map<
-	    const std::string,
-	    std::vector<android::sp<ISupplicantStaNetworkCallback>>>
-	    sta_network_callbacks_map_;
-
-#if 0  // TODO(b/31632518): HIDL object death notifications.
-	/**
-	 * Helper class used to deregister the callback object reference from
-	 * our callback list on the death of the hidl object.
-	 * This class stores a reference of the callback hidl object and a
-	 * function to be called to indicate the death of the hidl object.
-	 */
-	template <class CallbackType>
-	class CallbackObjectDeathNotifier
-	    : public android::hardware::IBinder::DeathRecipient
-	{
-	public:
-		CallbackObjectDeathNotifier(
-		    const android::sp<CallbackType> &callback,
-		    const std::function<void(const android::sp<CallbackType> &)>
-			&on_hidl_died)
-		    : callback_(callback), on_hidl_died_(on_hidl_died)
-		{
-		}
-		void binderDied(const android::wp<android::hardware::IBinder>
-				    & /* who */) override
-		{
-			on_hidl_died_(callback_);
-		}
-
-	private:
-		// The callback hidl object reference.
-		const android::sp<CallbackType> callback_;
-		// Callback function to be called when the hidl dies.
-		const std::function<void(const android::sp<CallbackType> &)>
-		    on_hidl_died_;
-	};
-#endif
-};
-
-// The hidl interface uses some values which are the same as internal ones to
-// avoid nasty runtime conversion functions. So, adding compile time asserts
-// to guard against any internal changes breaking the hidl interface.
-static_assert(
-    static_cast<uint32_t>(ISupplicant::DebugLevel::EXCESSIVE) == MSG_EXCESSIVE,
-    "Debug level value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicant::DebugLevel::ERROR) == MSG_ERROR,
-    "Debug level value mismatch");
-
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) ==
-	WPA_KEY_MGMT_NONE,
-    "KeyMgmt value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) ==
-	WPA_KEY_MGMT_PSK,
-    "KeyMgmt value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) ==
-	WPA_KEY_MGMT_IEEE8021X,
-    "KeyMgmt value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) ==
-	WPA_KEY_MGMT_IEEE8021X_NO_WPA,
-    "KeyMgmt value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) ==
-	WPA_KEY_MGMT_FT_IEEE8021X,
-    "KeyMgmt value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) ==
-	WPA_KEY_MGMT_FT_PSK,
-    "KeyMgmt value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN) ==
-	WPA_KEY_MGMT_OSEN,
-    "KeyMgmt value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
-	WPA_PROTO_WPA,
-    "Proto value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) ==
-	WPA_PROTO_RSN,
-    "Proto value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN) ==
-	WPA_PROTO_OSEN,
-    "Proto value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
-	WPA_AUTH_ALG_OPEN,
-    "AuthAlg value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) ==
-	WPA_AUTH_ALG_SHARED,
-    "AuthAlg value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP) ==
-	WPA_AUTH_ALG_LEAP,
-    "AuthAlg value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) ==
-	WPA_CIPHER_WEP40,
-    "GroupCipher value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) ==
-	WPA_CIPHER_WEP104,
-    "GroupCipher value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) ==
-	WPA_CIPHER_TKIP,
-    "GroupCipher value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) ==
-	WPA_CIPHER_CCMP,
-    "GroupCipher value mismatch");
-static_assert(
-    static_cast<uint32_t>(
-	ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
-	WPA_CIPHER_GTK_NOT_USED,
-    "GroupCipher value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) ==
-	WPA_CIPHER_NONE,
-    "PairwiseCipher value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) ==
-	WPA_CIPHER_TKIP,
-    "PairwiseCipher value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
-	WPA_CIPHER_CCMP,
-    "PairwiseCipher value mismatch");
-
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::DISCONNECTED) ==
-	WPA_DISCONNECTED,
-    "State value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::COMPLETED) ==
-	WPA_COMPLETED,
-    "State value mismatch");
-
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::VENUE_NAME) ==
-	ANQP_VENUE_NAME,
-    "ANQP ID value mismatch");
-static_assert(
-    static_cast<uint32_t>(
-	ISupplicantStaIface::AnqpInfoId::ROAMING_CONSORTIUM) ==
-	ANQP_ROAMING_CONSORTIUM,
-    "ANQP ID value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::NAI_REALM) ==
-	ANQP_NAI_REALM,
-    "ANQP ID value mismatch");
-static_assert(
-    static_cast<uint32_t>(
-	ISupplicantStaIface::AnqpInfoId::IP_ADDR_TYPE_AVAILABILITY) ==
-	ANQP_IP_ADDR_TYPE_AVAILABILITY,
-    "ANQP ID value mismatch");
-static_assert(
-    static_cast<uint32_t>(
-	ISupplicantStaIface::AnqpInfoId::ANQP_3GPP_CELLULAR_NETWORK) ==
-	ANQP_3GPP_CELLULAR_NETWORK,
-    "ANQP ID value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::DOMAIN_NAME) ==
-	ANQP_DOMAIN_NAME,
-    "ANQP ID value mismatch");
-static_assert(
-    static_cast<uint32_t>(
-	ISupplicantStaIface::Hs20AnqpSubtypes::OPERATOR_FRIENDLY_NAME) ==
-	HS20_STYPE_OPERATOR_FRIENDLY_NAME,
-    "HS Subtype value mismatch");
-static_assert(
-    static_cast<uint32_t>(ISupplicantStaIface::Hs20AnqpSubtypes::WAN_METRICS) ==
-	HS20_STYPE_WAN_METRICS,
-    "HS Subtype value mismatch");
-static_assert(
-    static_cast<uint32_t>(
-	ISupplicantStaIface::Hs20AnqpSubtypes::CONNECTION_CAPABILITY) ==
-	HS20_STYPE_CONNECTION_CAPABILITY,
-    "HS Subtype value mismatch");
-static_assert(
-    static_cast<uint32_t>(
-	ISupplicantStaIface::Hs20AnqpSubtypes::OSU_PROVIDERS_LIST) ==
-	HS20_STYPE_OSU_PROVIDERS_LIST,
-    "HS Subtype value mismatch");
-
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantStaIfaceCallback::WpsConfigError::NO_ERROR) ==
-	WPS_CFG_NO_ERROR,
-    "Wps config error value mismatch");
-static_assert(
-    static_cast<uint16_t>(ISupplicantStaIfaceCallback::WpsConfigError::
-			      PUBLIC_KEY_HASH_MISMATCH) ==
-	WPS_CFG_PUBLIC_KEY_HASH_MISMATCH,
-    "Wps config error value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantStaIfaceCallback::WpsErrorIndication::NO_ERROR) ==
-	WPS_EI_NO_ERROR,
-    "Wps error indication value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantStaIfaceCallback::WpsErrorIndication::AUTH_FAILURE) ==
-	WPS_EI_AUTH_FAILURE,
-    "Wps error indication value mismatch");
-
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::USBA) == WPS_CONFIG_USBA,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::ETHERNET) == WPS_CONFIG_ETHERNET,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::LABEL) == WPS_CONFIG_LABEL,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::DISPLAY) == WPS_CONFIG_DISPLAY,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::INT_NFC_TOKEN) ==
-	WPS_CONFIG_INT_NFC_TOKEN,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::EXT_NFC_TOKEN) ==
-	WPS_CONFIG_EXT_NFC_TOKEN,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::NFC_INTERFACE) ==
-	WPS_CONFIG_NFC_INTERFACE,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::PUSHBUTTON) ==
-	WPS_CONFIG_PUSHBUTTON,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::KEYPAD) == WPS_CONFIG_KEYPAD,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::VIRT_PUSHBUTTON) ==
-	WPS_CONFIG_VIRT_PUSHBUTTON,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::PHY_PUSHBUTTON) ==
-	WPS_CONFIG_PHY_PUSHBUTTON,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::P2PS) == WPS_CONFIG_P2PS,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::VIRT_DISPLAY) ==
-	WPS_CONFIG_VIRT_DISPLAY,
-    "Wps config value mismatch");
-static_assert(
-    static_cast<uint32_t>(WpsConfigMethods::PHY_DISPLAY) ==
-	WPS_CONFIG_PHY_DISPLAY,
-    "Wps config value mismatch");
-
-static_assert(
-    static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_OWNER) ==
-	P2P_GROUP_CAPAB_GROUP_OWNER,
-    "P2P capability value mismatch");
-static_assert(
-    static_cast<uint32_t>(P2pGroupCapabilityMask::PERSISTENT_GROUP) ==
-	P2P_GROUP_CAPAB_PERSISTENT_GROUP,
-    "P2P capability value mismatch");
-static_assert(
-    static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_LIMIT) ==
-	P2P_GROUP_CAPAB_GROUP_LIMIT,
-    "P2P capability value mismatch");
-static_assert(
-    static_cast<uint32_t>(P2pGroupCapabilityMask::INTRA_BSS_DIST) ==
-	P2P_GROUP_CAPAB_INTRA_BSS_DIST,
-    "P2P capability value mismatch");
-static_assert(
-    static_cast<uint32_t>(P2pGroupCapabilityMask::CROSS_CONN) ==
-	P2P_GROUP_CAPAB_CROSS_CONN,
-    "P2P capability value mismatch");
-static_assert(
-    static_cast<uint32_t>(P2pGroupCapabilityMask::PERSISTENT_RECONN) ==
-	P2P_GROUP_CAPAB_PERSISTENT_RECONN,
-    "P2P capability value mismatch");
-static_assert(
-    static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_FORMATION) ==
-	P2P_GROUP_CAPAB_GROUP_FORMATION,
-    "P2P capability value mismatch");
-
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::WpsDevPasswordId::DEFAULT) ==
-	DEV_PW_DEFAULT,
-    "Wps dev password id value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::WpsDevPasswordId::USER_SPECIFIED) ==
-	DEV_PW_USER_SPECIFIED,
-    "Wps dev password id value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::WpsDevPasswordId::MACHINE_SPECIFIED) ==
-	DEV_PW_MACHINE_SPECIFIED,
-    "Wps dev password id value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::WpsDevPasswordId::REKEY) == DEV_PW_REKEY,
-    "Wps dev password id value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::WpsDevPasswordId::PUSHBUTTON) ==
-	DEV_PW_PUSHBUTTON,
-    "Wps dev password id value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::WpsDevPasswordId::REGISTRAR_SPECIFIED) ==
-	DEV_PW_REGISTRAR_SPECIFIED,
-    "Wps dev password id value mismatch");
-static_assert(
-    static_cast<uint16_t>(ISupplicantP2pIfaceCallback::WpsDevPasswordId::
-			      NFC_CONNECTION_HANDOVER) ==
-	DEV_PW_NFC_CONNECTION_HANDOVER,
-    "Wps dev password id value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::WpsDevPasswordId::P2PS_DEFAULT) ==
-	DEV_PW_P2PS_DEFAULT,
-    "Wps dev password id value mismatch");
-
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::SUCCESS) == P2P_SC_SUCCESS,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
-			      FAIL_INFO_CURRENTLY_UNAVAILABLE) ==
-	P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_INCOMPATIBLE_PARAMS) ==
-	P2P_SC_FAIL_INCOMPATIBLE_PARAMS,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_LIMIT_REACHED) ==
-	P2P_SC_FAIL_LIMIT_REACHED,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_INVALID_PARAMS) ==
-	P2P_SC_FAIL_INVALID_PARAMS,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
-			      FAIL_UNABLE_TO_ACCOMMODATE) ==
-	P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_PREV_PROTOCOL_ERROR) ==
-	P2P_SC_FAIL_PREV_PROTOCOL_ERROR,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_NO_COMMON_CHANNELS) ==
-	P2P_SC_FAIL_NO_COMMON_CHANNELS,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_UNKNOWN_GROUP) ==
-	P2P_SC_FAIL_UNKNOWN_GROUP,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_BOTH_GO_INTENT_15) ==
-	P2P_SC_FAIL_BOTH_GO_INTENT_15,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
-			      FAIL_INCOMPATIBLE_PROV_METHOD) ==
-	P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_REJECTED_BY_USER) ==
-	P2P_SC_FAIL_REJECTED_BY_USER,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pStatusCode::SUCCESS_DEFERRED) ==
-	P2P_SC_SUCCESS_DEFERRED,
-    "P2P status code value mismatch");
-
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::SUCCESS) ==
-	P2P_PROV_DISC_SUCCESS,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::TIMEOUT) ==
-	P2P_PROV_DISC_TIMEOUT,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::REJECTED) ==
-	P2P_PROV_DISC_REJECTED,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::TIMEOUT_JOIN) ==
-	P2P_PROV_DISC_TIMEOUT_JOIN,
-    "P2P status code value mismatch");
-static_assert(
-    static_cast<uint16_t>(
-	ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::INFO_UNAVAILABLE) ==
-	P2P_PROV_DISC_INFO_UNAVAILABLE,
-    "P2P status code value mismatch");
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
-#endif  // WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_return_util.h b/wpa_supplicant/hidl/1.0/hidl_return_util.h
deleted file mode 100644
index c077fc8..0000000
--- a/wpa_supplicant/hidl/1.0/hidl_return_util.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef HIDL_RETURN_UTIL_H_
-#define HIDL_RETURN_UTIL_H_
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-namespace hidl_return_util {
-
-/**
- * These utility functions are used to invoke a method on the provided
- * HIDL interface object.
- * These functions checks if the provided HIDL interface object is valid.
- * a) if valid, Invokes the corresponding internal implementation function of
- * the HIDL method. It then invokes the HIDL continuation callback with
- * the status and any returned values.
- * b) if invalid, invokes the HIDL continuation callback with the
- * provided error status and default values.
- */
-// Use for HIDL methods which return only an instance of SupplicantStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const SupplicantStatus&)>& hidl_cb, Args&&... args)
-{
-	if (obj->isValid()) {
-		hidl_cb((obj->*work)(std::forward<Args>(args)...));
-	} else {
-		hidl_cb({status_code_if_invalid, ""});
-	}
-	return Void();
-}
-
-// Use for HIDL methods which return instance of SupplicantStatus and a single
-// return value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const SupplicantStatus&, ReturnT)>& hidl_cb,
-    Args&&... args)
-{
-	if (obj->isValid()) {
-		const auto& ret_pair =
-		    (obj->*work)(std::forward<Args>(args)...);
-		const SupplicantStatus& status = std::get<0>(ret_pair);
-		const auto& ret_value = std::get<1>(ret_pair);
-		hidl_cb(status, ret_value);
-	} else {
-		hidl_cb(
-		    {status_code_if_invalid, ""},
-		    typename std::remove_reference<ReturnT>::type());
-	}
-	return Void();
-}
-
-// Use for HIDL methods which return instance of SupplicantStatus and 2 return
-// values.
-template <
-    typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2,
-    typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const SupplicantStatus&, ReturnT1, ReturnT2)>&
-	hidl_cb,
-    Args&&... args)
-{
-	if (obj->isValid()) {
-		const auto& ret_tuple =
-		    (obj->*work)(std::forward<Args>(args)...);
-		const SupplicantStatus& status = std::get<0>(ret_tuple);
-		const auto& ret_value1 = std::get<1>(ret_tuple);
-		const auto& ret_value2 = std::get<2>(ret_tuple);
-		hidl_cb(status, ret_value1, ret_value2);
-	} else {
-		hidl_cb(
-		    {status_code_if_invalid, ""},
-		    typename std::remove_reference<ReturnT1>::type(),
-		    typename std::remove_reference<ReturnT2>::type());
-	}
-	return Void();
-}
-
-}  // namespace hidl_util
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace supplicant
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wpa_supplicant/hidl/1.0/misc_utils.h b/wpa_supplicant/hidl/1.0/misc_utils.h
deleted file mode 100644
index 354ec32..0000000
--- a/wpa_supplicant/hidl/1.0/misc_utils.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef MISC_UTILS_H_
-#define MISC_UTILS_H_
-
-extern "C" {
-#include "wpabuf.h"
-}
-
-namespace {
-constexpr size_t kWpsPinNumDigits = 8;
-// Custom deleter for wpabuf.
-void freeWpaBuf(wpabuf *ptr) { wpabuf_free(ptr); }
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-namespace misc_utils {
-using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
-
-// Creates a unique_ptr for wpabuf ptr with a custom deleter.
-inline wpabuf_unique_ptr createWpaBufUniquePtr(struct wpabuf *raw_ptr)
-{
-	return {raw_ptr, freeWpaBuf};
-}
-
-// Creates a wpabuf ptr with a custom deleter copying the data from the provided
-// vector.
-inline wpabuf_unique_ptr convertVectorToWpaBuf(const std::vector<uint8_t> &data)
-{
-	return createWpaBufUniquePtr(
-	    wpabuf_alloc_copy(data.data(), data.size()));
-}
-
-// Copies the provided wpabuf contents to a std::vector.
-inline std::vector<uint8_t> convertWpaBufToVector(const struct wpabuf *buf)
-{
-	if (buf) {
-		return std::vector<uint8_t>(
-		    wpabuf_head_u8(buf), wpabuf_head_u8(buf) + wpabuf_len(buf));
-	} else {
-		return std::vector<uint8_t>();
-	}
-}
-
-// Returns a string holding the wps pin.
-inline std::string convertWpsPinToString(int pin)
-{
-	char pin_str[kWpsPinNumDigits + 1];
-	snprintf(pin_str, sizeof(pin_str), "%08d", pin);
-	return pin_str;
-}
-
-}  // namespace misc_utils
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace supplicant
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // MISC_UTILS_H_
diff --git a/wpa_supplicant/hidl/1.0/p2p_iface.h b/wpa_supplicant/hidl/1.0/p2p_iface.h
deleted file mode 100644
index 4f4a79d..0000000
--- a/wpa_supplicant/hidl/1.0/p2p_iface.h
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_P2P_IFACE_H
-#define WPA_SUPPLICANT_HIDL_P2P_IFACE_H
-
-#include <array>
-#include <vector>
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "p2p/p2p.h"
-#include "p2p/p2p_i.h"
-#include "p2p_supplicant.h"
-#include "p2p_supplicant.h"
-#include "config.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * Implementation of P2pIface hidl object. Each unique hidl
- * object is used for control operations on a specific interface
- * controlled by wpa_supplicant.
- */
-class P2pIface
-    : public android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface
-{
-public:
-	P2pIface(struct wpa_global* wpa_global, const char ifname[]);
-	~P2pIface() override = default;
-	// Refer to |StaIface::invalidate()|.
-	void invalidate();
-	bool isValid();
-
-	// Hidl methods exposed.
-	Return<void> getName(getName_cb _hidl_cb) override;
-	Return<void> getType(getType_cb _hidl_cb) override;
-	Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
-	Return<void> removeNetwork(
-	    SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
-	Return<void> getNetwork(
-	    SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
-	Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
-	Return<void> registerCallback(
-	    const sp<ISupplicantP2pIfaceCallback>& callback,
-	    registerCallback_cb _hidl_cb) override;
-	Return<void> getDeviceAddress(getDeviceAddress_cb _hidl_cb) override;
-	Return<void> setSsidPostfix(
-	    const hidl_vec<uint8_t>& postfix,
-	    setSsidPostfix_cb _hidl_cb) override;
-	Return<void> setGroupIdle(
-	    const hidl_string& group_ifname, uint32_t timeout_in_sec,
-	    setGroupIdle_cb _hidl_cb) override;
-	Return<void> setPowerSave(
-	    const hidl_string& group_ifname, bool enable,
-	    setPowerSave_cb _hidl_cb) override;
-	Return<void> find(uint32_t timeout_in_sec, find_cb _hidl_cb) override;
-	Return<void> stopFind(stopFind_cb _hidl_cb) override;
-	Return<void> flush(flush_cb _hidl_cb) override;
-	Return<void> connect(
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    ISupplicantP2pIface::WpsProvisionMethod provision_method,
-	    const hidl_string& pre_selected_pin, bool join_existing_group,
-	    bool persistent, uint32_t go_intent, connect_cb _hidl_cb) override;
-	Return<void> cancelConnect(cancelConnect_cb _hidl_cb) override;
-	Return<void> provisionDiscovery(
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    ISupplicantP2pIface::WpsProvisionMethod provision_method,
-	    provisionDiscovery_cb _hidl_cb) override;
-	Return<void> addGroup(
-	    bool persistent, SupplicantNetworkId persistent_network_id,
-	    addGroup_cb _hidl_cb) override;
-	Return<void> removeGroup(
-	    const hidl_string& group_ifname, removeGroup_cb _hidl_cb) override;
-	Return<void> reject(
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    reject_cb _hidl_cb) override;
-	Return<void> invite(
-	    const hidl_string& group_ifname,
-	    const hidl_array<uint8_t, 6>& go_device_address,
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    invite_cb _hidl_cb) override;
-	Return<void> reinvoke(
-	    SupplicantNetworkId persistent_network_id,
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    reinvoke_cb _hidl_cb) override;
-	Return<void> configureExtListen(
-	    uint32_t period_in_millis, uint32_t interval_in_millis,
-	    configureExtListen_cb _hidl_cb) override;
-	Return<void> setListenChannel(
-	    uint32_t channel, uint32_t operating_class,
-	    setListenChannel_cb _hidl_cb) override;
-	Return<void> setDisallowedFrequencies(
-	    const hidl_vec<FreqRange>& ranges,
-	    setDisallowedFrequencies_cb _hidl_cb) override;
-	Return<void> getSsid(
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    getSsid_cb _hidl_cb) override;
-	Return<void> getGroupCapability(
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    getGroupCapability_cb _hidl_cb) override;
-	Return<void> addBonjourService(
-	    const hidl_vec<uint8_t>& query, const hidl_vec<uint8_t>& response,
-	    addBonjourService_cb _hidl_cb) override;
-	Return<void> removeBonjourService(
-	    const hidl_vec<uint8_t>& query,
-	    removeBonjourService_cb _hidl_cb) override;
-	Return<void> addUpnpService(
-	    uint32_t version, const hidl_string& service_name,
-	    addUpnpService_cb _hidl_cb) override;
-	Return<void> removeUpnpService(
-	    uint32_t version, const hidl_string& service_name,
-	    removeUpnpService_cb _hidl_cb) override;
-	Return<void> flushServices(flushServices_cb _hidl_cb) override;
-	Return<void> requestServiceDiscovery(
-	    const hidl_array<uint8_t, 6>& peer_address,
-	    const hidl_vec<uint8_t>& query,
-	    requestServiceDiscovery_cb _hidl_cb) override;
-	Return<void> cancelServiceDiscovery(
-	    uint64_t identifier, cancelServiceDiscovery_cb _hidl_cb) override;
-	Return<void> setMiracastMode(
-	    ISupplicantP2pIface::MiracastMode mode,
-	    setMiracastMode_cb _hidl_cb) override;
-	Return<void> startWpsPbc(
-	    const hidl_string& groupIfName, const hidl_array<uint8_t, 6>& bssid,
-	    startWpsPbc_cb _hidl_cb) override;
-	Return<void> startWpsPinKeypad(
-	    const hidl_string& groupIfName, const hidl_string& pin,
-	    startWpsPinKeypad_cb _hidl_cb) override;
-	Return<void> startWpsPinDisplay(
-	    const hidl_string& groupIfName, const hidl_array<uint8_t, 6>& bssid,
-	    startWpsPinDisplay_cb _hidl_cb) override;
-	Return<void> cancelWps(
-	    const hidl_string& groupIfName, cancelWps_cb _hidl_cb) override;
-	Return<void> setWpsDeviceName(
-	    const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
-	Return<void> setWpsDeviceType(
-	    const hidl_array<uint8_t, 8>& type,
-	    setWpsDeviceType_cb _hidl_cb) override;
-	Return<void> setWpsManufacturer(
-	    const hidl_string& manufacturer,
-	    setWpsManufacturer_cb _hidl_cb) override;
-	Return<void> setWpsModelName(
-	    const hidl_string& model_name,
-	    setWpsModelName_cb _hidl_cb) override;
-	Return<void> setWpsModelNumber(
-	    const hidl_string& model_number,
-	    setWpsModelNumber_cb _hidl_cb) override;
-	Return<void> setWpsSerialNumber(
-	    const hidl_string& serial_number,
-	    setWpsSerialNumber_cb _hidl_cb) override;
-	Return<void> setWpsConfigMethods(
-	    uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb) override;
-	Return<void> enableWfd(bool enable, enableWfd_cb _hidl_cb) override;
-	Return<void> setWfdDeviceInfo(
-	    const hidl_array<uint8_t, 6>& info,
-	    setWfdDeviceInfo_cb _hidl_cb) override;
-	Return<void> createNfcHandoverRequestMessage(
-	    createNfcHandoverRequestMessage_cb _hidl_cb) override;
-	Return<void> createNfcHandoverSelectMessage(
-	    createNfcHandoverSelectMessage_cb _hidl_cb) override;
-	Return<void> reportNfcHandoverResponse(
-	    const hidl_vec<uint8_t>& request,
-	    reportNfcHandoverResponse_cb _hidl_cb) override;
-	Return<void> reportNfcHandoverInitiation(
-	    const hidl_vec<uint8_t>& select,
-	    reportNfcHandoverInitiation_cb _hidl_cb) override;
-	Return<void> saveConfig(saveConfig_cb _hidl_cb) override;
-
-private:
-	// Corresponding worker functions for the HIDL methods.
-	std::pair<SupplicantStatus, std::string> getNameInternal();
-	std::pair<SupplicantStatus, IfaceType> getTypeInternal();
-	std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
-	addNetworkInternal();
-	SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
-	std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
-	getNetworkInternal(SupplicantNetworkId id);
-	std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
-	listNetworksInternal();
-	SupplicantStatus registerCallbackInternal(
-	    const sp<ISupplicantP2pIfaceCallback>& callback);
-	std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-	getDeviceAddressInternal();
-	SupplicantStatus setSsidPostfixInternal(
-	    const std::vector<uint8_t>& postfix);
-	SupplicantStatus setGroupIdleInternal(
-	    const std::string& group_ifname, uint32_t timeout_in_sec);
-	SupplicantStatus setPowerSaveInternal(
-	    const std::string& group_ifname, bool enable);
-	SupplicantStatus findInternal(uint32_t timeout_in_sec);
-	SupplicantStatus stopFindInternal();
-	SupplicantStatus flushInternal();
-	std::pair<SupplicantStatus, std::string> connectInternal(
-	    const std::array<uint8_t, 6>& peer_address,
-	    ISupplicantP2pIface::WpsProvisionMethod provision_method,
-	    const std::string& pre_selected_pin, bool join_existing_group,
-	    bool persistent, uint32_t go_intent);
-	SupplicantStatus cancelConnectInternal();
-	SupplicantStatus provisionDiscoveryInternal(
-	    const std::array<uint8_t, 6>& peer_address,
-	    ISupplicantP2pIface::WpsProvisionMethod provision_method);
-	SupplicantStatus addGroupInternal(
-	    bool persistent, SupplicantNetworkId persistent_network_id);
-	SupplicantStatus removeGroupInternal(const std::string& group_ifname);
-	SupplicantStatus rejectInternal(
-	    const std::array<uint8_t, 6>& peer_address);
-	SupplicantStatus inviteInternal(
-	    const std::string& group_ifname,
-	    const std::array<uint8_t, 6>& go_device_address,
-	    const std::array<uint8_t, 6>& peer_address);
-	SupplicantStatus reinvokeInternal(
-	    SupplicantNetworkId persistent_network_id,
-	    const std::array<uint8_t, 6>& peer_address);
-	SupplicantStatus configureExtListenInternal(
-	    uint32_t period_in_millis, uint32_t interval_in_millis);
-	SupplicantStatus setListenChannelInternal(
-	    uint32_t channel, uint32_t operating_class);
-	SupplicantStatus setDisallowedFrequenciesInternal(
-	    const std::vector<FreqRange>& ranges);
-	std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal(
-	    const std::array<uint8_t, 6>& peer_address);
-	std::pair<SupplicantStatus, uint32_t> getGroupCapabilityInternal(
-	    const std::array<uint8_t, 6>& peer_address);
-	SupplicantStatus addBonjourServiceInternal(
-	    const std::vector<uint8_t>& query,
-	    const std::vector<uint8_t>& response);
-	SupplicantStatus removeBonjourServiceInternal(
-	    const std::vector<uint8_t>& query);
-	SupplicantStatus addUpnpServiceInternal(
-	    uint32_t version, const std::string& service_name);
-	SupplicantStatus removeUpnpServiceInternal(
-	    uint32_t version, const std::string& service_name);
-	SupplicantStatus flushServicesInternal();
-	std::pair<SupplicantStatus, uint64_t> requestServiceDiscoveryInternal(
-	    const std::array<uint8_t, 6>& peer_address,
-	    const std::vector<uint8_t>& query);
-	SupplicantStatus cancelServiceDiscoveryInternal(uint64_t identifier);
-	SupplicantStatus setMiracastModeInternal(
-	    ISupplicantP2pIface::MiracastMode mode);
-	SupplicantStatus startWpsPbcInternal(
-	    const std::string& group_ifname,
-	    const std::array<uint8_t, 6>& bssid);
-	SupplicantStatus startWpsPinKeypadInternal(
-	    const std::string& group_ifname, const std::string& pin);
-	std::pair<SupplicantStatus, std::string> startWpsPinDisplayInternal(
-	    const std::string& group_ifname,
-	    const std::array<uint8_t, 6>& bssid);
-	SupplicantStatus cancelWpsInternal(const std::string& group_ifname);
-	SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
-	SupplicantStatus setWpsDeviceTypeInternal(
-	    const std::array<uint8_t, 8>& type);
-	SupplicantStatus setWpsManufacturerInternal(
-	    const std::string& manufacturer);
-	SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
-	SupplicantStatus setWpsModelNumberInternal(
-	    const std::string& model_number);
-	SupplicantStatus setWpsSerialNumberInternal(
-	    const std::string& serial_number);
-	SupplicantStatus setWpsConfigMethodsInternal(uint16_t config_methods);
-	SupplicantStatus enableWfdInternal(bool enable);
-	SupplicantStatus setWfdDeviceInfoInternal(
-	    const std::array<uint8_t, 6>& info);
-	std::pair<SupplicantStatus, std::vector<uint8_t>>
-	createNfcHandoverRequestMessageInternal();
-	std::pair<SupplicantStatus, std::vector<uint8_t>>
-	createNfcHandoverSelectMessageInternal();
-	SupplicantStatus reportNfcHandoverResponseInternal(
-	    const std::vector<uint8_t>& request);
-	SupplicantStatus reportNfcHandoverInitiationInternal(
-	    const std::vector<uint8_t>& select);
-	SupplicantStatus saveConfigInternal();
-
-	struct wpa_supplicant* retrieveIfacePtr();
-	struct wpa_supplicant* retrieveGroupIfacePtr(
-	    const std::string& group_ifname);
-
-	// Reference to the global wpa_struct. This is assumed to be valid for
-	// the lifetime of the process.
-	struct wpa_global* wpa_global_;
-	// Name of the iface this hidl object controls
-	const std::string ifname_;
-	bool is_valid_;
-
-	DISALLOW_COPY_AND_ASSIGN(P2pIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WPA_SUPPLICANT_HIDL_P2P_IFACE_H
diff --git a/wpa_supplicant/hidl/1.0/p2p_network.cpp b/wpa_supplicant/hidl/1.0/p2p_network.cpp
deleted file mode 100644
index 7daa453..0000000
--- a/wpa_supplicant/hidl/1.0/p2p_network.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "p2p_network.h"
-
-extern "C" {
-#include "config_ssid.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-P2pNetwork::P2pNetwork(
-    struct wpa_global *wpa_global, const char ifname[], int network_id)
-    : wpa_global_(wpa_global),
-      ifname_(ifname),
-      network_id_(network_id),
-      is_valid_(true)
-{
-}
-
-void P2pNetwork::invalidate() { is_valid_ = false; }
-bool P2pNetwork::isValid()
-{
-	return (is_valid_ && (retrieveNetworkPtr() != nullptr));
-}
-
-Return<void> P2pNetwork::getId(getId_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::getIdInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::getInterfaceName(getInterfaceName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::getInterfaceNameInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::getType(getType_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::getTypeInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::registerCallback(
-    const sp<ISupplicantP2pNetworkCallback> &callback,
-    registerCallback_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> P2pNetwork::getSsid(getSsid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::getSsidInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::getBssid(getBssid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::getBssidInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::isCurrent(isCurrent_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::isCurrentInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::isPersistent(isPersistent_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::isPersistentInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::isGo(isGo_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::isGoInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::setClientList(
-    const hidl_vec<hidl_array<uint8_t, 6>> &clients, setClientList_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::setClientListInternal, _hidl_cb, clients);
-}
-
-Return<void> P2pNetwork::getClientList(getClientList_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &P2pNetwork::getClientListInternal, _hidl_cb);
-}
-
-std::pair<SupplicantStatus, uint32_t> P2pNetwork::getIdInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
-}
-
-std::pair<SupplicantStatus, std::string> P2pNetwork::getInterfaceNameInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> P2pNetwork::getTypeInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::P2P};
-}
-
-SupplicantStatus P2pNetwork::registerCallbackInternal(
-    const sp<ISupplicantP2pNetworkCallback> &callback)
-{
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->addP2pNetworkCallbackHidlObject(
-		ifname_, network_id_, callback)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> P2pNetwork::getSsidInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		{wpa_ssid->ssid, wpa_ssid->ssid + wpa_ssid->ssid_len}};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-P2pNetwork::getBssidInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	std::array<uint8_t, 6> bssid{};
-	if (wpa_ssid->bssid_set) {
-		os_memcpy(bssid.data(), wpa_ssid->bssid, ETH_ALEN);
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, bssid};
-}
-
-std::pair<SupplicantStatus, bool> P2pNetwork::isCurrentInternal()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		(wpa_s->current_ssid == wpa_ssid)};
-}
-
-std::pair<SupplicantStatus, bool> P2pNetwork::isPersistentInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""}, (wpa_ssid->disabled == 2)};
-}
-
-std::pair<SupplicantStatus, bool> P2pNetwork::isGoInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		(wpa_ssid->mode == wpa_ssid::wpas_mode::WPAS_MODE_P2P_GO)};
-}
-
-SupplicantStatus P2pNetwork::setClientListInternal(
-    const std::vector<hidl_array<uint8_t, 6>> &clients)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	os_free(wpa_ssid->p2p_client_list);
-	// Internal representation uses a generic MAC addr/mask storage format
-	// (even though the mask is always 0xFF'ed for p2p_client_list). So, the
-	// first 6 bytes holds the client MAC address and the next 6 bytes are
-	// OxFF'ed.
-	wpa_ssid->p2p_client_list =
-	    (u8 *)os_malloc(ETH_ALEN * 2 * clients.size());
-	if (!wpa_ssid->p2p_client_list) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	u8 *list = wpa_ssid->p2p_client_list;
-	for (const auto &client : clients) {
-		os_memcpy(list, client.data(), ETH_ALEN);
-		list += ETH_ALEN;
-		os_memset(list, 0xFF, ETH_ALEN);
-		list += ETH_ALEN;
-	}
-	wpa_ssid->num_p2p_clients = clients.size();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<hidl_array<uint8_t, 6>>>
-P2pNetwork::getClientListInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->p2p_client_list) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	std::vector<hidl_array<uint8_t, 6>> clients;
-	u8 *list = wpa_ssid->p2p_client_list;
-	for (size_t i = 0; i < wpa_ssid->num_p2p_clients; i++) {
-		clients.emplace_back(list);
-		list += 2 * ETH_ALEN;
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, clients};
-}
-
-/**
- * Retrieve the underlying |wpa_ssid| struct pointer for
- * this network.
- * If the underlying network is removed or the interface
- * this network belong to is removed, all RPC method calls
- * on this object will return failure.
- */
-struct wpa_ssid *P2pNetwork::retrieveNetworkPtr()
-{
-	wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (!wpa_s)
-		return nullptr;
-	return wpa_config_get_network(wpa_s->conf, network_id_);
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this network.
- */
-struct wpa_supplicant *P2pNetwork::retrieveIfacePtr()
-{
-	return wpa_supplicant_get_iface(
-	    (struct wpa_global *)wpa_global_, ifname_.c_str());
-}
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
diff --git a/wpa_supplicant/hidl/1.0/p2p_network.h b/wpa_supplicant/hidl/1.0/p2p_network.h
deleted file mode 100644
index 6164f43..0000000
--- a/wpa_supplicant/hidl/1.0/p2p_network.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
-#define WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * Implementation of P2pNetwork hidl object. Each unique hidl
- * object is used for control operations on a specific network
- * controlled by wpa_supplicant.
- */
-class P2pNetwork : public ISupplicantP2pNetwork
-{
-public:
-	P2pNetwork(
-	    struct wpa_global* wpa_global, const char ifname[], int network_id);
-	~P2pNetwork() override = default;
-	// Refer to |StaIface::invalidate()|.
-	void invalidate();
-	bool isValid();
-
-	// Hidl methods exposed.
-	Return<void> getId(getId_cb _hidl_cb) override;
-	Return<void> getInterfaceName(getInterfaceName_cb _hidl_cb) override;
-	Return<void> getType(getType_cb _hidl_cb) override;
-	Return<void> registerCallback(
-	    const sp<ISupplicantP2pNetworkCallback>& callback,
-	    registerCallback_cb _hidl_cb) override;
-	Return<void> getSsid(getSsid_cb _hidl_cb) override;
-	Return<void> getBssid(getBssid_cb _hidl_cb) override;
-	Return<void> isCurrent(isCurrent_cb _hidl_cb) override;
-	Return<void> isPersistent(isPersistent_cb _hidl_cb) override;
-	Return<void> isGo(isGo_cb _hidl_cb) override;
-	Return<void> setClientList(
-	    const hidl_vec<hidl_array<uint8_t, 6>>& clients,
-	    setClientList_cb _hidl_cb) override;
-	Return<void> getClientList(getClientList_cb _hidl_cb) override;
-
-private:
-	// Corresponding worker functions for the HIDL methods.
-	std::pair<SupplicantStatus, uint32_t> getIdInternal();
-	std::pair<SupplicantStatus, std::string> getInterfaceNameInternal();
-	std::pair<SupplicantStatus, IfaceType> getTypeInternal();
-	SupplicantStatus registerCallbackInternal(
-	    const sp<ISupplicantP2pNetworkCallback>& callback);
-	std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
-	std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
-	std::pair<SupplicantStatus, bool> isCurrentInternal();
-	std::pair<SupplicantStatus, bool> isPersistentInternal();
-	std::pair<SupplicantStatus, bool> isGoInternal();
-	SupplicantStatus setClientListInternal(
-	    const std::vector<hidl_array<uint8_t, 6>>& clients);
-	std::pair<SupplicantStatus, std::vector<hidl_array<uint8_t, 6>>>
-	getClientListInternal();
-
-	struct wpa_ssid* retrieveNetworkPtr();
-	struct wpa_supplicant* retrieveIfacePtr();
-
-	// Reference to the global wpa_struct. This is assumed to be valid
-	// for the lifetime of the process.
-	const struct wpa_global* wpa_global_;
-	// Name of the iface this network belongs to.
-	const std::string ifname_;
-	// Id of the network this hidl object controls.
-	const int network_id_;
-	bool is_valid_;
-
-	DISALLOW_COPY_AND_ASSIGN(P2pNetwork);
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
diff --git a/wpa_supplicant/hidl/1.0/sta_iface.cpp b/wpa_supplicant/hidl/1.0/sta_iface.cpp
deleted file mode 100644
index 8498e69..0000000
--- a/wpa_supplicant/hidl/1.0/sta_iface.cpp
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "iface_config_utils.h"
-#include "misc_utils.h"
-#include "sta_iface.h"
-
-extern "C" {
-#include "utils/eloop.h"
-#include "gas_query.h"
-#include "interworking.h"
-#include "hs20_supplicant.h"
-#include "wps_supplicant.h"
-}
-
-namespace {
-using android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager;
-
-constexpr uint32_t kMaxAnqpElems = 100;
-constexpr char kGetMacAddress[] = "MACADDR";
-constexpr char kStartRxFilter[] = "RXFILTER-START";
-constexpr char kStopRxFilter[] = "RXFILTER-STOP";
-constexpr char kAddRxFilter[] = "RXFILTER-ADD";
-constexpr char kRemoveRxFilter[] = "RXFILTER-REMOVE";
-constexpr char kSetBtCoexistenceMode[] = "BTCOEXMODE";
-constexpr char kSetBtCoexistenceScanStart[] = "BTCOEXSCAN-START";
-constexpr char kSetBtCoexistenceScanStop[] = "BTCOEXSCAN-STOP";
-constexpr char kSetSupendModeEnabled[] = "SETSUSPENDMODE 1";
-constexpr char kSetSupendModeDisabled[] = "SETSUSPENDMODE 0";
-constexpr char kSetCountryCode[] = "COUNTRY";
-constexpr uint32_t kExtRadioWorkDefaultTimeoutInSec = static_cast<uint32_t>(
-    ISupplicantStaIface::ExtRadioWorkDefaults::TIMEOUT_IN_SECS);
-constexpr char kExtRadioWorkNamePrefix[] = "ext:";
-
-uint8_t convertHidlRxFilterTypeToInternal(
-    ISupplicantStaIface::RxFilterType type)
-{
-	switch (type) {
-	case ISupplicantStaIface::RxFilterType::V4_MULTICAST:
-		return 2;
-	case ISupplicantStaIface::RxFilterType::V6_MULTICAST:
-		return 3;
-	};
-	WPA_ASSERT(false);
-}
-
-uint8_t convertHidlBtCoexModeToInternal(
-    ISupplicantStaIface::BtCoexistenceMode mode)
-{
-	switch (mode) {
-	case ISupplicantStaIface::BtCoexistenceMode::ENABLED:
-		return 0;
-	case ISupplicantStaIface::BtCoexistenceMode::DISABLED:
-		return 1;
-	case ISupplicantStaIface::BtCoexistenceMode::SENSE:
-		return 2;
-	};
-	WPA_ASSERT(false);
-}
-
-SupplicantStatus doZeroArgDriverCommand(
-    struct wpa_supplicant *wpa_s, const char *cmd)
-{
-	std::vector<char> cmd_vec(cmd, cmd + strlen(cmd) + 1);
-	char driver_cmd_reply_buf[4096] = {};
-	if (wpa_drv_driver_cmd(
-		wpa_s, cmd_vec.data(), driver_cmd_reply_buf,
-		sizeof(driver_cmd_reply_buf))) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus doOneArgDriverCommand(
-    struct wpa_supplicant *wpa_s, const char *cmd, uint8_t arg)
-{
-	std::string cmd_str = std::string(cmd) + " " + std::to_string(arg);
-	return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
-}
-
-SupplicantStatus doOneArgDriverCommand(
-    struct wpa_supplicant *wpa_s, const char *cmd, const std::string &arg)
-{
-	std::string cmd_str = std::string(cmd) + " " + arg;
-	return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
-}
-
-void endExtRadioWork(struct wpa_radio_work *work)
-{
-	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
-	work->wpa_s->ext_work_in_progress = 0;
-	radio_work_done(work);
-	os_free(ework);
-}
-
-void extRadioWorkTimeoutCb(void *eloop_ctx, void *timeout_ctx)
-{
-	auto *work = static_cast<struct wpa_radio_work *>(eloop_ctx);
-	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
-	wpa_dbg(
-	    work->wpa_s, MSG_DEBUG, "Timing out external radio work %u (%s)",
-	    ework->id, work->type);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	WPA_ASSERT(hidl_manager);
-	hidl_manager->notifyExtRadioWorkTimeout(work->wpa_s, ework->id);
-
-	endExtRadioWork(work);
-}
-
-void startExtRadioWork(struct wpa_radio_work *work)
-{
-	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
-	work->wpa_s->ext_work_in_progress = 1;
-	if (!ework->timeout) {
-		ework->timeout = kExtRadioWorkDefaultTimeoutInSec;
-	}
-	eloop_register_timeout(
-	    ework->timeout, 0, extRadioWorkTimeoutCb, work, nullptr);
-}
-
-void extRadioWorkStartCb(struct wpa_radio_work *work, int deinit)
-{
-	// deinit==1 is invoked during interface removal. Since the HIDL
-	// interface does not support interface addition/removal, we don't
-	// need to handle this scenario.
-	WPA_ASSERT(!deinit);
-
-	auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
-	wpa_dbg(
-	    work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
-	    ework->id, ework->type);
-
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	WPA_ASSERT(hidl_manager);
-	hidl_manager->notifyExtRadioWorkStart(work->wpa_s, ework->id);
-
-	startExtRadioWork(work);
-}
-
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
-    : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
-
-void StaIface::invalidate() { is_valid_ = false; }
-bool StaIface::isValid()
-{
-	return (is_valid_ && (retrieveIfacePtr() != nullptr));
-}
-
-Return<void> StaIface::getName(getName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::getNameInternal, _hidl_cb);
-}
-
-Return<void> StaIface::getType(getType_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::getTypeInternal, _hidl_cb);
-}
-
-Return<void> StaIface::addNetwork(addNetwork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::addNetworkInternal, _hidl_cb);
-}
-
-Return<void> StaIface::removeNetwork(
-    SupplicantNetworkId id, removeNetwork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::removeNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> StaIface::getNetwork(
-    SupplicantNetworkId id, getNetwork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::getNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> StaIface::listNetworks(listNetworks_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::listNetworksInternal, _hidl_cb);
-}
-
-Return<void> StaIface::registerCallback(
-    const sp<ISupplicantStaIfaceCallback> &callback,
-    registerCallback_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::reassociateInternal, _hidl_cb);
-}
-
-Return<void> StaIface::reconnect(reconnect_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::reconnectInternal, _hidl_cb);
-}
-
-Return<void> StaIface::disconnect(disconnect_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::disconnectInternal, _hidl_cb);
-}
-
-Return<void> StaIface::setPowerSave(bool enable, setPowerSave_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setPowerSaveInternal, _hidl_cb, enable);
-}
-
-Return<void> StaIface::initiateTdlsDiscover(
-    const hidl_array<uint8_t, 6> &mac_address, initiateTdlsDiscover_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::initiateTdlsDiscoverInternal, _hidl_cb, mac_address);
-}
-
-Return<void> StaIface::initiateTdlsSetup(
-    const hidl_array<uint8_t, 6> &mac_address, initiateTdlsSetup_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::initiateTdlsSetupInternal, _hidl_cb, mac_address);
-}
-
-Return<void> StaIface::initiateTdlsTeardown(
-    const hidl_array<uint8_t, 6> &mac_address, initiateTdlsTeardown_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::initiateTdlsTeardownInternal, _hidl_cb, mac_address);
-}
-Return<void> StaIface::initiateAnqpQuery(
-    const hidl_array<uint8_t, 6> &mac_address,
-    const hidl_vec<ISupplicantStaIface::AnqpInfoId> &info_elements,
-    const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes> &sub_types,
-    initiateAnqpQuery_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::initiateAnqpQueryInternal, _hidl_cb, mac_address,
-	    info_elements, sub_types);
-}
-
-Return<void> StaIface::initiateHs20IconQuery(
-    const hidl_array<uint8_t, 6> &mac_address, const hidl_string &file_name,
-    initiateHs20IconQuery_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::initiateHs20IconQueryInternal, _hidl_cb, mac_address,
-	    file_name);
-}
-
-Return<void> StaIface::getMacAddress(getMacAddress_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::getMacAddressInternal, _hidl_cb);
-}
-
-Return<void> StaIface::startRxFilter(startRxFilter_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::startRxFilterInternal, _hidl_cb);
-}
-
-Return<void> StaIface::stopRxFilter(stopRxFilter_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::stopRxFilterInternal, _hidl_cb);
-}
-
-Return<void> StaIface::addRxFilter(
-    ISupplicantStaIface::RxFilterType type, addRxFilter_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::addRxFilterInternal, _hidl_cb, type);
-}
-
-Return<void> StaIface::removeRxFilter(
-    ISupplicantStaIface::RxFilterType type, removeRxFilter_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::removeRxFilterInternal, _hidl_cb, type);
-}
-
-Return<void> StaIface::setBtCoexistenceMode(
-    ISupplicantStaIface::BtCoexistenceMode mode,
-    setBtCoexistenceMode_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setBtCoexistenceModeInternal, _hidl_cb, mode);
-}
-
-Return<void> StaIface::setBtCoexistenceScanModeEnabled(
-    bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setBtCoexistenceScanModeEnabledInternal, _hidl_cb,
-	    enable);
-}
-
-Return<void> StaIface::setSuspendModeEnabled(
-    bool enable, setSuspendModeEnabled_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setSuspendModeEnabledInternal, _hidl_cb, enable);
-}
-
-Return<void> StaIface::setCountryCode(
-    const hidl_array<int8_t, 2> &code, setCountryCode_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setCountryCodeInternal, _hidl_cb, code);
-}
-
-Return<void> StaIface::startWpsRegistrar(
-    const hidl_array<uint8_t, 6> &bssid, const hidl_string &pin,
-    startWpsRegistrar_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::startWpsRegistrarInternal, _hidl_cb, bssid, pin);
-}
-
-Return<void> StaIface::startWpsPbc(
-    const hidl_array<uint8_t, 6> &bssid, startWpsPbc_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::startWpsPbcInternal, _hidl_cb, bssid);
-}
-
-Return<void> StaIface::startWpsPinKeypad(
-    const hidl_string &pin, startWpsPinKeypad_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::startWpsPinKeypadInternal, _hidl_cb, pin);
-}
-
-Return<void> StaIface::startWpsPinDisplay(
-    const hidl_array<uint8_t, 6> &bssid, startWpsPinDisplay_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::startWpsPinDisplayInternal, _hidl_cb, bssid);
-}
-
-Return<void> StaIface::cancelWps(cancelWps_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::cancelWpsInternal, _hidl_cb);
-}
-
-Return<void> StaIface::setWpsDeviceName(
-    const hidl_string &name, setWpsDeviceName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setWpsDeviceNameInternal, _hidl_cb, name);
-}
-
-Return<void> StaIface::setWpsDeviceType(
-    const hidl_array<uint8_t, 8> &type, setWpsDeviceType_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setWpsDeviceTypeInternal, _hidl_cb, type);
-}
-
-Return<void> StaIface::setWpsManufacturer(
-    const hidl_string &manufacturer, setWpsManufacturer_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setWpsManufacturerInternal, _hidl_cb, manufacturer);
-}
-
-Return<void> StaIface::setWpsModelName(
-    const hidl_string &model_name, setWpsModelName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setWpsModelNameInternal, _hidl_cb, model_name);
-}
-
-Return<void> StaIface::setWpsModelNumber(
-    const hidl_string &model_number, setWpsModelNumber_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setWpsModelNumberInternal, _hidl_cb, model_number);
-}
-
-Return<void> StaIface::setWpsSerialNumber(
-    const hidl_string &serial_number, setWpsSerialNumber_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setWpsSerialNumberInternal, _hidl_cb, serial_number);
-}
-
-Return<void> StaIface::setWpsConfigMethods(
-    uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setWpsConfigMethodsInternal, _hidl_cb, config_methods);
-}
-
-Return<void> StaIface::setExternalSim(
-    bool useExternalSim, setExternalSim_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::setExternalSimInternal, _hidl_cb, useExternalSim);
-}
-
-Return<void> StaIface::addExtRadioWork(
-    const hidl_string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec,
-    addExtRadioWork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::addExtRadioWorkInternal, _hidl_cb, name, freq_in_mhz,
-	    timeout_in_sec);
-}
-
-Return<void> StaIface::removeExtRadioWork(
-    uint32_t id, removeExtRadioWork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::removeExtRadioWorkInternal, _hidl_cb, id);
-}
-
-Return<void> StaIface::enableAutoReconnect(
-    bool enable, enableAutoReconnect_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &StaIface::enableAutoReconnectInternal, _hidl_cb, enable);
-}
-
-std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> StaIface::getTypeInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
-StaIface::addNetworkInternal()
-{
-	android::sp<ISupplicantStaNetwork> network;
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
-	if (!ssid) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
-	}
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
-		wpa_s->ifname, ssid->id, &network)) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-SupplicantStatus StaIface::removeNetworkInternal(SupplicantNetworkId id)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	int result = wpa_supplicant_remove_network(wpa_s, id);
-	if (result == -1) {
-		return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
-	}
-	if (result != 0) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
-StaIface::getNetworkInternal(SupplicantNetworkId id)
-{
-	android::sp<ISupplicantStaNetwork> network;
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (!ssid) {
-		return {{SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""},
-			network};
-	}
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
-		wpa_s->ifname, ssid->id, &network)) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
-StaIface::listNetworksInternal()
-{
-	std::vector<SupplicantNetworkId> network_ids;
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	for (struct wpa_ssid *wpa_ssid = wpa_s->conf->ssid; wpa_ssid;
-	     wpa_ssid = wpa_ssid->next) {
-		network_ids.emplace_back(wpa_ssid->id);
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, std::move(network_ids)};
-}
-
-SupplicantStatus StaIface::registerCallbackInternal(
-    const sp<ISupplicantStaIfaceCallback> &callback)
-{
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->addStaIfaceCallbackHidlObject(ifname_, callback)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::reassociateInternal()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
-		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
-	}
-	wpas_request_connection(wpa_s);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::reconnectInternal()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
-		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
-	}
-	if (!wpa_s->disconnected) {
-		return {SupplicantStatusCode::FAILURE_IFACE_NOT_DISCONNECTED,
-			""};
-	}
-	wpas_request_connection(wpa_s);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::disconnectInternal()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
-		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
-	}
-	wpas_request_disconnection(wpa_s);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::setPowerSaveInternal(bool enable)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
-		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
-	}
-	if (wpa_drv_set_p2p_powersave(wpa_s, enable, -1, -1)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateTdlsDiscoverInternal(
-    const std::array<uint8_t, 6> &mac_address)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	int ret;
-	const u8 *peer = mac_address.data();
-	if (wpa_tdls_is_external_setup(wpa_s->wpa)) {
-		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
-	} else {
-		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
-	}
-	if (ret) {
-		wpa_printf(MSG_INFO, "StaIface: TDLS discover failed: %d", ret);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateTdlsSetupInternal(
-    const std::array<uint8_t, 6> &mac_address)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	int ret;
-	const u8 *peer = mac_address.data();
-	if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
-	    !(wpa_s->conf->tdls_external_control)) {
-		wpa_tdls_remove(wpa_s->wpa, peer);
-		ret = wpa_tdls_start(wpa_s->wpa, peer);
-	} else {
-		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
-	}
-	if (ret) {
-		wpa_printf(MSG_INFO, "StaIface: TDLS setup failed: %d", ret);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateTdlsTeardownInternal(
-    const std::array<uint8_t, 6> &mac_address)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	int ret;
-	const u8 *peer = mac_address.data();
-	if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
-	    !(wpa_s->conf->tdls_external_control)) {
-		ret = wpa_tdls_teardown_link(
-		    wpa_s->wpa, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
-	} else {
-		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
-	}
-	if (ret) {
-		wpa_printf(MSG_INFO, "StaIface: TDLS teardown failed: %d", ret);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateAnqpQueryInternal(
-    const std::array<uint8_t, 6> &mac_address,
-    const std::vector<ISupplicantStaIface::AnqpInfoId> &info_elements,
-    const std::vector<ISupplicantStaIface::Hs20AnqpSubtypes> &sub_types)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (info_elements.size() > kMaxAnqpElems) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	uint16_t info_elems_buf[kMaxAnqpElems];
-	uint32_t num_info_elems = 0;
-	for (const auto &info_element : info_elements) {
-		info_elems_buf[num_info_elems++] =
-		    static_cast<std::underlying_type<
-			ISupplicantStaIface::AnqpInfoId>::type>(info_element);
-	}
-	uint32_t sub_types_bitmask = 0;
-	for (const auto &type : sub_types) {
-		sub_types_bitmask |= BIT(
-		    static_cast<std::underlying_type<
-			ISupplicantStaIface::Hs20AnqpSubtypes>::type>(type));
-	}
-	if (anqp_send_req(
-		wpa_s, mac_address.data(), info_elems_buf, num_info_elems,
-		sub_types_bitmask, false)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateHs20IconQueryInternal(
-    const std::array<uint8_t, 6> &mac_address, const std::string &file_name)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	wpa_s->fetch_osu_icon_in_progress = 0;
-	if (hs20_anqp_send_req(
-		wpa_s, mac_address.data(), BIT(HS20_STYPE_ICON_REQUEST),
-		reinterpret_cast<const uint8_t *>(file_name.c_str()),
-		file_name.size(), true)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-StaIface::getMacAddressInternal()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	std::vector<char> cmd(
-	    kGetMacAddress, kGetMacAddress + sizeof(kGetMacAddress));
-	char driver_cmd_reply_buf[4096] = {};
-	int ret = wpa_drv_driver_cmd(
-	    wpa_s, cmd.data(), driver_cmd_reply_buf,
-	    sizeof(driver_cmd_reply_buf));
-	// Reply is of the format: "Macaddr = XX:XX:XX:XX:XX:XX"
-	std::string reply_str = driver_cmd_reply_buf;
-	if (ret < 0 || reply_str.empty() ||
-	    reply_str.find("=") == std::string::npos) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	// Remove all whitespace first and then split using the delimiter "=".
-	reply_str.erase(
-	    remove_if(reply_str.begin(), reply_str.end(), isspace),
-	    reply_str.end());
-	std::string mac_addr_str =
-	    reply_str.substr(reply_str.find("=") + 1, reply_str.size());
-	std::array<uint8_t, 6> mac_addr;
-	if (hwaddr_aton(mac_addr_str.c_str(), mac_addr.data())) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, mac_addr};
-}
-
-SupplicantStatus StaIface::startRxFilterInternal()
-{
-	return doZeroArgDriverCommand(retrieveIfacePtr(), kStartRxFilter);
-}
-
-SupplicantStatus StaIface::stopRxFilterInternal()
-{
-	return doZeroArgDriverCommand(retrieveIfacePtr(), kStopRxFilter);
-}
-
-SupplicantStatus StaIface::addRxFilterInternal(
-    ISupplicantStaIface::RxFilterType type)
-{
-	return doOneArgDriverCommand(
-	    retrieveIfacePtr(), kAddRxFilter,
-	    convertHidlRxFilterTypeToInternal(type));
-}
-
-SupplicantStatus StaIface::removeRxFilterInternal(
-    ISupplicantStaIface::RxFilterType type)
-{
-	return doOneArgDriverCommand(
-	    retrieveIfacePtr(), kRemoveRxFilter,
-	    convertHidlRxFilterTypeToInternal(type));
-}
-
-SupplicantStatus StaIface::setBtCoexistenceModeInternal(
-    ISupplicantStaIface::BtCoexistenceMode mode)
-{
-	return doOneArgDriverCommand(
-	    retrieveIfacePtr(), kSetBtCoexistenceMode,
-	    convertHidlBtCoexModeToInternal(mode));
-}
-
-SupplicantStatus StaIface::setBtCoexistenceScanModeEnabledInternal(bool enable)
-{
-	const char *cmd;
-	if (enable) {
-		cmd = kSetBtCoexistenceScanStart;
-	} else {
-		cmd = kSetBtCoexistenceScanStop;
-	}
-	return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
-}
-
-SupplicantStatus StaIface::setSuspendModeEnabledInternal(bool enable)
-{
-	const char *cmd;
-	if (enable) {
-		cmd = kSetSupendModeEnabled;
-	} else {
-		cmd = kSetSupendModeDisabled;
-	}
-	return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
-}
-
-SupplicantStatus StaIface::setCountryCodeInternal(
-    const std::array<int8_t, 2> &code)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	SupplicantStatus status = doOneArgDriverCommand(
-	    wpa_s, kSetCountryCode,
-	    std::string(std::begin(code), std::end(code)));
-	if (status.code != SupplicantStatusCode::SUCCESS) {
-		return status;
-	}
-	struct p2p_data *p2p = wpa_s->global->p2p;
-	if (p2p) {
-		char country[3];
-		country[0] = code[0];
-		country[1] = code[1];
-		country[2] = 0x04;
-		p2p_set_country(p2p, country);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::startWpsRegistrarInternal(
-    const std::array<uint8_t, 6> &bssid, const std::string &pin)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpas_wps_start_reg(wpa_s, bssid.data(), pin.c_str(), nullptr)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::startWpsPbcInternal(
-    const std::array<uint8_t, 6> &bssid)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	const uint8_t *bssid_addr =
-	    is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
-	if (wpas_wps_start_pbc(wpa_s, bssid_addr, 0)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::startWpsPinKeypadInternal(const std::string &pin)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpas_wps_start_pin(
-		wpa_s, nullptr, pin.c_str(), 0, DEV_PW_DEFAULT)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::string> StaIface::startWpsPinDisplayInternal(
-    const std::array<uint8_t, 6> &bssid)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	const uint8_t *bssid_addr =
-	    is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
-	int pin =
-	    wpas_wps_start_pin(wpa_s, bssid_addr, nullptr, 0, DEV_PW_DEFAULT);
-	if (pin < 0) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, ""};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		misc_utils::convertWpsPinToString(pin)};
-}
-
-SupplicantStatus StaIface::cancelWpsInternal()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpas_wps_cancel(wpa_s)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::setWpsDeviceNameInternal(const std::string &name)
-{
-	return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
-}
-
-SupplicantStatus StaIface::setWpsDeviceTypeInternal(
-    const std::array<uint8_t, 8> &type)
-{
-	return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
-}
-
-SupplicantStatus StaIface::setWpsManufacturerInternal(
-    const std::string &manufacturer)
-{
-	return iface_config_utils::setWpsManufacturer(
-	    retrieveIfacePtr(), manufacturer);
-}
-
-SupplicantStatus StaIface::setWpsModelNameInternal(
-    const std::string &model_name)
-{
-	return iface_config_utils::setWpsModelName(
-	    retrieveIfacePtr(), model_name);
-}
-
-SupplicantStatus StaIface::setWpsModelNumberInternal(
-    const std::string &model_number)
-{
-	return iface_config_utils::setWpsModelNumber(
-	    retrieveIfacePtr(), model_number);
-}
-
-SupplicantStatus StaIface::setWpsSerialNumberInternal(
-    const std::string &serial_number)
-{
-	return iface_config_utils::setWpsSerialNumber(
-	    retrieveIfacePtr(), serial_number);
-}
-
-SupplicantStatus StaIface::setWpsConfigMethodsInternal(uint16_t config_methods)
-{
-	return iface_config_utils::setWpsConfigMethods(
-	    retrieveIfacePtr(), config_methods);
-}
-
-SupplicantStatus StaIface::setExternalSimInternal(bool useExternalSim)
-{
-	return iface_config_utils::setExternalSim(
-	    retrieveIfacePtr(), useExternalSim);
-}
-
-std::pair<SupplicantStatus, uint32_t> StaIface::addExtRadioWorkInternal(
-    const std::string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	auto *ework = static_cast<struct wpa_external_work *>(
-	    os_zalloc(sizeof(struct wpa_external_work)));
-	if (!ework) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
-			UINT32_MAX};
-	}
-
-	std::string radio_work_name = kExtRadioWorkNamePrefix + name;
-	os_strlcpy(ework->type, radio_work_name.c_str(), sizeof(ework->type));
-	ework->timeout = timeout_in_sec;
-	wpa_s->ext_work_id++;
-	if (wpa_s->ext_work_id == 0) {
-		wpa_s->ext_work_id++;
-	}
-	ework->id = wpa_s->ext_work_id;
-
-	if (radio_add_work(
-		wpa_s, freq_in_mhz, ework->type, 0, extRadioWorkStartCb,
-		ework)) {
-		os_free(ework);
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
-			UINT32_MAX};
-	}
-	return {SupplicantStatus{SupplicantStatusCode::SUCCESS, ""}, ework->id};
-}
-
-SupplicantStatus StaIface::removeExtRadioWorkInternal(uint32_t id)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	struct wpa_radio_work *work;
-	dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
-	{
-		if (os_strncmp(
-			work->type, kExtRadioWorkNamePrefix,
-			sizeof(kExtRadioWorkNamePrefix)) != 0)
-			continue;
-
-		auto *ework =
-		    static_cast<struct wpa_external_work *>(work->ctx);
-		if (ework->id != id)
-			continue;
-
-		wpa_dbg(
-		    wpa_s, MSG_DEBUG, "Completed external radio work %u (%s)",
-		    ework->id, ework->type);
-		eloop_cancel_timeout(extRadioWorkTimeoutCb, work, NULL);
-		endExtRadioWork(work);
-
-		return {SupplicantStatusCode::SUCCESS, ""};
-	}
-	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-}
-
-SupplicantStatus StaIface::enableAutoReconnectInternal(bool enable)
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	wpa_s->auto_reconnect_disabled = enable ? 0 : 1;
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this iface.
- * If the underlying iface is removed, then all RPC method calls on this object
- * will return failure.
- */
-wpa_supplicant *StaIface::retrieveIfacePtr()
-{
-	return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
-}
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
diff --git a/wpa_supplicant/hidl/1.0/sta_network.cpp b/wpa_supplicant/hidl/1.0/sta_network.cpp
deleted file mode 100644
index f471941..0000000
--- a/wpa_supplicant/hidl/1.0/sta_network.cpp
+++ /dev/null
@@ -1,1825 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "misc_utils.h"
-#include "sta_network.h"
-
-extern "C" {
-#include "wps_supplicant.h"
-}
-
-namespace {
-using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
-
-constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
-
-constexpr uint32_t kAllowedKeyMgmtMask =
-    (static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN));
-constexpr uint32_t kAllowedProtoMask =
-    (static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN));
-constexpr uint32_t kAllowedAuthAlgMask =
-    (static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP));
-constexpr uint32_t kAllowedGroupCipherMask =
-    (static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) |
-     static_cast<uint32_t>(
-	 ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED));
-constexpr uint32_t kAllowedPairwisewCipherMask =
-    (static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP));
-
-constexpr uint32_t kEapMethodMax =
-    static_cast<uint32_t>(ISupplicantStaNetwork::EapMethod::WFA_UNAUTH_TLS) + 1;
-constexpr char const *kEapMethodStrings[kEapMethodMax] = {
-    "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS"};
-constexpr uint32_t kEapPhase2MethodMax =
-    static_cast<uint32_t>(ISupplicantStaNetwork::EapPhase2Method::AKA_PRIME) +
-    1;
-constexpr char const *kEapPhase2MethodStrings[kEapPhase2MethodMax] = {
-    "", "PAP", "MSCHAP", "MSCHAPV2", "GTC", "SIM", "AKA", "AKA'"};
-constexpr char kEapPhase2AuthPrefix[] = "auth=";
-constexpr char kEapPhase2AuthEapPrefix[] = "autheap=";
-constexpr char kNetworkEapSimGsmAuthResponse[] = "GSM-AUTH";
-constexpr char kNetworkEapSimUmtsAuthResponse[] = "UMTS-AUTH";
-constexpr char kNetworkEapSimUmtsAutsResponse[] = "UMTS-AUTS";
-constexpr char kNetworkEapSimGsmAuthFailure[] = "GSM-FAIL";
-constexpr char kNetworkEapSimUmtsAuthFailure[] = "UMTS-FAIL";
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-StaNetwork::StaNetwork(
-    struct wpa_global *wpa_global, const char ifname[], int network_id)
-    : wpa_global_(wpa_global),
-      ifname_(ifname),
-      network_id_(network_id),
-      is_valid_(true)
-{
-}
-
-void StaNetwork::invalidate() { is_valid_ = false; }
-bool StaNetwork::isValid()
-{
-	return (is_valid_ && (retrieveNetworkPtr() != nullptr));
-}
-
-Return<void> StaNetwork::getId(getId_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getIdInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getInterfaceName(getInterfaceName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getInterfaceNameInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getType(getType_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getTypeInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::registerCallback(
-    const sp<ISupplicantStaNetworkCallback> &callback,
-    registerCallback_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> StaNetwork::setSsid(
-    const hidl_vec<uint8_t> &ssid, setSsid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setSsidInternal, _hidl_cb, ssid);
-}
-
-Return<void> StaNetwork::setBssid(
-    const hidl_array<uint8_t, 6> &bssid, setBssid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setBssidInternal, _hidl_cb, bssid);
-}
-
-Return<void> StaNetwork::setScanSsid(bool enable, setScanSsid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setScanSsidInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setKeyMgmt(
-    uint32_t key_mgmt_mask, setKeyMgmt_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setKeyMgmtInternal, _hidl_cb, key_mgmt_mask);
-}
-
-Return<void> StaNetwork::setProto(uint32_t proto_mask, setProto_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setProtoInternal, _hidl_cb, proto_mask);
-}
-
-Return<void> StaNetwork::setAuthAlg(
-    uint32_t auth_alg_mask,
-    std::function<void(const SupplicantStatus &status)> _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setAuthAlgInternal, _hidl_cb, auth_alg_mask);
-}
-
-Return<void> StaNetwork::setGroupCipher(
-    uint32_t group_cipher_mask, setGroupCipher_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setGroupCipherInternal, _hidl_cb, group_cipher_mask);
-}
-
-Return<void> StaNetwork::setPairwiseCipher(
-    uint32_t pairwise_cipher_mask, setPairwiseCipher_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setPairwiseCipherInternal, _hidl_cb,
-	    pairwise_cipher_mask);
-}
-
-Return<void> StaNetwork::setPskPassphrase(
-    const hidl_string &psk, setPskPassphrase_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setPskPassphraseInternal, _hidl_cb, psk);
-}
-
-Return<void> StaNetwork::setPsk(
-    const hidl_array<uint8_t, 32> &psk, setPsk_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setPskInternal, _hidl_cb, psk);
-}
-
-Return<void> StaNetwork::setWepKey(
-    uint32_t key_idx, const hidl_vec<uint8_t> &wep_key, setWepKey_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setWepKeyInternal, _hidl_cb, key_idx, wep_key);
-}
-
-Return<void> StaNetwork::setWepTxKeyIdx(
-    uint32_t key_idx, setWepTxKeyIdx_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setWepTxKeyIdxInternal, _hidl_cb, key_idx);
-}
-
-Return<void> StaNetwork::setRequirePmf(bool enable, setRequirePmf_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setRequirePmfInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setEapMethod(
-    ISupplicantStaNetwork::EapMethod method, setEapMethod_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapMethodInternal, _hidl_cb, method);
-}
-
-Return<void> StaNetwork::setEapPhase2Method(
-    ISupplicantStaNetwork::EapPhase2Method method,
-    setEapPhase2Method_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapPhase2MethodInternal, _hidl_cb, method);
-}
-
-Return<void> StaNetwork::setEapIdentity(
-    const hidl_vec<uint8_t> &identity, setEapIdentity_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapIdentityInternal, _hidl_cb, identity);
-}
-
-Return<void> StaNetwork::setEapAnonymousIdentity(
-    const hidl_vec<uint8_t> &identity, setEapAnonymousIdentity_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapAnonymousIdentityInternal, _hidl_cb, identity);
-}
-
-Return<void> StaNetwork::setEapPassword(
-    const hidl_vec<uint8_t> &password, setEapPassword_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapPasswordInternal, _hidl_cb, password);
-}
-
-Return<void> StaNetwork::setEapCACert(
-    const hidl_string &path, setEapCACert_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapCACertInternal, _hidl_cb, path);
-}
-
-Return<void> StaNetwork::setEapCAPath(
-    const hidl_string &path, setEapCAPath_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapCAPathInternal, _hidl_cb, path);
-}
-
-Return<void> StaNetwork::setEapClientCert(
-    const hidl_string &path, setEapClientCert_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapClientCertInternal, _hidl_cb, path);
-}
-
-Return<void> StaNetwork::setEapPrivateKeyId(
-    const hidl_string &id, setEapPrivateKeyId_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapPrivateKeyIdInternal, _hidl_cb, id);
-}
-
-Return<void> StaNetwork::setEapSubjectMatch(
-    const hidl_string &match, setEapSubjectMatch_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapSubjectMatchInternal, _hidl_cb, match);
-}
-
-Return<void> StaNetwork::setEapAltSubjectMatch(
-    const hidl_string &match, setEapAltSubjectMatch_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapAltSubjectMatchInternal, _hidl_cb, match);
-}
-
-Return<void> StaNetwork::setEapEngine(bool enable, setEapEngine_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapEngineInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setEapEngineID(
-    const hidl_string &id, setEapEngineID_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapEngineIDInternal, _hidl_cb, id);
-}
-
-Return<void> StaNetwork::setEapDomainSuffixMatch(
-    const hidl_string &match, setEapDomainSuffixMatch_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapDomainSuffixMatchInternal, _hidl_cb, match);
-}
-
-Return<void> StaNetwork::setProactiveKeyCaching(
-    bool enable, setProactiveKeyCaching_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setProactiveKeyCachingInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setIdStr(
-    const hidl_string &id_str, setIdStr_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setIdStrInternal, _hidl_cb, id_str);
-}
-
-Return<void> StaNetwork::setUpdateIdentifier(
-    uint32_t id, setUpdateIdentifier_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setUpdateIdentifierInternal, _hidl_cb, id);
-}
-
-Return<void> StaNetwork::getSsid(getSsid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getSsidInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getBssid(getBssid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getBssidInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getScanSsid(getScanSsid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getScanSsidInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getKeyMgmt(getKeyMgmt_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getKeyMgmtInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getProto(getProto_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getProtoInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getAuthAlg(getAuthAlg_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getAuthAlgInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getGroupCipher(getGroupCipher_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getGroupCipherInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getPairwiseCipher(getPairwiseCipher_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getPairwiseCipherInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getPskPassphrase(getPskPassphrase_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getPskPassphraseInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getPsk(getPsk_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getPskInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getWepKey(uint32_t key_idx, getWepKey_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getWepKeyInternal, _hidl_cb, key_idx);
-}
-
-Return<void> StaNetwork::getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getWepTxKeyIdxInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getRequirePmf(getRequirePmf_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getRequirePmfInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapMethod(getEapMethod_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapMethodInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapPhase2Method(getEapPhase2Method_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapPhase2MethodInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapIdentity(getEapIdentity_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapIdentityInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapAnonymousIdentity(
-    getEapAnonymousIdentity_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapAnonymousIdentityInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapPassword(getEapPassword_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapPasswordInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapCACert(getEapCACert_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapCACertInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapCAPath(getEapCAPath_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapCAPathInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapClientCert(getEapClientCert_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapClientCertInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapPrivateKeyId(getEapPrivateKeyId_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapPrivateKeyIdInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapSubjectMatch(getEapSubjectMatch_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapSubjectMatchInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapAltSubjectMatch(
-    getEapAltSubjectMatch_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapAltSubjectMatchInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapEngine(getEapEngine_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapEngineInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapEngineID(getEapEngineID_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapEngineIDInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapDomainSuffixMatch(
-    getEapDomainSuffixMatch_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getEapDomainSuffixMatchInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getIdStr(getIdStr_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getIdStrInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getWpsNfcConfigurationToken(
-    getWpsNfcConfigurationToken_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::getWpsNfcConfigurationTokenInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::enable(bool no_connect, enable_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::enableInternal, _hidl_cb, no_connect);
-}
-
-Return<void> StaNetwork::disable(disable_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::disableInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::select(select_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::selectInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimGsmAuthResponse(
-    const hidl_vec<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
-	&vec_params,
-    sendNetworkEapSimGsmAuthResponse_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::sendNetworkEapSimGsmAuthResponseInternal, _hidl_cb,
-	    vec_params);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimGsmAuthFailure(
-    sendNetworkEapSimGsmAuthFailure_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::sendNetworkEapSimGsmAuthFailureInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimUmtsAuthResponse(
-    const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams &params,
-    sendNetworkEapSimUmtsAuthResponse_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal, _hidl_cb,
-	    params);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimUmtsAutsResponse(
-    const hidl_array<uint8_t, 14> &auts,
-    sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal, _hidl_cb,
-	    auts);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimUmtsAuthFailure(
-    sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::sendNetworkEapIdentityResponse(
-    const hidl_vec<uint8_t> &identity,
-    sendNetworkEapIdentityResponse_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::sendNetworkEapIdentityResponseInternal, _hidl_cb,
-	    identity);
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getInterfaceNameInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> StaNetwork::getTypeInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
-}
-
-SupplicantStatus StaNetwork::registerCallbackInternal(
-    const sp<ISupplicantStaNetworkCallback> &callback)
-{
-	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->addStaNetworkCallbackHidlObject(
-		ifname_, network_id_, callback)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setSsidInternal(const std::vector<uint8_t> &ssid)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (ssid.size() == 0 ||
-	    ssid.size() >
-		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
-					  SSID_MAX_LEN_IN_BYTES)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	if (setByteArrayFieldAndResetState(
-		ssid.data(), ssid.size(), &(wpa_ssid->ssid),
-		&(wpa_ssid->ssid_len), "ssid")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	if (wpa_ssid->passphrase) {
-		wpa_config_update_psk(wpa_ssid);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setBssidInternal(
-    const std::array<uint8_t, 6> &bssid)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	int prev_bssid_set = wpa_ssid->bssid_set;
-	u8 prev_bssid[ETH_ALEN];
-	os_memcpy(prev_bssid, wpa_ssid->bssid, ETH_ALEN);
-	// Zero'ed array is used to clear out the BSSID value.
-	if (os_memcmp(bssid.data(), kZeroBssid, ETH_ALEN) == 0) {
-		wpa_ssid->bssid_set = 0;
-		wpa_printf(MSG_MSGDUMP, "BSSID any");
-	} else {
-		os_memcpy(wpa_ssid->bssid, bssid.data(), ETH_ALEN);
-		wpa_ssid->bssid_set = 1;
-		wpa_hexdump(MSG_MSGDUMP, "BSSID", wpa_ssid->bssid, ETH_ALEN);
-	}
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if ((wpa_ssid->bssid_set != prev_bssid_set ||
-	     os_memcmp(wpa_ssid->bssid, prev_bssid, ETH_ALEN) != 0)) {
-		wpas_notify_network_bssid_set_changed(wpa_s, wpa_ssid);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setScanSsidInternal(bool enable)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	wpa_ssid->scan_ssid = enable ? 1 : 0;
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setKeyMgmtInternal(uint32_t key_mgmt_mask)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (key_mgmt_mask & ~kAllowedKeyMgmtMask) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	wpa_ssid->key_mgmt = key_mgmt_mask;
-	wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", wpa_ssid->key_mgmt);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setProtoInternal(uint32_t proto_mask)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (proto_mask & ~kAllowedProtoMask) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	wpa_ssid->proto = proto_mask;
-	wpa_printf(MSG_MSGDUMP, "proto: 0x%x", wpa_ssid->proto);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setAuthAlgInternal(uint32_t auth_alg_mask)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (auth_alg_mask & ~kAllowedAuthAlgMask) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	wpa_ssid->auth_alg = auth_alg_mask;
-	wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", wpa_ssid->auth_alg);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setGroupCipherInternal(uint32_t group_cipher_mask)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (group_cipher_mask & ~kAllowedGroupCipherMask) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	wpa_ssid->group_cipher = group_cipher_mask;
-	wpa_printf(MSG_MSGDUMP, "group_cipher: 0x%x", wpa_ssid->group_cipher);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setPairwiseCipherInternal(
-    uint32_t pairwise_cipher_mask)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (pairwise_cipher_mask & ~kAllowedPairwisewCipherMask) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	wpa_ssid->pairwise_cipher = pairwise_cipher_mask;
-	wpa_printf(
-	    MSG_MSGDUMP, "pairwise_cipher: 0x%x", wpa_ssid->pairwise_cipher);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setPskPassphraseInternal(const std::string &psk)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (isPskPassphraseValid(psk)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	if (wpa_ssid->passphrase &&
-	    os_strlen(wpa_ssid->passphrase) == psk.size() &&
-	    os_memcmp(wpa_ssid->passphrase, psk.c_str(), psk.size()) == 0) {
-		return {SupplicantStatusCode::SUCCESS, ""};
-	}
-	// Flag to indicate if raw psk is calculated or not using
-	// |wpa_config_update_psk|. Deferred if ssid not already set.
-	wpa_ssid->psk_set = 0;
-	if (setStringKeyFieldAndResetState(
-		psk.c_str(), &(wpa_ssid->passphrase), "psk passphrase")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	if (wpa_ssid->ssid_len) {
-		wpa_config_update_psk(wpa_ssid);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setPskInternal(const std::array<uint8_t, 32> &psk)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	WPA_ASSERT(psk.size() == sizeof(wpa_ssid->psk));
-	str_clear_free(wpa_ssid->passphrase);
-	wpa_ssid->passphrase = nullptr;
-	os_memcpy(wpa_ssid->psk, psk.data(), sizeof(wpa_ssid->psk));
-	wpa_ssid->psk_set = 1;
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setWepKeyInternal(
-    uint32_t key_idx, const std::vector<uint8_t> &wep_key)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (key_idx >=
-	    static_cast<uint32_t>(
-		ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	if (wep_key.size() !=
-		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
-					  WEP40_KEY_LEN_IN_BYTES) &&
-	    wep_key.size() !=
-		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
-					  WEP104_KEY_LEN_IN_BYTES)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	os_memcpy(wpa_ssid->wep_key[key_idx], wep_key.data(), wep_key.size());
-	wpa_ssid->wep_key_len[key_idx] = wep_key.size();
-	std::string msg_dump_title("wep_key" + std::to_string(key_idx));
-	wpa_hexdump_key(
-	    MSG_MSGDUMP, msg_dump_title.c_str(), wpa_ssid->wep_key[key_idx],
-	    wpa_ssid->wep_key_len[key_idx]);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setWepTxKeyIdxInternal(uint32_t key_idx)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (key_idx >=
-	    static_cast<uint32_t>(
-		ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	wpa_ssid->wep_tx_keyidx = key_idx;
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setRequirePmfInternal(bool enable)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	wpa_ssid->ieee80211w =
-	    enable ? MGMT_FRAME_PROTECTION_REQUIRED : NO_MGMT_FRAME_PROTECTION;
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapMethodInternal(
-    ISupplicantStaNetwork::EapMethod method)
-{
-	uint32_t eap_method_idx = static_cast<
-	    std::underlying_type<ISupplicantStaNetwork::EapMethod>::type>(
-	    method);
-	if (eap_method_idx >= kEapMethodMax) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	int retrieved_vendor, retrieved_method;
-	const char *method_str = kEapMethodStrings[eap_method_idx];
-	// This string lookup is needed to check if the device supports the
-	// corresponding EAP type.
-	retrieved_method = eap_peer_get_type(method_str, &retrieved_vendor);
-	if (retrieved_vendor == EAP_VENDOR_IETF &&
-	    retrieved_method == EAP_TYPE_NONE) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	if (wpa_ssid->eap.eap_methods) {
-		os_free(wpa_ssid->eap.eap_methods);
-	}
-	// wpa_supplicant can support setting multiple eap methods for each
-	// network. But, this is not really used by Android. So, just adding
-	// support for setting one EAP method for each network. The additional
-	// |eap_method_type| member in the array is used to indicate the end
-	// of list.
-	wpa_ssid->eap.eap_methods =
-	    (eap_method_type *)os_malloc(sizeof(eap_method_type) * 2);
-	if (!wpa_ssid->eap.eap_methods) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	wpa_ssid->eap.eap_methods[0].vendor = retrieved_vendor;
-	wpa_ssid->eap.eap_methods[0].method = retrieved_method;
-	wpa_ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
-	wpa_ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
-
-	wpa_ssid->leap = 0;
-	wpa_ssid->non_leap = 0;
-	if (retrieved_vendor == EAP_VENDOR_IETF &&
-	    retrieved_method == EAP_TYPE_LEAP) {
-		wpa_ssid->leap++;
-	} else {
-		wpa_ssid->non_leap++;
-	}
-	wpa_hexdump(
-	    MSG_MSGDUMP, "eap methods", (u8 *)wpa_ssid->eap.eap_methods,
-	    sizeof(eap_method_type) * 2);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapPhase2MethodInternal(
-    ISupplicantStaNetwork::EapPhase2Method method)
-{
-	uint32_t eap_phase2_method_idx = static_cast<
-	    std::underlying_type<ISupplicantStaNetwork::EapPhase2Method>::type>(
-	    method);
-	if (eap_phase2_method_idx >= kEapPhase2MethodMax) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	// EAP method needs to be set for us to construct the eap
-	// phase 2 method string.
-	SupplicantStatus status;
-	ISupplicantStaNetwork::EapMethod eap_method;
-	std::tie(status, eap_method) = getEapMethodInternal();
-	if (status.code != SupplicantStatusCode::SUCCESS) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN,
-			"EAP method not set"};
-	}
-	std::string eap_phase2_str;
-	if (method == ISupplicantStaNetwork::EapPhase2Method::NONE) {
-		eap_phase2_str = "";
-	} else if (
-	    eap_method == ISupplicantStaNetwork::EapMethod::TTLS &&
-	    method == ISupplicantStaNetwork::EapPhase2Method::GTC) {
-		eap_phase2_str = kEapPhase2AuthEapPrefix;
-	} else {
-		eap_phase2_str = kEapPhase2AuthPrefix;
-	}
-	eap_phase2_str += kEapPhase2MethodStrings[eap_phase2_method_idx];
-	if (setStringFieldAndResetState(
-		eap_phase2_str.c_str(), &(wpa_ssid->eap.phase2),
-		"eap phase2")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapIdentityInternal(
-    const std::vector<uint8_t> &identity)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setByteArrayFieldAndResetState(
-		identity.data(), identity.size(), &(wpa_ssid->eap.identity),
-		&(wpa_ssid->eap.identity_len), "eap identity")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapAnonymousIdentityInternal(
-    const std::vector<uint8_t> &identity)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setByteArrayFieldAndResetState(
-		identity.data(), identity.size(),
-		&(wpa_ssid->eap.anonymous_identity),
-		&(wpa_ssid->eap.anonymous_identity_len),
-		"eap anonymous_identity")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapPasswordInternal(
-    const std::vector<uint8_t> &password)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setByteArrayKeyFieldAndResetState(
-		password.data(), password.size(), &(wpa_ssid->eap.password),
-		&(wpa_ssid->eap.password_len), "eap password")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	wpa_ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
-	wpa_ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapCACertInternal(const std::string &path)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		path.c_str(), &(wpa_ssid->eap.ca_cert), "eap ca_cert")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapCAPathInternal(const std::string &path)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		path.c_str(), &(wpa_ssid->eap.ca_path), "eap ca_path")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapClientCertInternal(const std::string &path)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		path.c_str(), &(wpa_ssid->eap.client_cert),
-		"eap client_cert")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapPrivateKeyIdInternal(const std::string &id)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		id.c_str(), &(wpa_ssid->eap.key_id), "eap key_id")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapSubjectMatchInternal(
-    const std::string &match)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		match.c_str(), &(wpa_ssid->eap.subject_match),
-		"eap subject_match")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapAltSubjectMatchInternal(
-    const std::string &match)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		match.c_str(), &(wpa_ssid->eap.altsubject_match),
-		"eap altsubject_match")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapEngineInternal(bool enable)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	wpa_ssid->eap.engine = enable ? 1 : 0;
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapEngineIDInternal(const std::string &id)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		id.c_str(), &(wpa_ssid->eap.engine_id), "eap engine_id")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapDomainSuffixMatchInternal(
-    const std::string &match)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		match.c_str(), &(wpa_ssid->eap.domain_suffix_match),
-		"eap domain_suffix_match")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setProactiveKeyCachingInternal(bool enable)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	wpa_ssid->proactive_key_caching = enable ? 1 : 0;
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setIdStrInternal(const std::string &id_str)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (setStringFieldAndResetState(
-		id_str.c_str(), &(wpa_ssid->id_str), "id_str")) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setUpdateIdentifierInternal(uint32_t id)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	wpa_ssid->update_identifier = id;
-	wpa_printf(
-	    MSG_MSGDUMP, "update_identifier: %d", wpa_ssid->update_identifier);
-	resetInternalStateAfterParamsUpdate();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getSsidInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	std::vector<uint8_t> ssid;
-	ssid.assign(wpa_ssid->ssid, wpa_ssid->ssid + wpa_ssid->ssid_len);
-	return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ssid)};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-StaNetwork::getBssidInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	std::array<uint8_t, 6> bssid{};
-	os_memcpy(bssid.data(), kZeroBssid, ETH_ALEN);
-	if (wpa_ssid->bssid_set) {
-		os_memcpy(bssid.data(), wpa_ssid->bssid, ETH_ALEN);
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, std::move(bssid)};
-}
-
-std::pair<SupplicantStatus, bool> StaNetwork::getScanSsidInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		(wpa_ssid->scan_ssid == 1)};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getKeyMgmtInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		wpa_ssid->key_mgmt & kAllowedKeyMgmtMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getProtoInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		wpa_ssid->proto & kAllowedProtoMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getAuthAlgInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		wpa_ssid->auth_alg & kAllowedAuthAlgMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipherInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		wpa_ssid->group_cipher & kAllowedGroupCipherMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipherInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		wpa_ssid->pairwise_cipher & kAllowedPairwisewCipherMask};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getPskPassphraseInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->passphrase) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->passphrase};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 32>>
-StaNetwork::getPskInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	WPA_ASSERT(psk.size() == sizeof(wpa_ssid->psk));
-	if (!wpa_ssid->psk_set) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	std::array<uint8_t, 32> psk;
-	os_memcpy(psk.data(), wpa_ssid->psk, psk.size());
-	return {{SupplicantStatusCode::SUCCESS, ""}, psk};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getWepKeyInternal(
-    uint32_t key_idx)
-{
-	std::vector<uint8_t> wep_key;
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (key_idx >=
-	    static_cast<uint32_t>(
-		ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
-		return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""},
-			wep_key};
-	}
-	wep_key.assign(
-	    wpa_ssid->wep_key[key_idx],
-	    wpa_ssid->wep_key[key_idx] + wpa_ssid->wep_key_len[key_idx]);
-	return {{SupplicantStatusCode::SUCCESS, ""}, std::move(wep_key)};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getWepTxKeyIdxInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->wep_tx_keyidx};
-}
-
-std::pair<SupplicantStatus, bool> StaNetwork::getRequirePmfInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		(wpa_ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)};
-}
-
-std::pair<SupplicantStatus, ISupplicantStaNetwork::EapMethod>
-StaNetwork::getEapMethodInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.eap_methods) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	// wpa_supplicant can support setting multiple eap methods for each
-	// network. But, this is not really used by Android. So, just reading
-	// the first EAP method for each network.
-	const std::string eap_method_str = eap_get_name(
-	    wpa_ssid->eap.eap_methods[0].vendor,
-	    static_cast<EapType>(wpa_ssid->eap.eap_methods[0].method));
-	size_t eap_method_idx =
-	    std::find(
-		std::begin(kEapMethodStrings), std::end(kEapMethodStrings),
-		eap_method_str) -
-	    std::begin(kEapMethodStrings);
-	if (eap_method_idx >= kEapMethodMax) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		static_cast<ISupplicantStaNetwork::EapMethod>(eap_method_idx)};
-}
-
-std::pair<SupplicantStatus, ISupplicantStaNetwork::EapPhase2Method>
-StaNetwork::getEapPhase2MethodInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.phase2) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	const std::string eap_phase2_method_str_with_prefix =
-	    wpa_ssid->eap.phase2;
-	std::string eap_phase2_method_str;
-	// Strip out the phase 2 method prefix before doing a reverse lookup
-	// of phase 2 string to the Eap Phase 2 type.
-	if (eap_phase2_method_str_with_prefix.find(kEapPhase2AuthPrefix) == 0) {
-		eap_phase2_method_str =
-		    eap_phase2_method_str_with_prefix.substr(
-			strlen(kEapPhase2AuthPrefix),
-			eap_phase2_method_str_with_prefix.size());
-	} else if (
-	    eap_phase2_method_str_with_prefix.find(kEapPhase2AuthEapPrefix) ==
-	    0) {
-		eap_phase2_method_str =
-		    eap_phase2_method_str_with_prefix.substr(
-			strlen(kEapPhase2AuthEapPrefix),
-			eap_phase2_method_str_with_prefix.size());
-	}
-	size_t eap_phase2_method_idx =
-	    std::find(
-		std::begin(kEapPhase2MethodStrings),
-		std::end(kEapPhase2MethodStrings), eap_phase2_method_str) -
-	    std::begin(kEapPhase2MethodStrings);
-	if (eap_phase2_method_idx >= kEapPhase2MethodMax) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		static_cast<ISupplicantStaNetwork::EapPhase2Method>(
-		    eap_phase2_method_idx)};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getEapIdentityInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.identity) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		std::vector<uint8_t>(
-		    wpa_ssid->eap.identity,
-		    wpa_ssid->eap.identity + wpa_ssid->eap.identity_len)};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getEapAnonymousIdentityInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.anonymous_identity) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		std::vector<uint8_t>(
-		    wpa_ssid->eap.anonymous_identity,
-		    wpa_ssid->eap.anonymous_identity +
-			wpa_ssid->eap.anonymous_identity_len)};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getEapPasswordInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.password) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		std::vector<uint8_t>(
-		    wpa_ssid->eap.password,
-		    wpa_ssid->eap.password + wpa_ssid->eap.password_len)};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapCACertInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.ca_cert) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		reinterpret_cast<char *>(wpa_ssid->eap.ca_cert)};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapCAPathInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.ca_path) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		reinterpret_cast<char *>(wpa_ssid->eap.ca_path)};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapClientCertInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.client_cert) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		reinterpret_cast<char *>(wpa_ssid->eap.client_cert)};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapPrivateKeyIdInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.key_id) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.key_id};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapSubjectMatchInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.subject_match) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		reinterpret_cast<char *>(wpa_ssid->eap.subject_match)};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapAltSubjectMatchInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.altsubject_match) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		reinterpret_cast<char *>(wpa_ssid->eap.altsubject_match)};
-}
-
-std::pair<SupplicantStatus, bool> StaNetwork::getEapEngineInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.engine == 1};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapEngineIDInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.engine_id) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.engine_id}};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapDomainSuffixMatchInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->eap.domain_suffix_match) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		{wpa_ssid->eap.domain_suffix_match}};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getIdStrInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (!wpa_ssid->id_str) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->id_str}};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getWpsNfcConfigurationTokenInternal()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	auto token_buf = misc_utils::createWpaBufUniquePtr(
-	    wpas_wps_network_config_token(wpa_s, 0, wpa_ssid));
-	if (!token_buf) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		misc_utils::convertWpaBufToVector(token_buf.get())};
-}
-
-SupplicantStatus StaNetwork::enableInternal(bool no_connect)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (wpa_ssid->disabled == 2) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (no_connect) {
-		wpa_ssid->disabled = 0;
-	} else {
-		wpa_s->scan_min_time.sec = 0;
-		wpa_s->scan_min_time.usec = 0;
-		wpa_supplicant_enable_network(wpa_s, wpa_ssid);
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::disableInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (wpa_ssid->disabled == 2) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	wpa_supplicant_disable_network(wpa_s, wpa_ssid);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::selectInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (wpa_ssid->disabled == 2) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	wpa_s->scan_min_time.sec = 0;
-	wpa_s->scan_min_time.usec = 0;
-	wpa_supplicant_select_network(wpa_s, wpa_ssid);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthResponseInternal(
-    const std::vector<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
-	&vec_params)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	// Convert the incoming parameters to a string to pass to
-	// wpa_supplicant.
-	std::string ctrl_rsp_param = std::string(kNetworkEapSimGsmAuthResponse);
-	for (const auto &params : vec_params) {
-		uint32_t kc_hex_len = params.kc.size() * 2 + 1;
-		std::vector<char> kc_hex(kc_hex_len);
-		uint32_t sres_hex_len = params.sres.size() * 2 + 1;
-		std::vector<char> sres_hex(sres_hex_len);
-		wpa_snprintf_hex(
-		    kc_hex.data(), kc_hex.size(), params.kc.data(),
-		    params.kc.size());
-		wpa_snprintf_hex(
-		    sres_hex.data(), sres_hex.size(), params.sres.data(),
-		    params.sres.size());
-		ctrl_rsp_param += ":" + std::string(kc_hex.data()) + ":" +
-				  std::string(sres_hex.data());
-	}
-	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_supplicant_ctrl_rsp_handle(
-		wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(),
-                ctrl_rsp_param.size())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	eapol_sm_notify_ctrl_response(wpa_s->eapol);
-	wpa_hexdump_ascii_key(
-	    MSG_DEBUG, "network sim gsm auth response param",
-	    (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthFailureInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
-	if (wpa_supplicant_ctrl_rsp_handle(
-		wpa_s, wpa_ssid, rtype, kNetworkEapSimGsmAuthFailure,
-                strlen(kNetworkEapSimGsmAuthFailure))) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	eapol_sm_notify_ctrl_response(wpa_s->eapol);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal(
-    const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams &params)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	// Convert the incoming parameters to a string to pass to
-	// wpa_supplicant.
-	uint32_t ik_hex_len = params.ik.size() * 2 + 1;
-	std::vector<char> ik_hex(ik_hex_len);
-	uint32_t ck_hex_len = params.ck.size() * 2 + 1;
-	std::vector<char> ck_hex(ck_hex_len);
-	uint32_t res_hex_len = params.res.size() * 2 + 1;
-	std::vector<char> res_hex(res_hex_len);
-	wpa_snprintf_hex(
-	    ik_hex.data(), ik_hex.size(), params.ik.data(), params.ik.size());
-	wpa_snprintf_hex(
-	    ck_hex.data(), ck_hex.size(), params.ck.data(), params.ck.size());
-	wpa_snprintf_hex(
-	    res_hex.data(), res_hex.size(), params.res.data(),
-	    params.res.size());
-	std::string ctrl_rsp_param =
-	    std::string(kNetworkEapSimUmtsAuthResponse) + ":" +
-	    std::string(ik_hex.data()) + ":" + std::string(ck_hex.data()) +
-	    ":" + std::string(res_hex.data());
-	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_supplicant_ctrl_rsp_handle(
-		wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(),
-                ctrl_rsp_param.size())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	eapol_sm_notify_ctrl_response(wpa_s->eapol);
-	wpa_hexdump_ascii_key(
-	    MSG_DEBUG, "network sim umts auth response param",
-	    (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal(
-    const std::array<uint8_t, 14> &auts)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	uint32_t auts_hex_len = auts.size() * 2 + 1;
-	std::vector<char> auts_hex(auts_hex_len);
-	wpa_snprintf_hex(
-	    auts_hex.data(), auts_hex.size(), auts.data(), auts.size());
-	std::string ctrl_rsp_param =
-	    std::string(kNetworkEapSimUmtsAutsResponse) + ":" +
-	    std::string(auts_hex.data());
-	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_supplicant_ctrl_rsp_handle(
-		wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(),
-                ctrl_rsp_param.size())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	eapol_sm_notify_ctrl_response(wpa_s->eapol);
-	wpa_hexdump_ascii_key(
-	    MSG_DEBUG, "network sim umts auts response param",
-	    (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal()
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
-	if (wpa_supplicant_ctrl_rsp_handle(
-		wpa_s, wpa_ssid, rtype, kNetworkEapSimUmtsAuthFailure,
-                strlen(kNetworkEapSimUmtsAuthFailure))) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	eapol_sm_notify_ctrl_response(wpa_s->eapol);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal(
-    const std::vector<uint8_t> &identity)
-{
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	std::string ctrl_rsp_param(identity.begin(), identity.end());
-	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_EAP_IDENTITY;
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (wpa_supplicant_ctrl_rsp_handle(
-		wpa_s, wpa_ssid, rtype,  ctrl_rsp_param.data(),
-                ctrl_rsp_param.size())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	eapol_sm_notify_ctrl_response(wpa_s->eapol);
-	wpa_hexdump_ascii_key(
-	    MSG_DEBUG, "network identity response param",
-	    (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-/**
- * Retrieve the underlying |wpa_ssid| struct pointer for
- * this network.
- * If the underlying network is removed or the interface
- * this network belong to
- * is removed, all RPC method calls on this object will
- * return failure.
- */
-struct wpa_ssid *StaNetwork::retrieveNetworkPtr()
-{
-	wpa_supplicant *wpa_s = retrieveIfacePtr();
-	if (!wpa_s)
-		return nullptr;
-	return wpa_config_get_network(wpa_s->conf, network_id_);
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for
- * this network.
- */
-struct wpa_supplicant *StaNetwork::retrieveIfacePtr()
-{
-	return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
-}
-
-/**
- * Check if the provided psk passhrase is valid or not.
- *
- * Returns 0 if valid, 1 otherwise.
- */
-int StaNetwork::isPskPassphraseValid(const std::string &psk)
-{
-	if (psk.size() <
-		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
-					  PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
-	    psk.size() >
-		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
-					  PSK_PASSPHRASE_MAX_LEN_IN_BYTES)) {
-		return 1;
-	}
-	if (has_ctrl_char((u8 *)psk.c_str(), psk.size())) {
-		return 1;
-	}
-	return 0;
-}
-
-/**
- * Reset internal wpa_supplicant state machine state
- * after params update (except
- * bssid).
- */
-void StaNetwork::resetInternalStateAfterParamsUpdate()
-{
-	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
-	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-
-	wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_ssid);
-
-	if (wpa_s->current_ssid == wpa_ssid || wpa_s->current_ssid == NULL) {
-		/*
-		 * Invalidate the EAP session cache if
-		 * anything in the
-		 * current or previously used
-		 * configuration changes.
-		 */
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
-	}
-}
-
-/**
- * Helper function to set value in a string field in |wpa_ssid| structue
- * instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setStringFieldAndResetState(
-    const char *value, uint8_t **to_update_field, const char *hexdump_prefix)
-{
-	return setStringFieldAndResetState(
-	    value, (char **)to_update_field, hexdump_prefix);
-}
-
-/**
- * Helper function to set value in a string field in |wpa_ssid| structue
- * instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setStringFieldAndResetState(
-    const char *value, char **to_update_field, const char *hexdump_prefix)
-{
-	int value_len = strlen(value);
-	if (*to_update_field) {
-		os_free(*to_update_field);
-	}
-	*to_update_field = dup_binstr(value, value_len);
-	if (!(*to_update_field)) {
-		return 1;
-	}
-	wpa_hexdump_ascii(
-	    MSG_MSGDUMP, hexdump_prefix, *to_update_field, value_len);
-	resetInternalStateAfterParamsUpdate();
-	return 0;
-}
-
-/**
- * Helper function to set value in a string key field in |wpa_ssid| structue
- * instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setStringKeyFieldAndResetState(
-    const char *value, char **to_update_field, const char *hexdump_prefix)
-{
-	int value_len = strlen(value);
-	if (*to_update_field) {
-		str_clear_free(*to_update_field);
-	}
-	*to_update_field = dup_binstr(value, value_len);
-	if (!(*to_update_field)) {
-		return 1;
-	}
-	wpa_hexdump_ascii_key(
-	    MSG_MSGDUMP, hexdump_prefix, *to_update_field, value_len);
-	resetInternalStateAfterParamsUpdate();
-	return 0;
-}
-
-/**
- * Helper function to set value in a string field with a corresponding length
- * field in |wpa_ssid| structue instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setByteArrayFieldAndResetState(
-    const uint8_t *value, const size_t value_len, uint8_t **to_update_field,
-    size_t *to_update_field_len, const char *hexdump_prefix)
-{
-	if (*to_update_field) {
-		os_free(*to_update_field);
-	}
-	*to_update_field = (uint8_t *)os_malloc(value_len);
-	if (!(*to_update_field)) {
-		return 1;
-	}
-	os_memcpy(*to_update_field, value, value_len);
-	*to_update_field_len = value_len;
-
-	wpa_hexdump_ascii(
-	    MSG_MSGDUMP, hexdump_prefix, *to_update_field,
-	    *to_update_field_len);
-	resetInternalStateAfterParamsUpdate();
-	return 0;
-}
-
-/**
- * Helper function to set value in a string key field with a corresponding
- * length field in |wpa_ssid| structue instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setByteArrayKeyFieldAndResetState(
-    const uint8_t *value, const size_t value_len, uint8_t **to_update_field,
-    size_t *to_update_field_len, const char *hexdump_prefix)
-{
-	if (*to_update_field) {
-		bin_clear_free(*to_update_field, *to_update_field_len);
-	}
-	*to_update_field = (uint8_t *)os_malloc(value_len);
-	if (!(*to_update_field)) {
-		return 1;
-	}
-	os_memcpy(*to_update_field, value, value_len);
-	*to_update_field_len = value_len;
-
-	wpa_hexdump_ascii_key(
-	    MSG_MSGDUMP, hexdump_prefix, *to_update_field,
-	    *to_update_field_len);
-	resetInternalStateAfterParamsUpdate();
-	return 0;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
diff --git a/wpa_supplicant/hidl/1.0/sta_network.h b/wpa_supplicant/hidl/1.0/sta_network.h
deleted file mode 100644
index 6e8d42b..0000000
--- a/wpa_supplicant/hidl/1.0/sta_network.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_STA_NETWORK_H
-#define WPA_SUPPLICANT_HIDL_STA_NETWORK_H
-
-#include <array>
-#include <vector>
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "notify.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "eap_peer/eap.h"
-#include "rsn_supp/wpa.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * Implementation of StaNetwork hidl object. Each unique hidl
- * object is used for control operations on a specific network
- * controlled by wpa_supplicant.
- */
-class StaNetwork : public ISupplicantStaNetwork
-{
-public:
-	StaNetwork(
-	    struct wpa_global* wpa_global, const char ifname[], int network_id);
-	~StaNetwork() override = default;
-	// Refer to |StaIface::invalidate()|.
-	void invalidate();
-	bool isValid();
-
-	// Hidl methods exposed.
-	Return<void> getId(getId_cb _hidl_cb) override;
-	Return<void> getInterfaceName(getInterfaceName_cb _hidl_cb) override;
-	Return<void> getType(getType_cb _hidl_cb) override;
-	Return<void> registerCallback(
-	    const sp<ISupplicantStaNetworkCallback>& callback,
-	    registerCallback_cb _hidl_cb) override;
-	Return<void> setSsid(
-	    const hidl_vec<uint8_t>& ssid, setSsid_cb _hidl_cb) override;
-	Return<void> setBssid(
-	    const hidl_array<uint8_t, 6>& bssid, setBssid_cb _hidl_cb) override;
-	Return<void> setScanSsid(bool enable, setScanSsid_cb _hidl_cb) override;
-	Return<void> setKeyMgmt(
-	    uint32_t key_mgmt_mask, setKeyMgmt_cb _hidl_cb) override;
-	Return<void> setProto(
-	    uint32_t proto_mask, setProto_cb _hidl_cb) override;
-	Return<void> setAuthAlg(
-	    uint32_t auth_alg_mask, setAuthAlg_cb _hidl_cb) override;
-	Return<void> setGroupCipher(
-	    uint32_t group_cipher_mask, setGroupCipher_cb _hidl_cb) override;
-	Return<void> setPairwiseCipher(
-	    uint32_t pairwise_cipher_mask,
-	    setPairwiseCipher_cb _hidl_cb) override;
-	Return<void> setPskPassphrase(
-	    const hidl_string& psk, setPskPassphrase_cb _hidl_cb) override;
-	Return<void> setPsk(
-	    const hidl_array<uint8_t, 32>& psk, setPsk_cb _hidl_cb) override;
-	Return<void> setWepKey(
-	    uint32_t key_idx, const hidl_vec<uint8_t>& wep_key,
-	    setWepKey_cb _hidl_cb) override;
-	Return<void> setWepTxKeyIdx(
-	    uint32_t key_idx, setWepTxKeyIdx_cb _hidl_cb) override;
-	Return<void> setRequirePmf(
-	    bool enable, setRequirePmf_cb _hidl_cb) override;
-	Return<void> setEapMethod(
-	    ISupplicantStaNetwork::EapMethod method,
-	    setEapMethod_cb _hidl_cb) override;
-	Return<void> setEapPhase2Method(
-	    ISupplicantStaNetwork::EapPhase2Method method,
-	    setEapPhase2Method_cb _hidl_cb) override;
-	Return<void> setEapIdentity(
-	    const hidl_vec<uint8_t>& identity,
-	    setEapIdentity_cb _hidl_cb) override;
-	Return<void> setEapAnonymousIdentity(
-	    const hidl_vec<uint8_t>& identity,
-	    setEapAnonymousIdentity_cb _hidl_cb) override;
-	Return<void> setEapPassword(
-	    const hidl_vec<uint8_t>& password,
-	    setEapPassword_cb _hidl_cb) override;
-	Return<void> setEapCACert(
-	    const hidl_string& path, setEapCACert_cb _hidl_cb) override;
-	Return<void> setEapCAPath(
-	    const hidl_string& path, setEapCAPath_cb _hidl_cb) override;
-	Return<void> setEapClientCert(
-	    const hidl_string& path, setEapClientCert_cb _hidl_cb) override;
-	Return<void> setEapPrivateKeyId(
-	    const hidl_string& id, setEapPrivateKeyId_cb _hidl_cb) override;
-	Return<void> setEapSubjectMatch(
-	    const hidl_string& match, setEapSubjectMatch_cb _hidl_cb) override;
-	Return<void> setEapAltSubjectMatch(
-	    const hidl_string& match,
-	    setEapAltSubjectMatch_cb _hidl_cb) override;
-	Return<void> setEapEngine(
-	    bool enable, setEapEngine_cb _hidl_cb) override;
-	Return<void> setEapEngineID(
-	    const hidl_string& id, setEapEngineID_cb _hidl_cb) override;
-	Return<void> setEapDomainSuffixMatch(
-	    const hidl_string& match,
-	    setEapDomainSuffixMatch_cb _hidl_cb) override;
-	Return<void> setProactiveKeyCaching(
-	    bool enable, setProactiveKeyCaching_cb _hidl_cb) override;
-	Return<void> setIdStr(
-	    const hidl_string& id_str, setIdStr_cb _hidl_cb) override;
-	Return<void> setUpdateIdentifier(
-	    uint32_t id, setUpdateIdentifier_cb _hidl_cb) override;
-	Return<void> getSsid(getSsid_cb _hidl_cb) override;
-	Return<void> getBssid(getBssid_cb _hidl_cb) override;
-	Return<void> getScanSsid(getScanSsid_cb _hidl_cb) override;
-	Return<void> getKeyMgmt(getKeyMgmt_cb _hidl_cb) override;
-	Return<void> getProto(getProto_cb _hidl_cb) override;
-	Return<void> getAuthAlg(getAuthAlg_cb _hidl_cb) override;
-	Return<void> getGroupCipher(getGroupCipher_cb _hidl_cb) override;
-	Return<void> getPairwiseCipher(getPairwiseCipher_cb _hidl_cb) override;
-	Return<void> getPskPassphrase(getPskPassphrase_cb _hidl_cb) override;
-	Return<void> getPsk(getPsk_cb _hidl_cb) override;
-	Return<void> getWepKey(
-	    uint32_t key_idx, getWepKey_cb _hidl_cb) override;
-	Return<void> getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb) override;
-	Return<void> getRequirePmf(getRequirePmf_cb _hidl_cb) override;
-	Return<void> getEapMethod(getEapMethod_cb _hidl_cb) override;
-	Return<void> getEapPhase2Method(
-	    getEapPhase2Method_cb _hidl_cb) override;
-	Return<void> getEapIdentity(getEapIdentity_cb _hidl_cb) override;
-	Return<void> getEapAnonymousIdentity(
-	    getEapAnonymousIdentity_cb _hidl_cb) override;
-	Return<void> getEapPassword(getEapPassword_cb _hidl_cb) override;
-	Return<void> getEapCACert(getEapCACert_cb _hidl_cb) override;
-	Return<void> getEapCAPath(getEapCAPath_cb _hidl_cb) override;
-	Return<void> getEapClientCert(getEapClientCert_cb _hidl_cb) override;
-	Return<void> getEapPrivateKeyId(
-	    getEapPrivateKeyId_cb _hidl_cb) override;
-	Return<void> getEapSubjectMatch(
-	    getEapSubjectMatch_cb _hidl_cb) override;
-	Return<void> getEapAltSubjectMatch(
-	    getEapAltSubjectMatch_cb _hidl_cb) override;
-	Return<void> getEapEngine(getEapEngine_cb _hidl_cb) override;
-	Return<void> getEapEngineID(getEapEngineID_cb _hidl_cb) override;
-	Return<void> getEapDomainSuffixMatch(
-	    getEapDomainSuffixMatch_cb _hidl_cb) override;
-	Return<void> getIdStr(getIdStr_cb _hidl_cb) override;
-	Return<void> getWpsNfcConfigurationToken(
-	    getWpsNfcConfigurationToken_cb _hidl_cb) override;
-	Return<void> enable(bool no_connect, enable_cb _hidl_cb) override;
-	Return<void> disable(disable_cb _hidl_cb) override;
-	Return<void> select(select_cb _hidl_cb) override;
-	Return<void> sendNetworkEapSimGsmAuthResponse(
-	    const hidl_vec<
-		ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
-		vec_params,
-	    sendNetworkEapSimGsmAuthResponse_cb _hidl_cb) override;
-	Return<void> sendNetworkEapSimGsmAuthFailure(
-	    sendNetworkEapSimGsmAuthFailure_cb _hidl_cb) override;
-	Return<void> sendNetworkEapSimUmtsAuthResponse(
-	    const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
-		params,
-	    sendNetworkEapSimUmtsAuthResponse_cb _hidl_cb) override;
-	Return<void> sendNetworkEapSimUmtsAutsResponse(
-	    const hidl_array<uint8_t, 14>& auts,
-	    sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb) override;
-	Return<void> sendNetworkEapSimUmtsAuthFailure(
-	    sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb) override;
-	Return<void> sendNetworkEapIdentityResponse(
-	    const hidl_vec<uint8_t>& identity,
-	    sendNetworkEapIdentityResponse_cb _hidl_cb) override;
-
-private:
-	// Corresponding worker functions for the HIDL methods.
-	std::pair<SupplicantStatus, uint32_t> getIdInternal();
-	std::pair<SupplicantStatus, std::string> getInterfaceNameInternal();
-	std::pair<SupplicantStatus, IfaceType> getTypeInternal();
-	SupplicantStatus registerCallbackInternal(
-	    const sp<ISupplicantStaNetworkCallback>& callback);
-	SupplicantStatus setSsidInternal(const std::vector<uint8_t>& ssid);
-	SupplicantStatus setBssidInternal(const std::array<uint8_t, 6>& bssid);
-	SupplicantStatus setScanSsidInternal(bool enable);
-	SupplicantStatus setKeyMgmtInternal(uint32_t key_mgmt_mask);
-	SupplicantStatus setProtoInternal(uint32_t proto_mask);
-	SupplicantStatus setAuthAlgInternal(uint32_t auth_alg_mask);
-	SupplicantStatus setGroupCipherInternal(uint32_t group_cipher_mask);
-	SupplicantStatus setPairwiseCipherInternal(
-	    uint32_t pairwise_cipher_mask);
-	SupplicantStatus setPskPassphraseInternal(const std::string& psk);
-	SupplicantStatus setPskInternal(const std::array<uint8_t, 32>& psk);
-	SupplicantStatus setWepKeyInternal(
-	    uint32_t key_idx, const std::vector<uint8_t>& wep_key);
-	SupplicantStatus setWepTxKeyIdxInternal(uint32_t key_idx);
-	SupplicantStatus setRequirePmfInternal(bool enable);
-	SupplicantStatus setEapMethodInternal(
-	    ISupplicantStaNetwork::EapMethod method);
-	SupplicantStatus setEapPhase2MethodInternal(
-	    ISupplicantStaNetwork::EapPhase2Method method);
-	SupplicantStatus setEapIdentityInternal(
-	    const std::vector<uint8_t>& identity);
-	SupplicantStatus setEapAnonymousIdentityInternal(
-	    const std::vector<uint8_t>& identity);
-	SupplicantStatus setEapPasswordInternal(
-	    const std::vector<uint8_t>& password);
-	SupplicantStatus setEapCACertInternal(const std::string& path);
-	SupplicantStatus setEapCAPathInternal(const std::string& path);
-	SupplicantStatus setEapClientCertInternal(const std::string& path);
-	SupplicantStatus setEapPrivateKeyIdInternal(const std::string& id);
-	SupplicantStatus setEapSubjectMatchInternal(const std::string& match);
-	SupplicantStatus setEapAltSubjectMatchInternal(
-	    const std::string& match);
-	SupplicantStatus setEapEngineInternal(bool enable);
-	SupplicantStatus setEapEngineIDInternal(const std::string& id);
-	SupplicantStatus setEapDomainSuffixMatchInternal(
-	    const std::string& match);
-	SupplicantStatus setProactiveKeyCachingInternal(bool enable);
-	SupplicantStatus setIdStrInternal(const std::string& id_str);
-	SupplicantStatus setUpdateIdentifierInternal(uint32_t id);
-	std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
-	std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
-	std::pair<SupplicantStatus, bool> getScanSsidInternal();
-	std::pair<SupplicantStatus, uint32_t> getKeyMgmtInternal();
-	std::pair<SupplicantStatus, uint32_t> getProtoInternal();
-	std::pair<SupplicantStatus, uint32_t> getAuthAlgInternal();
-	std::pair<SupplicantStatus, uint32_t> getGroupCipherInternal();
-	std::pair<SupplicantStatus, uint32_t> getPairwiseCipherInternal();
-	std::pair<SupplicantStatus, std::string> getPskPassphraseInternal();
-	std::pair<SupplicantStatus, std::array<uint8_t, 32>> getPskInternal();
-	std::pair<SupplicantStatus, std::vector<uint8_t>> getWepKeyInternal(
-	    uint32_t key_idx);
-	std::pair<SupplicantStatus, uint32_t> getWepTxKeyIdxInternal();
-	std::pair<SupplicantStatus, bool> getRequirePmfInternal();
-	std::pair<SupplicantStatus, ISupplicantStaNetwork::EapMethod>
-	getEapMethodInternal();
-	std::pair<SupplicantStatus, ISupplicantStaNetwork::EapPhase2Method>
-	getEapPhase2MethodInternal();
-	std::pair<SupplicantStatus, std::vector<uint8_t>>
-	getEapIdentityInternal();
-	std::pair<SupplicantStatus, std::vector<uint8_t>>
-	getEapAnonymousIdentityInternal();
-	std::pair<SupplicantStatus, std::vector<uint8_t>>
-	getEapPasswordInternal();
-	std::pair<SupplicantStatus, std::string> getEapCACertInternal();
-	std::pair<SupplicantStatus, std::string> getEapCAPathInternal();
-	std::pair<SupplicantStatus, std::string> getEapClientCertInternal();
-	std::pair<SupplicantStatus, std::string> getEapPrivateKeyIdInternal();
-	std::pair<SupplicantStatus, std::string> getEapSubjectMatchInternal();
-	std::pair<SupplicantStatus, std::string>
-	getEapAltSubjectMatchInternal();
-	std::pair<SupplicantStatus, bool> getEapEngineInternal();
-	std::pair<SupplicantStatus, std::string> getEapEngineIDInternal();
-	std::pair<SupplicantStatus, std::string>
-	getEapDomainSuffixMatchInternal();
-	std::pair<SupplicantStatus, std::string> getIdStrInternal();
-	std::pair<SupplicantStatus, std::vector<uint8_t>>
-	getWpsNfcConfigurationTokenInternal();
-	SupplicantStatus enableInternal(bool no_connect);
-	SupplicantStatus disableInternal();
-	SupplicantStatus selectInternal();
-	SupplicantStatus sendNetworkEapSimGsmAuthResponseInternal(
-	    const std::vector<
-		ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
-		vec_params);
-	SupplicantStatus sendNetworkEapSimGsmAuthFailureInternal();
-	SupplicantStatus sendNetworkEapSimUmtsAuthResponseInternal(
-	    const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
-		params);
-	SupplicantStatus sendNetworkEapSimUmtsAutsResponseInternal(
-	    const std::array<uint8_t, 14>& auts);
-	SupplicantStatus sendNetworkEapSimUmtsAuthFailureInternal();
-	SupplicantStatus sendNetworkEapIdentityResponseInternal(
-	    const std::vector<uint8_t>& identity);
-
-	struct wpa_ssid* retrieveNetworkPtr();
-	struct wpa_supplicant* retrieveIfacePtr();
-	int isPskPassphraseValid(const std::string& psk);
-	void resetInternalStateAfterParamsUpdate();
-	int setStringFieldAndResetState(
-	    const char* value, uint8_t** to_update_field,
-	    const char* hexdump_prefix);
-	int setStringFieldAndResetState(
-	    const char* value, char** to_update_field,
-	    const char* hexdump_prefix);
-	int setStringKeyFieldAndResetState(
-	    const char* value, char** to_update_field,
-	    const char* hexdump_prefix);
-	int setByteArrayFieldAndResetState(
-	    const uint8_t* value, const size_t value_len,
-	    uint8_t** to_update_field, size_t* to_update_field_len,
-	    const char* hexdump_prefix);
-	int setByteArrayKeyFieldAndResetState(
-	    const uint8_t* value, const size_t value_len,
-	    uint8_t** to_update_field, size_t* to_update_field_len,
-	    const char* hexdump_prefix);
-
-	// Reference to the global wpa_struct. This is assumed to be valid
-	// for the lifetime of the process.
-	struct wpa_global* wpa_global_;
-	// Name of the iface this network belongs to.
-	const std::string ifname_;
-	// Id of the network this hidl object controls.
-	const int network_id_;
-	bool is_valid_;
-
-	DISALLOW_COPY_AND_ASSIGN(StaNetwork);
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WPA_SUPPLICANT_HIDL_STA_NETWORK_H
diff --git a/wpa_supplicant/hidl/1.0/supplicant.cpp b/wpa_supplicant/hidl/1.0/supplicant.cpp
deleted file mode 100644
index bf009b5..0000000
--- a/wpa_supplicant/hidl/1.0/supplicant.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "supplicant.h"
-
-#include <android-base/file.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-namespace {
-constexpr char kStaIfaceConfPath[] =
-    "/data/misc/wifi/wpa_supplicant.conf";
-constexpr char kP2pIfaceConfPath[] =
-    "/data/misc/wifi/p2p_supplicant.conf";
-// Migrate conf files for existing devices.
-constexpr char kTemplateConfPath[] =
-    "/vendor/etc/wifi/wpa_supplicant.conf";
-constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
-
-int copyFile(
-    const std::string& src_file_path, const std::string& dest_file_path)
-{
-	std::string file_contents;
-	if (!android::base::ReadFileToString(src_file_path, &file_contents)) {
-		wpa_printf(
-		    MSG_ERROR, "Failed to read from %s. Errno: %s",
-		    src_file_path.c_str(), strerror(errno));
-		return -1;
-	}
-	if (!android::base::WriteStringToFile(
-		file_contents, dest_file_path, kConfigFileMode, getuid(),
-		getgid())) {
-		wpa_printf(
-		    MSG_ERROR, "Failed to write to %s. Errno: %s",
-		    dest_file_path.c_str(), strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-/**
- * Copy |src_file_path| to |dest_file_path| if it exists.
- *
- * Returns 1 if |src_file_path| does not exists,
- * Returns -1 if the copy fails.
- * Returns 0 if the copy succeeds.
- */
-int copyFileIfItExists(
-    const std::string& src_file_path, const std::string& dest_file_path)
-{
-	int ret = access(src_file_path.c_str(), R_OK);
-	if ((ret != 0) && (errno == ENOENT)) {
-		return 1;
-	}
-	ret = copyFile(src_file_path, dest_file_path);
-	if (ret != 0) {
-		wpa_printf(
-		    MSG_ERROR, "Failed copying %s to %s.",
-		    src_file_path.c_str(), dest_file_path.c_str());
-		return -1;
-	}
-	return 0;
-}
-
-/**
- * Ensure that the specified config file pointed by |config_file_path| exists.
- * a) If the |config_file_path| exists with the correct permissions, return.
- * b) If the |config_file_path| does not exists, copy over the contents of
- * |template_config_file_path|.
- */
-int copyTemplateConfigFileIfNotExists(
-    const std::string& config_file_path,
-    const std::string& template_config_file_path)
-{
-	int ret = access(config_file_path.c_str(), R_OK | W_OK);
-	if (ret == 0) {
-		return 0;
-	}
-	if (errno == EACCES) {
-		ret = chmod(config_file_path.c_str(), kConfigFileMode);
-		if (ret == 0) {
-			return 0;
-		} else {
-			wpa_printf(
-			    MSG_ERROR, "Cannot set RW to %s. Errno: %s",
-			    config_file_path.c_str(), strerror(errno));
-			return -1;
-		}
-	} else if (errno != ENOENT) {
-		wpa_printf(
-		    MSG_ERROR, "Cannot acces %s. Errno: %s",
-		    config_file_path.c_str(), strerror(errno));
-		return -1;
-	}
-	ret = copyFileIfItExists(template_config_file_path, config_file_path);
-	if (ret == 0) {
-		wpa_printf(
-		    MSG_INFO, "Copied template conf file from %s to %s",
-		    template_config_file_path.c_str(), config_file_path.c_str());
-		return 0;
-	} else if (ret == -1) {
-		unlink(config_file_path.c_str());
-		return -1;
-	}
-	// Did not create the conf file.
-	return -1;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-// These are hardcoded for android.
-const char Supplicant::kDriverName[] = "nl80211";
-const char Supplicant::kConfigFilePath[] =
-    "/data/misc/wifi/wpa_supplicant.conf";
-
-Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {}
-bool Supplicant::isValid()
-{
-	// This top level object cannot be invalidated.
-	return true;
-}
-
-bool Supplicant::ensureConfigFileExists()
-{
-	// To support Android P Wifi framework, make sure the config file exists.
-	if (copyTemplateConfigFileIfNotExists(
-		kStaIfaceConfPath, kTemplateConfPath) != 0) {
-		wpa_printf(MSG_ERROR, "Conf file does not exists: %s",
-		    kStaIfaceConfPath);
-		return false;
-	}
-	// P2P configuration file is not madatory but required for some devices.
-	if (copyTemplateConfigFileIfNotExists(
-		kP2pIfaceConfPath, kTemplateConfPath) != 0) {
-		wpa_printf(MSG_INFO, "Conf file does not exists: %s",
-		    kP2pIfaceConfPath);
-	}
-	return true;
-}
-
-Return<void> Supplicant::getInterface(
-    const IfaceInfo& iface_info, getInterface_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &Supplicant::getInterfaceInternal, _hidl_cb, iface_info);
-}
-
-Return<void> Supplicant::listInterfaces(listInterfaces_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &Supplicant::listInterfacesInternal, _hidl_cb);
-}
-
-Return<void> Supplicant::registerCallback(
-    const sp<ISupplicantCallback>& callback, registerCallback_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &Supplicant::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> Supplicant::setDebugParams(
-    ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys,
-    setDebugParams_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &Supplicant::setDebugParamsInternal, _hidl_cb, level,
-	    show_timestamp, show_keys);
-}
-
-Return<void> Supplicant::setConcurrencyPriority(
-    IfaceType type, setConcurrencyPriority_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &Supplicant::setConcurrencyPriorityInternal, _hidl_cb, type);
-}
-
-Return<ISupplicant::DebugLevel> Supplicant::getDebugLevel()
-{
-	// TODO: Add SupplicantStatus in this method return for uniformity with
-	// the other methods in supplicant HIDL interface.
-	return (ISupplicant::DebugLevel)wpa_debug_level;
-}
-
-Return<bool> Supplicant::isDebugShowTimestampEnabled()
-{
-	// TODO: Add SupplicantStatus in this method return for uniformity with
-	// the other methods in supplicant HIDL interface.
-	return ((wpa_debug_timestamp != 0) ? true : false);
-}
-
-Return<bool> Supplicant::isDebugShowKeysEnabled()
-{
-	// TODO: Add SupplicantStatus in this method return for uniformity with
-	// the other methods in supplicant HIDL interface.
-	return ((wpa_debug_show_keys != 0) ? true : false);
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantIface>>
-Supplicant::getInterfaceInternal(const IfaceInfo& iface_info)
-{
-	struct wpa_supplicant* wpa_s =
-	    wpa_supplicant_get_iface(wpa_global_, iface_info.name.c_str());
-	if (!wpa_s) {
-		return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""},
-			nullptr};
-	}
-	HidlManager* hidl_manager = HidlManager::getInstance();
-	if (iface_info.type == IfaceType::P2P) {
-		android::sp<ISupplicantP2pIface> iface;
-		if (!hidl_manager ||
-		    hidl_manager->getP2pIfaceHidlObjectByIfname(
-			wpa_s->ifname, &iface)) {
-			return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
-				iface};
-		}
-		// Set this flag true here, since there is no HIDL initialize method for the p2p
-		// config, and the supplicant interface is not ready when the p2p iface is created.
-		wpa_s->conf->persistent_reconnect = true;
-		return {{SupplicantStatusCode::SUCCESS, ""}, iface};
-	} else {
-		android::sp<ISupplicantStaIface> iface;
-		if (!hidl_manager ||
-		    hidl_manager->getStaIfaceHidlObjectByIfname(
-			wpa_s->ifname, &iface)) {
-			return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
-				iface};
-		}
-		return {{SupplicantStatusCode::SUCCESS, ""}, iface};
-	}
-}
-
-std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>>
-Supplicant::listInterfacesInternal()
-{
-	std::vector<ISupplicant::IfaceInfo> ifaces;
-	for (struct wpa_supplicant* wpa_s = wpa_global_->ifaces; wpa_s;
-	     wpa_s = wpa_s->next) {
-		if (wpa_s->global->p2p_init_wpa_s == wpa_s) {
-			ifaces.emplace_back(ISupplicant::IfaceInfo{
-			    IfaceType::P2P, wpa_s->ifname});
-		} else {
-			ifaces.emplace_back(ISupplicant::IfaceInfo{
-			    IfaceType::STA, wpa_s->ifname});
-		}
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ifaces)};
-}
-
-SupplicantStatus Supplicant::registerCallbackInternal(
-    const sp<ISupplicantCallback>& callback)
-{
-	HidlManager* hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->addSupplicantCallbackHidlObject(callback)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus Supplicant::setDebugParamsInternal(
-    ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys)
-{
-	if (wpa_supplicant_set_debug_params(
-		wpa_global_, static_cast<uint32_t>(level), show_timestamp,
-		show_keys)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus Supplicant::setConcurrencyPriorityInternal(IfaceType type)
-{
-	if (type == IfaceType::STA) {
-		wpa_global_->conc_pref =
-		    wpa_global::wpa_conc_pref::WPA_CONC_PREF_STA;
-	} else if (type == IfaceType::P2P) {
-		wpa_global_->conc_pref =
-		    wpa_global::wpa_conc_pref::WPA_CONC_PREF_P2P;
-	} else {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
-}
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
diff --git a/wpa_supplicant/hidl/1.0/supplicant.h b/wpa_supplicant/hidl/1.0/supplicant.h
deleted file mode 100644
index 04d1ae1..0000000
--- a/wpa_supplicant/hidl/1.0/supplicant.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_SUPPLICANT_H
-#define WPA_SUPPLICANT_HIDL_SUPPLICANT_H
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicant.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantIface.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "utils/wpa_debug.h"
-#include "wpa_supplicant_i.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-/**
- * Implementation of the supplicant hidl object. This hidl
- * object is used core for global control operations on
- * wpa_supplicant.
- */
-class Supplicant : public android::hardware::wifi::supplicant::V1_0::ISupplicant
-{
-public:
-	Supplicant(struct wpa_global* global);
-	~Supplicant() override = default;
-	bool isValid();
-	bool ensureConfigFileExists();
-
-	// Hidl methods exposed.
-	Return<void> getInterface(
-	    const IfaceInfo& iface_info, getInterface_cb _hidl_cb) override;
-	Return<void> listInterfaces(listInterfaces_cb _hidl_cb) override;
-	Return<void> registerCallback(
-	    const sp<ISupplicantCallback>& callback,
-	    registerCallback_cb _hidl_cb) override;
-	Return<void> setDebugParams(
-	    ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys,
-	    setDebugParams_cb _hidl_cb) override;
-	Return<ISupplicant::DebugLevel> getDebugLevel() override;
-	Return<bool> isDebugShowTimestampEnabled() override;
-	Return<bool> isDebugShowKeysEnabled() override;
-	Return<void> setConcurrencyPriority(
-	    IfaceType type, setConcurrencyPriority_cb _hidl_cb) override;
-
-private:
-	// Corresponding worker functions for the HIDL methods.
-	std::pair<SupplicantStatus, sp<ISupplicantIface>> getInterfaceInternal(
-	    const IfaceInfo& iface_info);
-	std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>>
-	listInterfacesInternal();
-	SupplicantStatus registerCallbackInternal(
-	    const sp<ISupplicantCallback>& callback);
-	SupplicantStatus setDebugParamsInternal(
-	    ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys);
-	SupplicantStatus setConcurrencyPriorityInternal(IfaceType type);
-
-	// Raw pointer to the global structure maintained by the core.
-	struct wpa_global* wpa_global_;
-	// Driver name to be used for creating interfaces.
-	static const char kDriverName[];
-	// wpa_supplicant.conf file location on the device.
-	static const char kConfigFilePath[];
-
-	DISALLOW_COPY_AND_ASSIGN(Supplicant);
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WPA_SUPPLICANT_HIDL_SUPPLICANT_H
diff --git a/wpa_supplicant/hidl/1.1/hidl.h b/wpa_supplicant/hidl/1.1/hidl.h
deleted file mode 100644
index 1dfadc6..0000000
--- a/wpa_supplicant/hidl/1.1/hidl.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_H
-#define WPA_SUPPLICANT_HIDL_HIDL_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif  // _cplusplus
-
-/**
- * This is the hidl RPC interface entry point to the wpa_supplicant core.
- * This initializes the hidl driver & HidlManager instance and then forwards
- * all the notifcations from the supplicant core to the HidlManager.
- */
-struct wpas_hidl_priv;
-struct wpa_global;
-
-struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global);
-void wpas_hidl_deinit(struct wpas_hidl_priv *priv);
-
-#ifdef CONFIG_CTRL_IFACE_HIDL
-int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_register_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_unregister_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s);
-int wpas_hidl_notify_network_request(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
-    enum wpa_ctrl_req_type rtype, const char *default_txt);
-void wpas_hidl_notify_anqp_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
-    const struct wpa_bss_anqp *anqp);
-void wpas_hidl_notify_hs20_icon_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
-    const u8 *image, u32 image_length);
-void wpas_hidl_notify_hs20_rx_subscription_remediation(
-    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
-void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
-    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url);
-void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_fail(
-    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
-    uint16_t error_indication);
-void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_device_found(
-    struct wpa_supplicant *wpa_s, const u8 *addr,
-    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
-    u8 peer_wfd_device_info_len);
-void wpas_hidl_notify_p2p_device_lost(
-    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
-void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_go_neg_req(
-    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
-    u8 go_intent);
-void wpas_hidl_notify_p2p_go_neg_completed(
-    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
-void wpas_hidl_notify_p2p_group_formation_failure(
-    struct wpa_supplicant *wpa_s, const char *reason);
-void wpas_hidl_notify_p2p_group_started(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
-    int client);
-void wpas_hidl_notify_p2p_group_removed(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
-    const char *role);
-void wpas_hidl_notify_p2p_invitation_received(
-    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
-    const u8 *bssid, int id, int op_freq);
-void wpas_hidl_notify_p2p_invitation_result(
-    struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
-void wpas_hidl_notify_p2p_provision_discovery(
-    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
-    enum p2p_prov_disc_status status, u16 config_methods,
-    unsigned int generated_pin);
-void wpas_hidl_notify_p2p_sd_response(
-    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
-    const u8 *tlvs, size_t tlvs_len);
-void wpas_hidl_notify_ap_sta_authorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-void wpas_hidl_notify_ap_sta_deauthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-void wpas_hidl_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code);
-#else   // CONFIG_CTRL_IFACE_HIDL
-static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-static inline int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-static inline int wpas_hidl_register_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	return 0;
-}
-static inline int wpas_hidl_unregister_network(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	return 0;
-}
-static inline int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-static inline int wpas_hidl_notify_network_request(
-    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
-    enum wpa_ctrl_req_type rtype, const char *default_txt)
-{
-	return 0;
-}
-static void wpas_hidl_notify_anqp_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
-    const struct wpa_bss_anqp *anqp)
-{
-}
-static void wpas_hidl_notify_hs20_icon_query_done(
-    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
-    const u8 *image, u32 image_length)
-{
-}
-static void wpas_hidl_notify_hs20_rx_subscription_remediation(
-    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
-}
-static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
-    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
-{
-}
-static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_fail(
-    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
-    uint16_t error_indication)
-{
-}
-static void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
-{
-}
-static void wpas_hidl_notify_p2p_device_found(
-    struct wpa_supplicant *wpa_s, const u8 *addr,
-    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
-    u8 peer_wfd_device_info_len);
-{
-}
-static void wpas_hidl_notify_p2p_device_lost(
-    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
-}
-static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_p2p_go_neg_req(
-    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
-    u8 go_intent)
-{
-}
-static void wpas_hidl_notify_p2p_go_neg_completed(
-    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
-}
-static void wpas_hidl_notify_p2p_group_formation_failure(
-    struct wpa_supplicant *wpa_s, const char *reason)
-{
-}
-static void wpas_hidl_notify_p2p_group_started(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
-    int client)
-{
-}
-static void wpas_hidl_notify_p2p_group_removed(
-    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_received(
-    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
-    const u8 *bssid, int id, int op_freq)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_result(
-    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
-}
-static void wpas_hidl_notify_p2p_provision_discovery(
-    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
-    enum p2p_prov_disc_status status, u16 config_methods,
-    unsigned int generated_pin)
-{
-}
-static void wpas_hidl_notify_p2p_sd_response(
-    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
-    const u8 *tlvs, size_t tlvs_len)
-{
-}
-static void wpas_hidl_notify_ap_sta_authorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-static void wpas_hidl_notify_ap_sta_deauthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-static void wpas_hidl_notify_eap_error(
-    struct wpa_supplicant *wpa_s, int error_code)
-{
-}
-#endif  // CONFIG_CTRL_IFACE_HIDL
-
-#ifdef _cplusplus
-}
-#endif  // _cplusplus
-
-#endif  // WPA_SUPPLICANT_HIDL_HIDL_H
diff --git a/wpa_supplicant/hidl/1.1/hidl_constants.h b/wpa_supplicant/hidl/1.1/hidl_constants.h
deleted file mode 100644
index 988a590..0000000
--- a/wpa_supplicant/hidl/1.1/hidl_constants.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H
-#define WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H
-
-namespace wpa_supplicant_hidl {
-namespace hidl_constants {
-
-extern const char kServiceName[];
-
-} /* namespace hidl_constants */
-} /* namespace wpa_supplicant_hidl */
-
-#endif /* WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H */
diff --git a/wpa_supplicant/hidl/1.1/hidl_i.h b/wpa_supplicant/hidl/1.1/hidl_i.h
deleted file mode 100644
index c7a0142..0000000
--- a/wpa_supplicant/hidl/1.1/hidl_i.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef HIDL_I_H
-#define HIDL_I_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif  // _cplusplus
-
-struct wpas_hidl_priv
-{
-	int hidl_fd;
-	struct wpa_global *global;
-	void *hidl_manager;
-};
-
-#ifdef _cplusplus
-}
-#endif  // _cplusplus
-
-#endif  // HIDL_I_H
diff --git a/wpa_supplicant/hidl/1.1/iface_config_utils.cpp b/wpa_supplicant/hidl/1.1/iface_config_utils.cpp
deleted file mode 100644
index 7fe6d19..0000000
--- a/wpa_supplicant/hidl/1.1/iface_config_utils.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Jouni Malinen
- * <j@w1.fi>
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Roshan Pius
- * <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "iface_config_utils.h"
-
-namespace {
-constexpr uint32_t kMaxWpsDeviceNameSize = WPS_DEV_NAME_MAX_LEN;
-constexpr uint32_t kMaxWpsManufacturerSize = WPS_MANUFACTURER_MAX_LEN;
-constexpr uint32_t kMaxWpsModelNameSize = WPS_MODEL_NAME_MAX_LEN;
-constexpr uint32_t kMaxWpsModelNumberSize = WPS_MODEL_NUMBER_MAX_LEN;
-constexpr uint32_t kMaxWpsSerialNumberSize = WPS_SERIAL_NUMBER_MAX_LEN;
-
-void processConfigUpdate(struct wpa_supplicant* wpa_s, uint32_t changed_param)
-{
-	wpa_s->conf->changed_parameters |= changed_param;
-	wpa_supplicant_update_config(wpa_s);
-}
-
-// Free any existing pointer stored in |dst| and store the provided string value
-// there.
-int freeAndSetStringConfigParam(
-    struct wpa_supplicant* wpa_s, const std::string& value, uint32_t max_size,
-    uint32_t changed_param, char** dst)
-{
-	if (value.size() > max_size) {
-		return -1;
-	}
-	WPA_ASSERT(dst);
-	os_free(static_cast<void*>(*dst));
-	*dst = os_strdup(value.c_str());
-	processConfigUpdate(wpa_s, changed_param);
-	return 0;
-}
-
-std::string convertWpsConfigMethodsMaskToString(uint16_t config_methods)
-{
-	using WpsConfigMethods =
-	    android::hardware::wifi::supplicant::V1_0::WpsConfigMethods;
-	std::string config_methods_str;
-	for (const auto& flag_and_name :
-	     {std::make_pair(WpsConfigMethods::USBA, "usba"),
-	      {WpsConfigMethods::ETHERNET, "ethernet"},
-	      {WpsConfigMethods::LABEL, "label"},
-	      {WpsConfigMethods::DISPLAY, "display"},
-	      {WpsConfigMethods::INT_NFC_TOKEN, "int_nfc_token"},
-	      {WpsConfigMethods::EXT_NFC_TOKEN, "ext_nfc_token"},
-	      {WpsConfigMethods::NFC_INTERFACE, "nfc_interface"},
-	      {WpsConfigMethods::PUSHBUTTON, "push_button"},
-	      {WpsConfigMethods::KEYPAD, "keypad"},
-	      {WpsConfigMethods::VIRT_PUSHBUTTON, "virtual_push_button"},
-	      {WpsConfigMethods::PHY_PUSHBUTTON, "physical_push_button"},
-	      {WpsConfigMethods::P2PS, "p2ps"},
-	      {WpsConfigMethods::VIRT_DISPLAY, "virtual_display"},
-	      {WpsConfigMethods::PHY_DISPLAY, "physical_display"}}) {
-		const auto flag =
-		    static_cast<std::underlying_type<WpsConfigMethods>::type>(
-			flag_and_name.first);
-		if ((config_methods & flag) == flag) {
-			config_methods_str += flag_and_name.second;
-			config_methods_str += " ";
-		}
-	}
-	return config_methods_str;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-namespace iface_config_utils {
-SupplicantStatus setWpsDeviceName(
-    struct wpa_supplicant* wpa_s, const std::string& name)
-{
-	WPA_ASSERT(wpa_s);
-	if (freeAndSetStringConfigParam(
-		wpa_s, name, kMaxWpsDeviceNameSize, CFG_CHANGED_DEVICE_NAME,
-		&wpa_s->conf->device_name)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsDeviceType(
-    struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type)
-{
-	WPA_ASSERT(wpa_s);
-	WPA_ASSERT(type.size() == WPS_DEV_TYPE_LEN);
-	os_memcpy(wpa_s->conf->device_type, type.data(), WPS_DEV_TYPE_LEN);
-	processConfigUpdate(wpa_s, CFG_CHANGED_DEVICE_TYPE);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsManufacturer(
-    struct wpa_supplicant* wpa_s, const std::string& manufacturer)
-{
-	WPA_ASSERT(wpa_s);
-	if (freeAndSetStringConfigParam(
-		wpa_s, manufacturer, kMaxWpsManufacturerSize,
-		CFG_CHANGED_WPS_STRING, &wpa_s->conf->manufacturer)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsModelName(
-    struct wpa_supplicant* wpa_s, const std::string& model_name)
-{
-	WPA_ASSERT(wpa_s);
-	if (freeAndSetStringConfigParam(
-		wpa_s, model_name, kMaxWpsModelNameSize, CFG_CHANGED_WPS_STRING,
-		&wpa_s->conf->model_name)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsModelNumber(
-    struct wpa_supplicant* wpa_s, const std::string& model_number)
-{
-	WPA_ASSERT(wpa_s);
-	if (freeAndSetStringConfigParam(
-		wpa_s, model_number, kMaxWpsModelNumberSize,
-		CFG_CHANGED_WPS_STRING, &wpa_s->conf->model_number)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsSerialNumber(
-    struct wpa_supplicant* wpa_s, const std::string& serial_number)
-{
-	WPA_ASSERT(wpa_s);
-	if (freeAndSetStringConfigParam(
-		wpa_s, serial_number, kMaxWpsSerialNumberSize,
-		CFG_CHANGED_WPS_STRING, &wpa_s->conf->serial_number)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsConfigMethods(
-    struct wpa_supplicant* wpa_s, uint16_t config_methods)
-{
-	WPA_ASSERT(wpa_s);
-	if (freeAndSetStringConfigParam(
-		wpa_s, convertWpsConfigMethodsMaskToString(config_methods),
-		UINT32_MAX, CFG_CHANGED_CONFIG_METHODS,
-		&wpa_s->conf->config_methods)) {
-		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setExternalSim(
-    struct wpa_supplicant* wpa_s, bool useExternalSim)
-{
-	WPA_ASSERT(wpa_s);
-	wpa_s->conf->external_sim = useExternalSim ? 1 : 0;
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-}  // namespace iface_config_utils
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
diff --git a/wpa_supplicant/hidl/1.1/iface_config_utils.h b/wpa_supplicant/hidl/1.1/iface_config_utils.h
deleted file mode 100644
index 39f5548..0000000
--- a/wpa_supplicant/hidl/1.1/iface_config_utils.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Jouni Malinen
- * <j@w1.fi>
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Roshan Pius
- * <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
-#define WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
-
-#include <android-base/macros.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-#include "config.h"
-}
-
-/**
- * Utility functions to set various config parameters of an iface via HIDL
- * methods.
- */
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-namespace iface_config_utils {
-SupplicantStatus setWpsDeviceName(
-    struct wpa_supplicant* wpa_s, const std::string& name);
-SupplicantStatus setWpsDeviceType(
-    struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type);
-SupplicantStatus setWpsManufacturer(
-    struct wpa_supplicant* wpa_s, const std::string& manufacturer);
-SupplicantStatus setWpsModelName(
-    struct wpa_supplicant* wpa_s, const std::string& model_name);
-SupplicantStatus setWpsModelNumber(
-    struct wpa_supplicant* wpa_s, const std::string& model_number);
-SupplicantStatus setWpsSerialNumber(
-    struct wpa_supplicant* wpa_s, const std::string& serial_number);
-SupplicantStatus setWpsConfigMethods(
-    struct wpa_supplicant* wpa_s, uint16_t config_methods);
-SupplicantStatus setExternalSim(
-    struct wpa_supplicant* wpa_s, bool useExternalSim);
-}  // namespace iface_config_utils
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
diff --git a/wpa_supplicant/hidl/1.1/p2p_iface.cpp b/wpa_supplicant/hidl/1.1/p2p_iface.cpp
deleted file mode 100644
index 5de383d..0000000
--- a/wpa_supplicant/hidl/1.1/p2p_iface.cpp
+++ /dev/null
@@ -1,1284 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- * Copyright (C) 2017 Sony Mobile Communications Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "iface_config_utils.h"
-#include "misc_utils.h"
-#include "p2p_iface.h"
-
-extern "C" {
-#include "ap.h"
-#include "wps_supplicant.h"
-#include "wifi_display.h"
-}
-
-namespace {
-const char kConfigMethodStrPbc[] = "pbc";
-const char kConfigMethodStrDisplay[] = "display";
-const char kConfigMethodStrKeypad[] = "keypad";
-constexpr char kSetMiracastMode[] = "MIRACAST ";
-constexpr uint8_t kWfdDeviceInfoSubelemId = 0;
-constexpr char kWfdDeviceInfoSubelemLenHexStr[] = "0006";
-
-using android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
-uint8_t convertHidlMiracastModeToInternal(
-    ISupplicantP2pIface::MiracastMode mode)
-{
-	switch (mode) {
-	case ISupplicantP2pIface::MiracastMode::DISABLED:
-		return 0;
-	case ISupplicantP2pIface::MiracastMode::SOURCE:
-		return 1;
-	case ISupplicantP2pIface::MiracastMode::SINK:
-		return 2;
-	};
-	WPA_ASSERT(false);
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-P2pIface::P2pIface(struct wpa_global* wpa_global, const char ifname[])
-    : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
-
-void P2pIface::invalidate() { is_valid_ = false; }
-bool P2pIface::isValid()
-{
-	return (is_valid_ && (retrieveIfacePtr() != nullptr));
-}
-Return<void> P2pIface::getName(getName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::getNameInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::getType(getType_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::getTypeInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::addNetwork(addNetwork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::addNetworkInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::removeNetwork(
-    SupplicantNetworkId id, removeNetwork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::removeNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> P2pIface::getNetwork(
-    SupplicantNetworkId id, getNetwork_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::getNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> P2pIface::listNetworks(listNetworks_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::listNetworksInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::registerCallback(
-    const sp<ISupplicantP2pIfaceCallback>& callback,
-    registerCallback_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> P2pIface::getDeviceAddress(getDeviceAddress_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::getDeviceAddressInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::setSsidPostfix(
-    const hidl_vec<uint8_t>& postfix, setSsidPostfix_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setSsidPostfixInternal, _hidl_cb, postfix);
-}
-
-Return<void> P2pIface::setGroupIdle(
-    const hidl_string& group_ifname, uint32_t timeout_in_sec,
-    setGroupIdle_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setGroupIdleInternal, _hidl_cb, group_ifname,
-	    timeout_in_sec);
-}
-
-Return<void> P2pIface::setPowerSave(
-    const hidl_string& group_ifname, bool enable, setPowerSave_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setPowerSaveInternal, _hidl_cb, group_ifname, enable);
-}
-
-Return<void> P2pIface::find(uint32_t timeout_in_sec, find_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::findInternal, _hidl_cb, timeout_in_sec);
-}
-
-Return<void> P2pIface::stopFind(stopFind_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::stopFindInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::flush(flush_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::flushInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::connect(
-    const hidl_array<uint8_t, 6>& peer_address,
-    ISupplicantP2pIface::WpsProvisionMethod provision_method,
-    const hidl_string& pre_selected_pin, bool join_existing_group,
-    bool persistent, uint32_t go_intent, connect_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::connectInternal, _hidl_cb, peer_address,
-	    provision_method, pre_selected_pin, join_existing_group, persistent,
-	    go_intent);
-}
-
-Return<void> P2pIface::cancelConnect(cancelConnect_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::cancelConnectInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::provisionDiscovery(
-    const hidl_array<uint8_t, 6>& peer_address,
-    ISupplicantP2pIface::WpsProvisionMethod provision_method,
-    provisionDiscovery_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::provisionDiscoveryInternal, _hidl_cb, peer_address,
-	    provision_method);
-}
-
-Return<void> P2pIface::addGroup(
-    bool persistent, SupplicantNetworkId persistent_network_id,
-    addGroup_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::addGroupInternal, _hidl_cb, persistent,
-	    persistent_network_id);
-}
-
-Return<void> P2pIface::removeGroup(
-    const hidl_string& group_ifname, removeGroup_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::removeGroupInternal, _hidl_cb, group_ifname);
-}
-
-Return<void> P2pIface::reject(
-    const hidl_array<uint8_t, 6>& peer_address, reject_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::rejectInternal, _hidl_cb, peer_address);
-}
-
-Return<void> P2pIface::invite(
-    const hidl_string& group_ifname,
-    const hidl_array<uint8_t, 6>& go_device_address,
-    const hidl_array<uint8_t, 6>& peer_address, invite_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::inviteInternal, _hidl_cb, group_ifname,
-	    go_device_address, peer_address);
-}
-
-Return<void> P2pIface::reinvoke(
-    SupplicantNetworkId persistent_network_id,
-    const hidl_array<uint8_t, 6>& peer_address, reinvoke_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::reinvokeInternal, _hidl_cb, persistent_network_id,
-	    peer_address);
-}
-
-Return<void> P2pIface::configureExtListen(
-    uint32_t period_in_millis, uint32_t interval_in_millis,
-    configureExtListen_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::configureExtListenInternal, _hidl_cb, period_in_millis,
-	    interval_in_millis);
-}
-
-Return<void> P2pIface::setListenChannel(
-    uint32_t channel, uint32_t operating_class, setListenChannel_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setListenChannelInternal, _hidl_cb, channel,
-	    operating_class);
-}
-
-Return<void> P2pIface::setDisallowedFrequencies(
-    const hidl_vec<FreqRange>& ranges, setDisallowedFrequencies_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setDisallowedFrequenciesInternal, _hidl_cb, ranges);
-}
-
-Return<void> P2pIface::getSsid(
-    const hidl_array<uint8_t, 6>& peer_address, getSsid_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::getSsidInternal, _hidl_cb, peer_address);
-}
-
-Return<void> P2pIface::getGroupCapability(
-    const hidl_array<uint8_t, 6>& peer_address, getGroupCapability_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::getGroupCapabilityInternal, _hidl_cb, peer_address);
-}
-
-Return<void> P2pIface::addBonjourService(
-    const hidl_vec<uint8_t>& query, const hidl_vec<uint8_t>& response,
-    addBonjourService_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::addBonjourServiceInternal, _hidl_cb, query, response);
-}
-
-Return<void> P2pIface::removeBonjourService(
-    const hidl_vec<uint8_t>& query, removeBonjourService_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::removeBonjourServiceInternal, _hidl_cb, query);
-}
-
-Return<void> P2pIface::addUpnpService(
-    uint32_t version, const hidl_string& service_name,
-    addUpnpService_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::addUpnpServiceInternal, _hidl_cb, version, service_name);
-}
-
-Return<void> P2pIface::removeUpnpService(
-    uint32_t version, const hidl_string& service_name,
-    removeUpnpService_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::removeUpnpServiceInternal, _hidl_cb, version,
-	    service_name);
-}
-
-Return<void> P2pIface::flushServices(flushServices_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::flushServicesInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::requestServiceDiscovery(
-    const hidl_array<uint8_t, 6>& peer_address, const hidl_vec<uint8_t>& query,
-    requestServiceDiscovery_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::requestServiceDiscoveryInternal, _hidl_cb, peer_address,
-	    query);
-}
-
-Return<void> P2pIface::cancelServiceDiscovery(
-    uint64_t identifier, cancelServiceDiscovery_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::cancelServiceDiscoveryInternal, _hidl_cb, identifier);
-}
-
-Return<void> P2pIface::setMiracastMode(
-    ISupplicantP2pIface::MiracastMode mode, setMiracastMode_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setMiracastModeInternal, _hidl_cb, mode);
-}
-
-Return<void> P2pIface::startWpsPbc(
-    const hidl_string& group_ifname, const hidl_array<uint8_t, 6>& bssid,
-    startWpsPbc_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::startWpsPbcInternal, _hidl_cb, group_ifname, bssid);
-}
-
-Return<void> P2pIface::startWpsPinKeypad(
-    const hidl_string& group_ifname, const hidl_string& pin,
-    startWpsPinKeypad_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::startWpsPinKeypadInternal, _hidl_cb, group_ifname, pin);
-}
-
-Return<void> P2pIface::startWpsPinDisplay(
-    const hidl_string& group_ifname, const hidl_array<uint8_t, 6>& bssid,
-    startWpsPinDisplay_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::startWpsPinDisplayInternal, _hidl_cb, group_ifname,
-	    bssid);
-}
-
-Return<void> P2pIface::cancelWps(
-    const hidl_string& group_ifname, cancelWps_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::cancelWpsInternal, _hidl_cb, group_ifname);
-}
-
-Return<void> P2pIface::setWpsDeviceName(
-    const hidl_string& name, setWpsDeviceName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWpsDeviceNameInternal, _hidl_cb, name);
-}
-
-Return<void> P2pIface::setWpsDeviceType(
-    const hidl_array<uint8_t, 8>& type, setWpsDeviceType_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWpsDeviceTypeInternal, _hidl_cb, type);
-}
-
-Return<void> P2pIface::setWpsManufacturer(
-    const hidl_string& manufacturer, setWpsManufacturer_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWpsManufacturerInternal, _hidl_cb, manufacturer);
-}
-
-Return<void> P2pIface::setWpsModelName(
-    const hidl_string& model_name, setWpsModelName_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWpsModelNameInternal, _hidl_cb, model_name);
-}
-
-Return<void> P2pIface::setWpsModelNumber(
-    const hidl_string& model_number, setWpsModelNumber_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWpsModelNumberInternal, _hidl_cb, model_number);
-}
-
-Return<void> P2pIface::setWpsSerialNumber(
-    const hidl_string& serial_number, setWpsSerialNumber_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWpsSerialNumberInternal, _hidl_cb, serial_number);
-}
-
-Return<void> P2pIface::setWpsConfigMethods(
-    uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWpsConfigMethodsInternal, _hidl_cb, config_methods);
-}
-
-Return<void> P2pIface::enableWfd(bool enable, enableWfd_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::enableWfdInternal, _hidl_cb, enable);
-}
-
-Return<void> P2pIface::setWfdDeviceInfo(
-    const hidl_array<uint8_t, 6>& info, setWfdDeviceInfo_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::setWfdDeviceInfoInternal, _hidl_cb, info);
-}
-
-Return<void> P2pIface::createNfcHandoverRequestMessage(
-    createNfcHandoverRequestMessage_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::createNfcHandoverRequestMessageInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::createNfcHandoverSelectMessage(
-    createNfcHandoverSelectMessage_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::createNfcHandoverSelectMessageInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::reportNfcHandoverResponse(
-    const hidl_vec<uint8_t>& request, reportNfcHandoverResponse_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::reportNfcHandoverResponseInternal, _hidl_cb, request);
-}
-
-Return<void> P2pIface::reportNfcHandoverInitiation(
-    const hidl_vec<uint8_t>& select, reportNfcHandoverInitiation_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::reportNfcHandoverInitiationInternal, _hidl_cb, select);
-}
-
-Return<void> P2pIface::saveConfig(saveConfig_cb _hidl_cb)
-{
-	return validateAndCall(
-	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
-	    &P2pIface::saveConfigInternal, _hidl_cb);
-}
-
-std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> P2pIface::getTypeInternal()
-{
-	return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::P2P};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
-P2pIface::addNetworkInternal()
-{
-	android::sp<ISupplicantP2pNetwork> network;
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	struct wpa_ssid* ssid = wpa_supplicant_add_network(wpa_s);
-	if (!ssid) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
-	}
-	HidlManager* hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->getP2pNetworkHidlObjectByIfnameAndNetworkId(
-		wpa_s->ifname, ssid->id, &network)) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-SupplicantStatus P2pIface::removeNetworkInternal(SupplicantNetworkId id)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	int result = wpa_supplicant_remove_network(wpa_s, id);
-	if (result == -1) {
-		return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
-	}
-	if (result != 0) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
-P2pIface::getNetworkInternal(SupplicantNetworkId id)
-{
-	android::sp<ISupplicantP2pNetwork> network;
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	struct wpa_ssid* ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (!ssid) {
-		return {{SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""},
-			network};
-	}
-	HidlManager* hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->getP2pNetworkHidlObjectByIfnameAndNetworkId(
-		wpa_s->ifname, ssid->id, &network)) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
-P2pIface::listNetworksInternal()
-{
-	std::vector<SupplicantNetworkId> network_ids;
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	for (struct wpa_ssid* wpa_ssid = wpa_s->conf->ssid; wpa_ssid;
-	     wpa_ssid = wpa_ssid->next) {
-		network_ids.emplace_back(wpa_ssid->id);
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, std::move(network_ids)};
-}
-
-SupplicantStatus P2pIface::registerCallbackInternal(
-    const sp<ISupplicantP2pIfaceCallback>& callback)
-{
-	HidlManager* hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->addP2pIfaceCallbackHidlObject(ifname_, callback)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-P2pIface::getDeviceAddressInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	std::array<uint8_t, 6> addr;
-	static_assert(ETH_ALEN == addr.size(), "Size mismatch");
-	os_memcpy(addr.data(), wpa_s->global->p2p_dev_addr, ETH_ALEN);
-	return {{SupplicantStatusCode::SUCCESS, ""}, addr};
-}
-
-SupplicantStatus P2pIface::setSsidPostfixInternal(
-    const std::vector<uint8_t>& postfix)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (p2p_set_ssid_postfix(
-		wpa_s->global->p2p, postfix.data(), postfix.size())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setGroupIdleInternal(
-    const std::string& group_ifname, uint32_t timeout_in_sec)
-{
-	struct wpa_supplicant* wpa_group_s =
-	    retrieveGroupIfacePtr(group_ifname);
-	if (!wpa_group_s) {
-		return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
-	}
-	wpa_group_s->conf->p2p_group_idle = timeout_in_sec;
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setPowerSaveInternal(
-    const std::string& group_ifname, bool enable)
-{
-	struct wpa_supplicant* wpa_group_s =
-	    retrieveGroupIfacePtr(group_ifname);
-	if (!wpa_group_s) {
-		return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
-	}
-	if (wpa_drv_set_p2p_powersave(wpa_group_s, enable, -1, -1)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::findInternal(uint32_t timeout_in_sec)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
-		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
-	}
-	uint32_t search_delay = wpas_p2p_search_delay(wpa_s);
-	if (wpas_p2p_find(
-		wpa_s, timeout_in_sec, P2P_FIND_START_WITH_FULL, 0, nullptr,
-		nullptr, search_delay, 0, nullptr, 0)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::stopFindInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
-		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
-	}
-	wpas_p2p_stop_find(wpa_s);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::flushInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
-	wpa_s->force_long_sd = 0;
-	wpas_p2p_stop_find(wpa_s);
-	wpa_s->parent->p2ps_method_config_any = 0;
-	if (wpa_s->global->p2p)
-		p2p_flush(wpa_s->global->p2p);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-// This method only implements support for subset (needed by Android framework)
-// of parameters that can be specified for connect.
-std::pair<SupplicantStatus, std::string> P2pIface::connectInternal(
-    const std::array<uint8_t, 6>& peer_address,
-    ISupplicantP2pIface::WpsProvisionMethod provision_method,
-    const std::string& pre_selected_pin, bool join_existing_group,
-    bool persistent, uint32_t go_intent)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (go_intent > 15) {
-		return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}};
-	}
-	int go_intent_signed = join_existing_group ? -1 : go_intent;
-	p2p_wps_method wps_method = {};
-	switch (provision_method) {
-	case WpsProvisionMethod::PBC:
-		wps_method = WPS_PBC;
-		break;
-	case WpsProvisionMethod::DISPLAY:
-		wps_method = WPS_PIN_DISPLAY;
-		break;
-	case WpsProvisionMethod::KEYPAD:
-		wps_method = WPS_PIN_KEYPAD;
-		break;
-	}
-	int vht = wpa_s->conf->p2p_go_vht;
-	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
-	const char* pin = pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
-	int new_pin = wpas_p2p_connect(
-	    wpa_s, peer_address.data(), pin, wps_method,
-	    persistent, false, join_existing_group, false, go_intent_signed, 0, 0, -1,
-	    false, ht40, vht, VHT_CHANWIDTH_USE_HT, nullptr, 0);
-	if (new_pin < 0) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	std::string pin_ret;
-	if (provision_method == WpsProvisionMethod::DISPLAY &&
-	    pre_selected_pin.empty()) {
-		pin_ret = misc_utils::convertWpsPinToString(new_pin);
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, pin_ret};
-}
-
-SupplicantStatus P2pIface::cancelConnectInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpas_p2p_cancel(wpa_s)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::provisionDiscoveryInternal(
-    const std::array<uint8_t, 6>& peer_address,
-    ISupplicantP2pIface::WpsProvisionMethod provision_method)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	p2ps_provision* prov_param;
-	const char* config_method_str = nullptr;
-	switch (provision_method) {
-	case WpsProvisionMethod::PBC:
-		config_method_str = kConfigMethodStrPbc;
-		break;
-	case WpsProvisionMethod::DISPLAY:
-		config_method_str = kConfigMethodStrDisplay;
-		break;
-	case WpsProvisionMethod::KEYPAD:
-		config_method_str = kConfigMethodStrKeypad;
-		break;
-	}
-	if (wpas_p2p_prov_disc(
-		wpa_s, peer_address.data(), config_method_str,
-		WPAS_P2P_PD_FOR_GO_NEG, nullptr)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::addGroupInternal(
-    bool persistent, SupplicantNetworkId persistent_network_id)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	int vht = wpa_s->conf->p2p_go_vht;
-	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
-	struct wpa_ssid* ssid =
-	    wpa_config_get_network(wpa_s->conf, persistent_network_id);
-	if (ssid == NULL) {
-		if (wpas_p2p_group_add(
-			wpa_s, persistent, 0, 0, ht40, vht,
-			VHT_CHANWIDTH_USE_HT)) {
-			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-		} else {
-			return {SupplicantStatusCode::SUCCESS, ""};
-		}
-	} else if (ssid->disabled == 2) {
-		if (wpas_p2p_group_add_persistent(
-			wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
-			VHT_CHANWIDTH_USE_HT, NULL, 0, 0)) {
-			return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
-				""};
-		} else {
-			return {SupplicantStatusCode::SUCCESS, ""};
-		}
-	}
-	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-}
-
-SupplicantStatus P2pIface::removeGroupInternal(const std::string& group_ifname)
-{
-	struct wpa_supplicant* wpa_group_s =
-	    retrieveGroupIfacePtr(group_ifname);
-	if (!wpa_group_s) {
-		return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
-	}
-	if (wpas_p2p_group_remove(wpa_group_s, group_ifname.c_str())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::rejectInternal(
-    const std::array<uint8_t, 6>& peer_address)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
-		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
-	}
-	if (wpas_p2p_reject(wpa_s, peer_address.data())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::inviteInternal(
-    const std::string& group_ifname,
-    const std::array<uint8_t, 6>& go_device_address,
-    const std::array<uint8_t, 6>& peer_address)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpas_p2p_invite_group(
-		wpa_s, group_ifname.c_str(), peer_address.data(),
-		go_device_address.data())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::reinvokeInternal(
-    SupplicantNetworkId persistent_network_id,
-    const std::array<uint8_t, 6>& peer_address)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	int vht = wpa_s->conf->p2p_go_vht;
-	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
-	struct wpa_ssid* ssid =
-	    wpa_config_get_network(wpa_s->conf, persistent_network_id);
-	if (ssid == NULL || ssid->disabled != 2) {
-		return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
-	}
-	if (wpas_p2p_invite(
-		wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
-		VHT_CHANWIDTH_USE_HT, 0)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::configureExtListenInternal(
-    uint32_t period_in_millis, uint32_t interval_in_millis)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpas_p2p_ext_listen(wpa_s, period_in_millis, interval_in_millis)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setListenChannelInternal(
-    uint32_t channel, uint32_t operating_class)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (p2p_set_listen_channel(
-		wpa_s->global->p2p, operating_class, channel, 1)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setDisallowedFrequenciesInternal(
-    const std::vector<FreqRange>& ranges)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	using DestT = struct wpa_freq_range_list::wpa_freq_range;
-	DestT* freq_ranges = nullptr;
-	// Empty ranges is used to enable all frequencies.
-	if (ranges.size() != 0) {
-		freq_ranges =
-		    static_cast<DestT*>(os_malloc(sizeof(DestT) * ranges.size()));
-		if (!freq_ranges) {
-			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-		}
-		uint32_t i = 0;
-		for (const auto& range : ranges) {
-			freq_ranges[i].min = range.min;
-			freq_ranges[i].max = range.max;
-			i++;
-		}
-	}
-
-	os_free(wpa_s->global->p2p_disallow_freq.range);
-	wpa_s->global->p2p_disallow_freq.range = freq_ranges;
-	wpa_s->global->p2p_disallow_freq.num = ranges.size();
-	wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> P2pIface::getSsidInternal(
-    const std::array<uint8_t, 6>& peer_address)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	const struct p2p_peer_info* info =
-	    p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
-	if (!info) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	const struct p2p_device* dev =
-	    reinterpret_cast<const struct p2p_device*>(
-		(reinterpret_cast<const uint8_t*>(info)) -
-		offsetof(struct p2p_device, info));
-	std::vector<uint8_t> ssid;
-	if (dev && dev->oper_ssid_len) {
-		ssid.assign(
-		    dev->oper_ssid, dev->oper_ssid + dev->oper_ssid_len);
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, ssid};
-}
-
-std::pair<SupplicantStatus, uint32_t> P2pIface::getGroupCapabilityInternal(
-    const std::array<uint8_t, 6>& peer_address)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	const struct p2p_peer_info* info =
-	    p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
-	if (!info) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, info->group_capab};
-}
-
-SupplicantStatus P2pIface::addBonjourServiceInternal(
-    const std::vector<uint8_t>& query, const std::vector<uint8_t>& response)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	auto query_buf = misc_utils::convertVectorToWpaBuf(query);
-	auto response_buf = misc_utils::convertVectorToWpaBuf(response);
-	if (!query_buf || !response_buf) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	if (wpas_p2p_service_add_bonjour(
-		wpa_s, query_buf.get(), response_buf.get())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	// If successful, the wpabuf is referenced internally and hence should
-	// not be freed.
-	query_buf.release();
-	response_buf.release();
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::removeBonjourServiceInternal(
-    const std::vector<uint8_t>& query)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	auto query_buf = misc_utils::convertVectorToWpaBuf(query);
-	if (!query_buf) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	if (wpas_p2p_service_del_bonjour(wpa_s, query_buf.get())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::addUpnpServiceInternal(
-    uint32_t version, const std::string& service_name)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpas_p2p_service_add_upnp(wpa_s, version, service_name.c_str())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::removeUpnpServiceInternal(
-    uint32_t version, const std::string& service_name)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpas_p2p_service_del_upnp(wpa_s, version, service_name.c_str())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::flushServicesInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	wpas_p2p_service_flush(wpa_s);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, uint64_t> P2pIface::requestServiceDiscoveryInternal(
-    const std::array<uint8_t, 6>& peer_address,
-    const std::vector<uint8_t>& query)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	auto query_buf = misc_utils::convertVectorToWpaBuf(query);
-	if (!query_buf) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	const uint8_t* dst_addr = is_zero_ether_addr(peer_address.data())
-				      ? nullptr
-				      : peer_address.data();
-	uint64_t identifier =
-	    wpas_p2p_sd_request(wpa_s, dst_addr, query_buf.get());
-	if (identifier == 0) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""}, identifier};
-}
-
-SupplicantStatus P2pIface::cancelServiceDiscoveryInternal(uint64_t identifier)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (wpas_p2p_sd_cancel_request(wpa_s, identifier)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setMiracastModeInternal(
-    ISupplicantP2pIface::MiracastMode mode)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	uint8_t mode_internal = convertHidlMiracastModeToInternal(mode);
-	const std::string cmd_str =
-	    kSetMiracastMode + std::to_string(mode_internal);
-	std::vector<char> cmd(
-	    cmd_str.c_str(), cmd_str.c_str() + cmd_str.size() + 1);
-	char driver_cmd_reply_buf[4096] = {};
-	if (wpa_drv_driver_cmd(
-		wpa_s, cmd.data(), driver_cmd_reply_buf,
-		sizeof(driver_cmd_reply_buf))) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::startWpsPbcInternal(
-    const std::string& group_ifname, const std::array<uint8_t, 6>& bssid)
-{
-	struct wpa_supplicant* wpa_group_s =
-	    retrieveGroupIfacePtr(group_ifname);
-	if (!wpa_group_s) {
-		return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
-	}
-	const uint8_t* bssid_addr =
-	    is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
-#ifdef CONFIG_AP
-	if (wpa_group_s->ap_iface) {
-		if (wpa_supplicant_ap_wps_pbc(wpa_group_s, bssid_addr, NULL)) {
-			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-		}
-		return {SupplicantStatusCode::SUCCESS, ""};
-	}
-#endif /* CONFIG_AP */
-	if (wpas_wps_start_pbc(wpa_group_s, bssid_addr, 0)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::startWpsPinKeypadInternal(
-    const std::string& group_ifname, const std::string& pin)
-{
-	struct wpa_supplicant* wpa_group_s =
-	    retrieveGroupIfacePtr(group_ifname);
-	if (!wpa_group_s) {
-		return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
-	}
-#ifdef CONFIG_AP
-	if (wpa_group_s->ap_iface) {
-		if (wpa_supplicant_ap_wps_pin(
-				wpa_group_s, nullptr, pin.c_str(), nullptr, 0, 0) < 0) {
-			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-		}
-		return {SupplicantStatusCode::SUCCESS, ""};
-	}
-#endif /* CONFIG_AP */
-	if (wpas_wps_start_pin(
-		wpa_group_s, nullptr, pin.c_str(), 0, DEV_PW_DEFAULT)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::string> P2pIface::startWpsPinDisplayInternal(
-    const std::string& group_ifname, const std::array<uint8_t, 6>& bssid)
-{
-	struct wpa_supplicant* wpa_group_s =
-	    retrieveGroupIfacePtr(group_ifname);
-	if (!wpa_group_s) {
-		return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""}, ""};
-	}
-	const uint8_t* bssid_addr =
-	    is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
-	int pin = wpas_wps_start_pin(
-	    wpa_group_s, bssid_addr, nullptr, 0, DEV_PW_DEFAULT);
-	if (pin < 0) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, ""};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		misc_utils::convertWpsPinToString(pin)};
-}
-
-SupplicantStatus P2pIface::cancelWpsInternal(const std::string& group_ifname)
-{
-	struct wpa_supplicant* wpa_group_s =
-	    retrieveGroupIfacePtr(group_ifname);
-	if (!wpa_group_s) {
-		return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
-	}
-	if (wpas_wps_cancel(wpa_group_s)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setWpsDeviceNameInternal(const std::string& name)
-{
-	return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
-}
-
-SupplicantStatus P2pIface::setWpsDeviceTypeInternal(
-    const std::array<uint8_t, 8>& type)
-{
-	return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
-}
-
-SupplicantStatus P2pIface::setWpsManufacturerInternal(
-    const std::string& manufacturer)
-{
-	return iface_config_utils::setWpsManufacturer(
-	    retrieveIfacePtr(), manufacturer);
-}
-
-SupplicantStatus P2pIface::setWpsModelNameInternal(
-    const std::string& model_name)
-{
-	return iface_config_utils::setWpsModelName(
-	    retrieveIfacePtr(), model_name);
-}
-
-SupplicantStatus P2pIface::setWpsModelNumberInternal(
-    const std::string& model_number)
-{
-	return iface_config_utils::setWpsModelNumber(
-	    retrieveIfacePtr(), model_number);
-}
-
-SupplicantStatus P2pIface::setWpsSerialNumberInternal(
-    const std::string& serial_number)
-{
-	return iface_config_utils::setWpsSerialNumber(
-	    retrieveIfacePtr(), serial_number);
-}
-
-SupplicantStatus P2pIface::setWpsConfigMethodsInternal(uint16_t config_methods)
-{
-	return iface_config_utils::setWpsConfigMethods(
-	    retrieveIfacePtr(), config_methods);
-}
-
-SupplicantStatus P2pIface::enableWfdInternal(bool enable)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	wifi_display_enable(wpa_s->global, enable);
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setWfdDeviceInfoInternal(
-    const std::array<uint8_t, 6>& info)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	std::vector<char> wfd_device_info_hex(info.size() * 2 + 1);
-	wpa_snprintf_hex(
-	    wfd_device_info_hex.data(), wfd_device_info_hex.size(), info.data(),
-	    info.size());
-	// |wifi_display_subelem_set| expects the first 2 bytes
-	// to hold the lenght of the subelement. In this case it's
-	// fixed to 6, so prepend that.
-	std::string wfd_device_info_set_cmd_str =
-	    std::to_string(kWfdDeviceInfoSubelemId) + " " +
-	    kWfdDeviceInfoSubelemLenHexStr + wfd_device_info_hex.data();
-	std::vector<char> wfd_device_info_set_cmd(
-	    wfd_device_info_set_cmd_str.c_str(),
-	    wfd_device_info_set_cmd_str.c_str() +
-		wfd_device_info_set_cmd_str.size() + 1);
-	if (wifi_display_subelem_set(
-		wpa_s->global, wfd_device_info_set_cmd.data())) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-P2pIface::createNfcHandoverRequestMessageInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	auto buf = misc_utils::createWpaBufUniquePtr(
-	    wpas_p2p_nfc_handover_req(wpa_s, 1));
-	if (!buf) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		misc_utils::convertWpaBufToVector(buf.get())};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-P2pIface::createNfcHandoverSelectMessageInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	auto buf = misc_utils::createWpaBufUniquePtr(
-	    wpas_p2p_nfc_handover_sel(wpa_s, 1, 0));
-	if (!buf) {
-		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
-	}
-	return {{SupplicantStatusCode::SUCCESS, ""},
-		misc_utils::convertWpaBufToVector(buf.get())};
-}
-
-SupplicantStatus P2pIface::reportNfcHandoverResponseInternal(
-    const std::vector<uint8_t>& request)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	auto req = misc_utils::convertVectorToWpaBuf(request);
-	auto sel = misc_utils::convertVectorToWpaBuf(std::vector<uint8_t>{0});
-	if (!req || !sel) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-
-	if (wpas_p2p_nfc_report_handover(wpa_s, 0, req.get(), sel.get(), 0)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::reportNfcHandoverInitiationInternal(
-    const std::vector<uint8_t>& select)
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	auto req = misc_utils::convertVectorToWpaBuf(std::vector<uint8_t>{0});
-	auto sel = misc_utils::convertVectorToWpaBuf(select);
-	if (!req || !sel) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-
-	if (wpas_p2p_nfc_report_handover(wpa_s, 1, req.get(), sel.get(), 0)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::saveConfigInternal()
-{
-	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
-	if (!wpa_s->conf->update_config) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
-		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-	}
-	return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this iface.
- * If the underlying iface is removed, then all RPC method calls on this object
- * will return failure.
- */
-wpa_supplicant* P2pIface::retrieveIfacePtr()
-{
-	return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this group iface.
- */
-wpa_supplicant* P2pIface::retrieveGroupIfacePtr(const std::string& group_ifname)
-{
-	return wpa_supplicant_get_iface(wpa_global_, group_ifname.c_str());
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
diff --git a/wpa_supplicant/hidl/1.1/sta_iface.h b/wpa_supplicant/hidl/1.1/sta_iface.h
deleted file mode 100644
index 1f1e64b..0000000
--- a/wpa_supplicant/hidl/1.1/sta_iface.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_STA_IFACE_H
-#define WPA_SUPPLICANT_HIDL_STA_IFACE_H
-
-#include <array>
-#include <vector>
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-#include "config.h"
-#include "driver_i.h"
-#include "wpa.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-
-/**
- * Implementation of StaIface hidl object. Each unique hidl
- * object is used for control operations on a specific interface
- * controlled by wpa_supplicant.
- */
-class StaIface : public ISupplicantStaIface
-{
-public:
-	StaIface(struct wpa_global* wpa_global, const char ifname[]);
-	~StaIface() override = default;
-	// HIDL does not provide a built-in mechanism to let the server
-	// invalidate a HIDL interface object after creation. If any client
-	// process holds onto a reference to the object in their context,
-	// any method calls on that reference will continue to be directed to
-	// the server.
-	// However Supplicant HAL needs to control the lifetime of these
-	// objects. So, add a public |invalidate| method to all |Iface| and
-	// |Network| objects.
-	// This will be used to mark an object invalid when the corresponding
-	// iface or network is removed.
-	// All HIDL method implementations should check if the object is still
-	// marked valid before processing them.
-	void invalidate();
-	bool isValid();
-
-	// Hidl methods exposed.
-	Return<void> getName(getName_cb _hidl_cb) override;
-	Return<void> getType(getType_cb _hidl_cb) override;
-	Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
-	Return<void> removeNetwork(
-	    SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
-	Return<void> getNetwork(
-	    SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
-	Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
-	Return<void> registerCallback(
-	    const sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback>
-	    & callback, registerCallback_cb _hidl_cb) override;
-	Return<void> registerCallback_1_1(
-	    const sp<ISupplicantStaIfaceCallback>& callback,
-	    registerCallback_cb _hidl_cb) override;
-	Return<void> reassociate(reassociate_cb _hidl_cb) override;
-	Return<void> reconnect(reconnect_cb _hidl_cb) override;
-	Return<void> disconnect(disconnect_cb _hidl_cb) override;
-	Return<void> setPowerSave(
-	    bool enable, setPowerSave_cb _hidl_cb) override;
-	Return<void> initiateTdlsDiscover(
-	    const hidl_array<uint8_t, 6>& mac_address,
-	    initiateTdlsDiscover_cb _hidl_cb) override;
-	Return<void> initiateTdlsSetup(
-	    const hidl_array<uint8_t, 6>& mac_address,
-	    initiateTdlsSetup_cb _hidl_cb) override;
-	Return<void> initiateTdlsTeardown(
-	    const hidl_array<uint8_t, 6>& mac_address,
-	    initiateTdlsTeardown_cb _hidl_cb) override;
-	Return<void> initiateAnqpQuery(
-	    const hidl_array<uint8_t, 6>& mac_address,
-	    const hidl_vec<ISupplicantStaIface::AnqpInfoId>& info_elements,
-	    const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes>& sub_types,
-	    initiateAnqpQuery_cb _hidl_cb) override;
-	Return<void> initiateHs20IconQuery(
-	    const hidl_array<uint8_t, 6>& mac_address,
-	    const hidl_string& file_name,
-	    initiateHs20IconQuery_cb _hidl_cb) override;
-	Return<void> getMacAddress(getMacAddress_cb _hidl_cb) override;
-	Return<void> startRxFilter(startRxFilter_cb _hidl_cb) override;
-	Return<void> stopRxFilter(stopRxFilter_cb _hidl_cb) override;
-	Return<void> addRxFilter(
-	    ISupplicantStaIface::RxFilterType type,
-	    addRxFilter_cb _hidl_cb) override;
-	Return<void> removeRxFilter(
-	    ISupplicantStaIface::RxFilterType type,
-	    removeRxFilter_cb _hidl_cb) override;
-	Return<void> setBtCoexistenceMode(
-	    ISupplicantStaIface::BtCoexistenceMode mode,
-	    setBtCoexistenceMode_cb _hidl_cb) override;
-	Return<void> setBtCoexistenceScanModeEnabled(
-	    bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb) override;
-	Return<void> setSuspendModeEnabled(
-	    bool enable, setSuspendModeEnabled_cb _hidl_cb) override;
-	Return<void> setCountryCode(
-	    const hidl_array<int8_t, 2>& code,
-	    setCountryCode_cb _hidl_cb) override;
-	Return<void> startWpsRegistrar(
-	    const hidl_array<uint8_t, 6>& bssid, const hidl_string& pin,
-	    startWpsRegistrar_cb _hidl_cb) override;
-	Return<void> startWpsPbc(
-	    const hidl_array<uint8_t, 6>& bssid,
-	    startWpsPbc_cb _hidl_cb) override;
-	Return<void> startWpsPinKeypad(
-	    const hidl_string& pin, startWpsPinKeypad_cb _hidl_cb) override;
-	Return<void> startWpsPinDisplay(
-	    const hidl_array<uint8_t, 6>& bssid,
-	    startWpsPinDisplay_cb _hidl_cb) override;
-	Return<void> cancelWps(cancelWps_cb _hidl_cb) override;
-	Return<void> setWpsDeviceName(
-	    const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
-	Return<void> setWpsDeviceType(
-	    const hidl_array<uint8_t, 8>& type,
-	    setWpsDeviceType_cb _hidl_cb) override;
-	Return<void> setWpsManufacturer(
-	    const hidl_string& manufacturer,
-	    setWpsManufacturer_cb _hidl_cb) override;
-	Return<void> setWpsModelName(
-	    const hidl_string& model_name,
-	    setWpsModelName_cb _hidl_cb) override;
-	Return<void> setWpsModelNumber(
-	    const hidl_string& model_number,
-	    setWpsModelNumber_cb _hidl_cb) override;
-	Return<void> setWpsSerialNumber(
-	    const hidl_string& serial_number,
-	    setWpsSerialNumber_cb _hidl_cb) override;
-	Return<void> setWpsConfigMethods(
-	    uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb) override;
-	Return<void> setExternalSim(
-	    bool useExternalSim, setExternalSim_cb _hidl_cb) override;
-	Return<void> addExtRadioWork(
-	    const hidl_string& name, uint32_t freq_in_mhz,
-	    uint32_t timeout_in_sec, addExtRadioWork_cb _hidl_cb) override;
-	Return<void> removeExtRadioWork(
-	    uint32_t id, removeExtRadioWork_cb _hidl_cb) override;
-	Return<void> enableAutoReconnect(
-	    bool enable, enableAutoReconnect_cb _hidl_cb) override;
-
-private:
-	// Corresponding worker functions for the HIDL methods.
-	std::pair<SupplicantStatus, std::string> getNameInternal();
-	std::pair<SupplicantStatus, IfaceType> getTypeInternal();
-	std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
-	addNetworkInternal();
-	SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
-	std::pair<SupplicantStatus, sp<ISupplicantNetwork>> getNetworkInternal(
-	    SupplicantNetworkId id);
-	std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
-	listNetworksInternal();
-	SupplicantStatus registerCallbackInternal(
-	    const sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback>
-	    & callback);
-	SupplicantStatus registerCallbackInternal_1_1(
-	    const sp<ISupplicantStaIfaceCallback>& callback);
-	SupplicantStatus reassociateInternal();
-	SupplicantStatus reconnectInternal();
-	SupplicantStatus disconnectInternal();
-	SupplicantStatus setPowerSaveInternal(bool enable);
-	SupplicantStatus initiateTdlsDiscoverInternal(
-	    const std::array<uint8_t, 6>& mac_address);
-	SupplicantStatus initiateTdlsSetupInternal(
-	    const std::array<uint8_t, 6>& mac_address);
-	SupplicantStatus initiateTdlsTeardownInternal(
-	    const std::array<uint8_t, 6>& mac_address);
-	SupplicantStatus initiateAnqpQueryInternal(
-	    const std::array<uint8_t, 6>& mac_address,
-	    const std::vector<ISupplicantStaIface::AnqpInfoId>& info_elements,
-	    const std::vector<ISupplicantStaIface::Hs20AnqpSubtypes>&
-		sub_types);
-	SupplicantStatus initiateHs20IconQueryInternal(
-	    const std::array<uint8_t, 6>& mac_address,
-	    const std::string& file_name);
-	std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-	getMacAddressInternal();
-	SupplicantStatus startRxFilterInternal();
-	SupplicantStatus stopRxFilterInternal();
-	SupplicantStatus addRxFilterInternal(
-	    ISupplicantStaIface::RxFilterType type);
-	SupplicantStatus removeRxFilterInternal(
-	    ISupplicantStaIface::RxFilterType type);
-	SupplicantStatus setBtCoexistenceModeInternal(
-	    ISupplicantStaIface::BtCoexistenceMode mode);
-	SupplicantStatus setBtCoexistenceScanModeEnabledInternal(bool enable);
-	SupplicantStatus setSuspendModeEnabledInternal(bool enable);
-	SupplicantStatus setCountryCodeInternal(
-	    const std::array<int8_t, 2>& code);
-	SupplicantStatus startWpsRegistrarInternal(
-	    const std::array<uint8_t, 6>& bssid, const std::string& pin);
-	SupplicantStatus startWpsPbcInternal(
-	    const std::array<uint8_t, 6>& bssid);
-	SupplicantStatus startWpsPinKeypadInternal(const std::string& pin);
-	std::pair<SupplicantStatus, std::string> startWpsPinDisplayInternal(
-	    const std::array<uint8_t, 6>& bssid);
-	SupplicantStatus cancelWpsInternal();
-	SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
-	SupplicantStatus setWpsDeviceTypeInternal(
-	    const std::array<uint8_t, 8>& type);
-	SupplicantStatus setWpsManufacturerInternal(
-	    const std::string& manufacturer);
-	SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
-	SupplicantStatus setWpsModelNumberInternal(
-	    const std::string& model_number);
-	SupplicantStatus setWpsSerialNumberInternal(
-	    const std::string& serial_number);
-	SupplicantStatus setWpsConfigMethodsInternal(uint16_t config_methods);
-	SupplicantStatus setExternalSimInternal(bool useExternalSim);
-	std::pair<SupplicantStatus, uint32_t> addExtRadioWorkInternal(
-	    const std::string& name, uint32_t freq_in_mhz,
-	    uint32_t timeout_in_sec);
-	SupplicantStatus removeExtRadioWorkInternal(uint32_t id);
-	SupplicantStatus enableAutoReconnectInternal(bool enable);
-
-	struct wpa_supplicant* retrieveIfacePtr();
-
-	// Reference to the global wpa_struct. This is assumed to be valid for
-	// the lifetime of the process.
-	struct wpa_global* wpa_global_;
-	// Name of the iface this hidl object controls
-	const std::string ifname_;
-	bool is_valid_;
-
-	DISALLOW_COPY_AND_ASSIGN(StaIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace supplicant
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WPA_SUPPLICANT_HIDL_STA_IFACE_H
diff --git a/wpa_supplicant/hidl/1.1/hidl.cpp b/wpa_supplicant/hidl/1.2/hidl.cpp
similarity index 79%
rename from wpa_supplicant/hidl/1.1/hidl.cpp
rename to wpa_supplicant/hidl/1.2/hidl.cpp
index 95194af..d8fa82f 100644
--- a/wpa_supplicant/hidl/1.1/hidl.cpp
+++ b/wpa_supplicant/hidl/1.2/hidl.cpp
@@ -12,7 +12,8 @@
 #include <hidl/HidlTransportSupport.h>
 #include "hidl_manager.h"
 
-extern "C" {
+extern "C"
+{
 #include "hidl.h"
 #include "hidl_i.h"
 #include "utils/common.h"
@@ -21,9 +22,14 @@
 }
 
 using android::hardware::configureRpcThreadpool;
-using android::hardware::setupTransportPolling;
 using android::hardware::handleTransportPoll;
-using android::hardware::wifi::supplicant::V1_1::implementation::HidlManager;
+using android::hardware::setupTransportPolling;
+using android::hardware::wifi::supplicant::V1_2::implementation::HidlManager;
+using namespace android::hardware::wifi::supplicant::V1_2;
+
+static void wpas_hidl_notify_dpp_success(struct wpa_supplicant *wpa_s, DppSuccessCode code);
+static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s, DppFailureCode code);
+static void wpas_hidl_notify_dpp_progress(struct wpa_supplicant *wpa_s, DppProgressCode code);
 
 void wpas_hidl_sock_handler(
     int sock, void * /* eloop_ctx */, void * /* sock_ctx */)
@@ -206,8 +212,9 @@
 		return;
 
 	wpa_printf(
-	    MSG_DEBUG, "Notifying HS20 icon query done to hidl control: " MACSTR
-		       "file_name: %s",
+	    MSG_DEBUG,
+	    "Notifying HS20 icon query done to hidl control: " MACSTR
+	    "file_name: %s",
 	    MAC2STR(bssid), file_name);
 
 	HidlManager *hidl_manager = HidlManager::getInstance();
@@ -533,13 +540,14 @@
 		return;
 	if (bssid) {
 		wpa_printf(
-			MSG_DEBUG,
-			"Notifying P2P invitation result to hidl control: " MACSTR,
-			MAC2STR(bssid));
+		    MSG_DEBUG,
+		    "Notifying P2P invitation result to hidl control: " MACSTR,
+		    MAC2STR(bssid));
 	} else {
 		wpa_printf(
-			MSG_DEBUG,
-			"Notifying P2P invitation result to hidl control: NULL bssid");
+		    MSG_DEBUG,
+		    "Notifying P2P invitation result to hidl control: NULL "
+		    "bssid");
 	}
 
 	HidlManager *hidl_manager = HidlManager::getInstance();
@@ -626,15 +634,12 @@
 	hidl_manager->notifyApStaDeauthorized(wpa_s, sta, p2p_dev_addr);
 }
 
-void wpas_hidl_notify_eap_error(
-    struct wpa_supplicant *wpa_s, int error_code)
+void wpas_hidl_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code)
 {
 	if (!wpa_s)
 		return;
 
-	wpa_printf(
-	    MSG_DEBUG,
-            "Notifying EAP Error: %d ", error_code);
+	wpa_printf(MSG_DEBUG, "Notifying EAP Error: %d ", error_code);
 
 	HidlManager *hidl_manager = HidlManager::getInstance();
 	if (!hidl_manager)
@@ -643,3 +648,140 @@
 	hidl_manager->notifyEapError(wpa_s, error_code);
 }
 
+void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+	    struct wpa_ssid *ssid)
+{
+	if (!wpa_s || !ssid)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying DPP configuration received for SSID %d", ssid->id);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyDppConfigReceived(wpa_s, ssid);
+}
+
+void wpas_hidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_success(wpa_s, DppSuccessCode::CONFIGURATION_SENT);
+}
+
+/* DPP Progress notifications */
+void wpas_hidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_progress(wpa_s, DppProgressCode::AUTHENTICATION_SUCCESS);
+}
+
+void wpas_hidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_progress(wpa_s, DppProgressCode::RESPONSE_PENDING);
+}
+
+/* DPP Failure notifications */
+void wpas_hidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::NOT_COMPATIBLE);
+}
+
+void wpas_hidl_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+}
+
+void wpas_hidl_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::CONFIGURATION);
+}
+
+void wpas_hidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::TIMEOUT);
+}
+
+void wpas_hidl_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::AUTHENTICATION);
+}
+
+void wpas_hidl_notify_dpp_fail(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::FAILURE);
+}
+
+/* DPP notification helper functions */
+static void wpas_hidl_notify_dpp_success(struct wpa_supplicant *wpa_s, DppSuccessCode code)
+{
+	if (!wpa_s)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying DPP success event %d", code);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyDppSuccess(wpa_s, code);
+}
+
+static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s, DppFailureCode code)
+{
+	if (!wpa_s)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying DPP failure event %d", code);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyDppFailure(wpa_s, code);
+}
+
+static void wpas_hidl_notify_dpp_progress(struct wpa_supplicant *wpa_s, DppProgressCode code)
+{
+	if (!wpa_s)
+		return;
+
+	wpa_printf(
+	    MSG_DEBUG,
+	    "Notifying DPP progress event %d", code);
+
+	HidlManager *hidl_manager = HidlManager::getInstance();
+	if (!hidl_manager)
+		return;
+
+	hidl_manager->notifyDppProgress(wpa_s, code);
+}
diff --git a/wpa_supplicant/hidl/1.2/hidl.h b/wpa_supplicant/hidl/1.2/hidl.h
new file mode 100644
index 0000000..a177f6e
--- /dev/null
+++ b/wpa_supplicant/hidl/1.2/hidl.h
@@ -0,0 +1,248 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_HIDL_H
+#define WPA_SUPPLICANT_HIDL_HIDL_H
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif  // _cplusplus
+
+	/**
+	 * This is the hidl RPC interface entry point to the wpa_supplicant
+	 * core. This initializes the hidl driver & HidlManager instance and
+	 * then forwards all the notifcations from the supplicant core to the
+	 * HidlManager.
+	 */
+	struct wpas_hidl_priv;
+	struct wpa_global;
+
+	struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global);
+	void wpas_hidl_deinit(struct wpas_hidl_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_HIDL
+	int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s);
+	int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s);
+	int wpas_hidl_register_network(
+	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+	int wpas_hidl_unregister_network(
+	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+	int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s);
+	int wpas_hidl_notify_network_request(
+	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	    enum wpa_ctrl_req_type rtype, const char *default_txt);
+	void wpas_hidl_notify_anqp_query_done(
+	    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+	    const struct wpa_bss_anqp *anqp);
+	void wpas_hidl_notify_hs20_icon_query_done(
+	    struct wpa_supplicant *wpa_s, const u8 *bssid,
+	    const char *file_name, const u8 *image, u32 image_length);
+	void wpas_hidl_notify_hs20_rx_subscription_remediation(
+	    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
+	void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
+	    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
+	    const char *url);
+	void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_wps_event_fail(
+	    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr,
+	    uint16_t config_error, uint16_t error_indication);
+	void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_wps_event_pbc_overlap(
+	    struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_p2p_device_found(
+	    struct wpa_supplicant *wpa_s, const u8 *addr,
+	    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+	    u8 peer_wfd_device_info_len);
+	void wpas_hidl_notify_p2p_device_lost(
+	    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
+	void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_p2p_go_neg_req(
+	    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+	    u8 go_intent);
+	void wpas_hidl_notify_p2p_go_neg_completed(
+	    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
+	void wpas_hidl_notify_p2p_group_formation_failure(
+	    struct wpa_supplicant *wpa_s, const char *reason);
+	void wpas_hidl_notify_p2p_group_started(
+	    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
+	    int persistent, int client);
+	void wpas_hidl_notify_p2p_group_removed(
+	    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
+	    const char *role);
+	void wpas_hidl_notify_p2p_invitation_received(
+	    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+	    const u8 *bssid, int id, int op_freq);
+	void wpas_hidl_notify_p2p_invitation_result(
+	    struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
+	void wpas_hidl_notify_p2p_provision_discovery(
+	    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+	    enum p2p_prov_disc_status status, u16 config_methods,
+	    unsigned int generated_pin);
+	void wpas_hidl_notify_p2p_sd_response(
+	    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+	    const u8 *tlvs, size_t tlvs_len);
+	void wpas_hidl_notify_ap_sta_authorized(
+	    struct wpa_supplicant *wpa_s, const u8 *sta,
+	    const u8 *p2p_dev_addr);
+	void wpas_hidl_notify_ap_sta_deauthorized(
+	    struct wpa_supplicant *wpa_s, const u8 *sta,
+	    const u8 *p2p_dev_addr);
+	void wpas_hidl_notify_eap_error(
+	    struct wpa_supplicant *wpa_s, int error_code);
+	void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+		    struct wpa_ssid *ssid);
+	void wpas_hidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_invalid_uri(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_dpp_fail(struct wpa_supplicant *wpa_s);
+#else   // CONFIG_CTRL_IFACE_HIDL
+static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+static inline int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+static inline int wpas_hidl_register_network(
+    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	return 0;
+}
+static inline int wpas_hidl_unregister_network(
+    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	return 0;
+}
+static inline int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+static inline int wpas_hidl_notify_network_request(
+    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+    enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+	return 0;
+}
+static void wpas_hidl_notify_anqp_query_done(
+    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+    const struct wpa_bss_anqp *anqp)
+{}
+static void wpas_hidl_notify_hs20_icon_query_done(
+    struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
+    const u8 *image, u32 image_length)
+{}
+static void wpas_hidl_notify_hs20_rx_subscription_remediation(
+    struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
+{}
+static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
+    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
+{}
+static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_fail(
+    struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
+    uint16_t error_indication)
+{}
+static void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_p2p_device_found(
+    struct wpa_supplicant *wpa_s, const u8 *addr,
+    const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+    u8 peer_wfd_device_info_len);
+{}
+static void wpas_hidl_notify_p2p_device_lost(
+    struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{}
+static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_p2p_go_neg_req(
+    struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+    u8 go_intent)
+{}
+static void wpas_hidl_notify_p2p_go_neg_completed(
+    struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{}
+static void wpas_hidl_notify_p2p_group_formation_failure(
+    struct wpa_supplicant *wpa_s, const char *reason)
+{}
+static void wpas_hidl_notify_p2p_group_started(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+    int client)
+{}
+static void wpas_hidl_notify_p2p_group_removed(
+    struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
+{}
+static void wpas_hidl_notify_p2p_invitation_received(
+    struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+    const u8 *bssid, int id, int op_freq)
+{}
+static void wpas_hidl_notify_p2p_invitation_result(
+    struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{}
+static void wpas_hidl_notify_p2p_provision_discovery(
+    struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+    enum p2p_prov_disc_status status, u16 config_methods,
+    unsigned int generated_pin)
+{}
+static void wpas_hidl_notify_p2p_sd_response(
+    struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+    const u8 *tlvs, size_t tlvs_len)
+{}
+static void wpas_hidl_notify_ap_sta_authorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{}
+static void wpas_hidl_notify_ap_sta_deauthorized(
+    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{}
+static void wpas_hidl_notify_eap_error(
+    struct wpa_supplicant *wpa_s, int error_code)
+{}
+static void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+	    struct wpa_ssid *ssid)
+{}
+static void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+	    struct wpa_ssid *ssid);
+static void wpas_hidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_invalid_uri(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s)
+{}
+#endif  // CONFIG_CTRL_IFACE_HIDL
+
+#ifdef _cplusplus
+}
+#endif  // _cplusplus
+
+#endif  // WPA_SUPPLICANT_HIDL_HIDL_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_constants.h b/wpa_supplicant/hidl/1.2/hidl_constants.h
similarity index 100%
rename from wpa_supplicant/hidl/1.0/hidl_constants.h
rename to wpa_supplicant/hidl/1.2/hidl_constants.h
diff --git a/wpa_supplicant/hidl/1.0/hidl_i.h b/wpa_supplicant/hidl/1.2/hidl_i.h
similarity index 79%
rename from wpa_supplicant/hidl/1.0/hidl_i.h
rename to wpa_supplicant/hidl/1.2/hidl_i.h
index c7a0142..9cff40d 100644
--- a/wpa_supplicant/hidl/1.0/hidl_i.h
+++ b/wpa_supplicant/hidl/1.2/hidl_i.h
@@ -11,15 +11,16 @@
 #define HIDL_I_H
 
 #ifdef _cplusplus
-extern "C" {
+extern "C"
+{
 #endif  // _cplusplus
 
-struct wpas_hidl_priv
-{
-	int hidl_fd;
-	struct wpa_global *global;
-	void *hidl_manager;
-};
+	struct wpas_hidl_priv
+	{
+		int hidl_fd;
+		struct wpa_global *global;
+		void *hidl_manager;
+	};
 
 #ifdef _cplusplus
 }
diff --git a/wpa_supplicant/hidl/1.1/hidl_manager.cpp b/wpa_supplicant/hidl/1.2/hidl_manager.cpp
similarity index 90%
rename from wpa_supplicant/hidl/1.1/hidl_manager.cpp
rename to wpa_supplicant/hidl/1.2/hidl_manager.cpp
index ca614d2..8297c03 100644
--- a/wpa_supplicant/hidl/1.1/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.2/hidl_manager.cpp
@@ -14,11 +14,13 @@
 #include "misc_utils.h"
 
 extern "C" {
+#include "scan.h"
 #include "src/eap_common/eap_sim_common.h"
 }
 
 namespace {
 using android::hardware::hidl_array;
+using namespace android::hardware::wifi::supplicant::V1_2;
 
 constexpr uint8_t kWfdDeviceInfoLen = 6;
 // GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
@@ -292,7 +294,8 @@
     const std::string &ifname,
     const std::function<
 	android::hardware::Return<void>(android::sp<CallbackTypeV1_1>)> &method,
-    const std::map<const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
+    const std::map<
+	const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
 	&callbacks_map)
 {
 	if (ifname.empty())
@@ -315,6 +318,35 @@
 	}
 }
 
+template <class CallbackTypeV1_0, class CallbackTypeV1_2>
+void callWithEachIfaceCallback_1_2(
+    const std::string &ifname,
+    const std::function<
+	android::hardware::Return<void>(android::sp<CallbackTypeV1_2>)> &method,
+    const std::map<
+	const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
+	&callbacks_map)
+{
+	if (ifname.empty())
+		return;
+
+	auto iface_callback_map_iter = callbacks_map.find(ifname);
+	if (iface_callback_map_iter == callbacks_map.end())
+		return;
+	const auto &iface_callback_list = iface_callback_map_iter->second;
+	for (const auto &callback : iface_callback_list) {
+		android::sp<CallbackTypeV1_2> callback_1_2 =
+		    CallbackTypeV1_2::castFrom(callback);
+		if (callback_1_2 == nullptr)
+			continue;
+
+		if (!method(callback_1_2).isOk()) {
+			wpa_printf(
+			    MSG_ERROR, "Failed to invoke HIDL iface callback");
+		}
+	}
+}
+
 template <class CallbackType>
 void callWithEachNetworkCallback(
     const std::string &ifname, int network_id,
@@ -397,11 +429,10 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
+using namespace android::hardware::wifi::supplicant::V1_2;
 using V1_0::ISupplicantStaIfaceCallback;
 
 HidlManager *HidlManager::instance_ = NULL;
@@ -470,6 +501,18 @@
 		}
 		sta_iface_callbacks_map_[wpa_s->ifname] =
 		    std::vector<android::sp<ISupplicantStaIfaceCallback>>();
+		// Turn on Android specific customizations for STA interfaces
+		// here!
+		//
+		// Turn on scan mac randomization only if driver supports.
+		if (wpa_s->mac_addr_rand_supported & MAC_ADDR_RAND_SCAN) {
+			if (wpas_mac_addr_rand_scan_set(
+				wpa_s, MAC_ADDR_RAND_SCAN, nullptr, nullptr)) {
+				wpa_printf(
+				    MSG_ERROR,
+				    "Failed to enable scan mac randomization");
+			}
+		}
 	}
 
 	// Invoke the |onInterfaceCreated| method on all registered callbacks.
@@ -1204,7 +1247,8 @@
 }
 
 void HidlManager::notifyP2pGroupStarted(
-    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid, int persistent, int client)
+    struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+    int persistent, int client)
 {
 	if (!wpa_group_s || !wpa_group_s->parent || !ssid)
 		return;
@@ -1358,9 +1402,11 @@
 	    p2p_iface_object_map_.end())
 		return;
 	callWithEachP2pIfaceCallback(
-	    wpa_s->parent->ifname, std::bind(
-			       &ISupplicantP2pIfaceCallback::onStaAuthorized,
-			       std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
+	    wpa_s->parent->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onStaAuthorized,
+		std::placeholders::_1, sta,
+		p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
 }
 
 void HidlManager::notifyApStaDeauthorized(
@@ -1373,9 +1419,11 @@
 		return;
 
 	callWithEachP2pIfaceCallback(
-	    wpa_s->parent->ifname, std::bind(
-			       &ISupplicantP2pIfaceCallback::onStaDeauthorized,
-			       std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
+	    wpa_s->parent->ifname,
+	    std::bind(
+		&ISupplicantP2pIfaceCallback::onStaDeauthorized,
+		std::placeholders::_1, sta,
+		p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
 }
 
 void HidlManager::notifyExtRadioWorkStart(
@@ -1420,22 +1468,106 @@
 		return;
 
 	switch (static_cast<EapErrorCode>(error_code)) {
-		case EapErrorCode::SIM_GENERAL_FAILURE_AFTER_AUTH:
-		case EapErrorCode::SIM_TEMPORARILY_DENIED:
-		case EapErrorCode::SIM_NOT_SUBSCRIBED:
-		case EapErrorCode::SIM_GENERAL_FAILURE_BEFORE_AUTH:
-		case EapErrorCode::SIM_VENDOR_SPECIFIC_EXPIRED_CERT:
-			break;
-		default:
-			return;
+	case EapErrorCode::SIM_GENERAL_FAILURE_AFTER_AUTH:
+	case EapErrorCode::SIM_TEMPORARILY_DENIED:
+	case EapErrorCode::SIM_NOT_SUBSCRIBED:
+	case EapErrorCode::SIM_GENERAL_FAILURE_BEFORE_AUTH:
+	case EapErrorCode::SIM_VENDOR_SPECIFIC_EXPIRED_CERT:
+		break;
+	default:
+		return;
 	}
 
 	callWithEachStaIfaceCallback_1_1(
 	    wpa_s->ifname,
 	    std::bind(
 		&V1_1::ISupplicantStaIfaceCallback::onEapFailure_1_1,
-		std::placeholders::_1,
-		static_cast<EapErrorCode>(error_code)));
+		std::placeholders::_1, static_cast<EapErrorCode>(error_code)));
+}
+
+/**
+ * Notify listener about a new DPP configuration success event
+ *
+ * @param ifname Interface name
+ * @param config Configuration object
+ */
+void HidlManager::notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
+		struct wpa_ssid *config)
+{
+	DppAkm securityAkm;
+	char *password;
+	std::string hidl_ifname = wpa_s->ifname;
+
+	if ((config->key_mgmt & WPA_KEY_MGMT_SAE) &&
+			(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+		securityAkm = DppAkm::SAE;
+	} else if (config->key_mgmt & WPA_KEY_MGMT_PSK) {
+			securityAkm = DppAkm::PSK;
+	} else {
+		/* Unsupported AKM */
+		wpa_printf(MSG_ERROR, "DPP: Error: Unsupported AKM 0x%X",
+				config->key_mgmt);
+		notifyDppFailure(wpa_s, DppFailureCode::NOT_SUPPORTED);
+		return;
+	}
+
+	password = config->passphrase;
+	std::vector < uint8_t > hidl_ssid;
+	hidl_ssid.assign(config->ssid, config->ssid + config->ssid_len);
+
+	/* At this point, the network is already registered, notify about new
+	 * received configuration
+	 */
+	callWithEachStaIfaceCallback_1_2(hidl_ifname,
+			std::bind(
+					&V1_2::ISupplicantStaIfaceCallback::onDppSuccessConfigReceived,
+					std::placeholders::_1, hidl_ssid, password, config->psk,
+					securityAkm));
+}
+
+/**
+ * Notify listener about a DPP success event
+ *
+ * @param ifname Interface name
+ * @param code Status code
+ */
+void HidlManager::notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code)
+{
+	std::string hidl_ifname = wpa_s->ifname;
+
+	callWithEachStaIfaceCallback_1_2(hidl_ifname,
+			std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppSuccess,
+					std::placeholders::_1, code));
+}
+
+/**
+ * Notify listener about a DPP failure event
+ *
+ * @param ifname Interface name
+ * @param code Status code
+ */
+void HidlManager::notifyDppFailure(struct wpa_supplicant *wpa_s, DppFailureCode code)
+{
+	std::string hidl_ifname = wpa_s->ifname;
+
+	callWithEachStaIfaceCallback_1_2(hidl_ifname,
+			std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppFailure,
+					std::placeholders::_1, code));
+}
+
+/**
+ * Notify listener about a DPP progress event
+ *
+ * @param ifname Interface name
+ * @param code Status code
+ */
+void HidlManager::notifyDppProgress(struct wpa_supplicant *wpa_s, DppProgressCode code)
+{
+	std::string hidl_ifname = wpa_s->ifname;
+
+	callWithEachStaIfaceCallback_1_2(hidl_ifname,
+			std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppProgress,
+					std::placeholders::_1, code));
 }
 
 /**
@@ -1767,8 +1899,8 @@
 }
 
 /**
- * Helper fucntion to invoke the provided callback method on all the
- * registered V1.1 iface callback hidl objects for the specified
+ * Helper function to invoke the provided callback method on all the
+ * registered V1.1 interface callback hidl objects for the specified
  * |ifname|.
  *
  * @param ifname Name of the corresponding interface.
@@ -1777,15 +1909,32 @@
  */
 void HidlManager::callWithEachStaIfaceCallback_1_1(
     const std::string &ifname,
-    const std::function<Return<void>
-	(android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method)
+    const std::function<
+	Return<void>(android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method)
 {
 	callWithEachIfaceCallback_1_1(ifname, method, sta_iface_callbacks_map_);
 }
 
 /**
- * Helper fucntion to invoke the provided callback method on all the
- * registered iface callback hidl objects for the specified
+ * Helper function to invoke the provided callback method on all the
+ * registered V1.2 interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * |V1_2::ISupplicantIfaceCallback|.
+ */
+void HidlManager::callWithEachStaIfaceCallback_1_2(
+    const std::string &ifname,
+    const std::function<
+	Return<void>(android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method)
+{
+	callWithEachIfaceCallback_1_2(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered interface callback hidl objects for the specified
  * |ifname|.
  *
  * @param ifname Name of the corresponding interface.
@@ -1838,8 +1987,8 @@
 	    ifname, network_id, method, sta_network_callbacks_map_);
 }
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wpa_supplicant/hidl/1.1/hidl_manager.h b/wpa_supplicant/hidl/1.2/hidl_manager.h
similarity index 92%
rename from wpa_supplicant/hidl/1.1/hidl_manager.h
rename to wpa_supplicant/hidl/1.2/hidl_manager.h
index 4f100aa..7291347 100644
--- a/wpa_supplicant/hidl/1.1/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.2/hidl_manager.h
@@ -16,7 +16,7 @@
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
 
 #include "p2p_iface.h"
@@ -25,7 +25,8 @@
 #include "sta_network.h"
 #include "supplicant.h"
 
-extern "C" {
+extern "C"
+{
 #include "utils/common.h"
 #include "utils/includes.h"
 #include "wpa_supplicant_i.h"
@@ -36,11 +37,13 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
+using namespace android::hardware::wifi::supplicant::V1_2;
+using V1_0::ISupplicantP2pIface;
 using V1_0::ISupplicantStaIfaceCallback;
+using V1_1::ISupplicant;
+using V1_1::ISupplicantStaIface;
 
 /**
  * HidlManager is responsible for managing the lifetime of all
@@ -124,8 +127,12 @@
 	void notifyApStaDeauthorized(
 	    struct wpa_supplicant *wpa_s, const u8 *sta,
 	    const u8 *p2p_dev_addr);
-	void notifyEapError(
-	    struct wpa_supplicant *wpa_s, int error_code);
+	void notifyEapError(struct wpa_supplicant *wpa_s, int error_code);
+	void notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
+			struct wpa_ssid *config);
+	void notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code);
+	void notifyDppFailure(struct wpa_supplicant *wpa_s, DppFailureCode code);
+	void notifyDppProgress(struct wpa_supplicant *wpa_s, DppProgressCode code);
 
 	// Methods called from hidl objects.
 	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
@@ -137,7 +144,7 @@
 	    android::sp<ISupplicantP2pIface> *iface_object);
 	int getStaIfaceHidlObjectByIfname(
 	    const std::string &ifname,
-	    android::sp<ISupplicantStaIface> *iface_object);
+	    android::sp<V1_1::ISupplicantStaIface> *iface_object);
 	int getP2pNetworkHidlObjectByIfnameAndNetworkId(
 	    const std::string &ifname, int network_id,
 	    android::sp<ISupplicantP2pNetwork> *network_object);
@@ -195,6 +202,10 @@
 	    const std::string &ifname,
 	    const std::function<android::hardware::Return<void>(
 		android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method);
+	void callWithEachStaIfaceCallback_1_2(
+	    const std::string &ifname,
+	    const std::function<android::hardware::Return<void>(
+	    android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method);
 	void callWithEachP2pNetworkCallback(
 	    const std::string &ifname, int network_id,
 	    const std::function<android::hardware::Return<void>(
@@ -334,6 +345,26 @@
 	WPA_KEY_MGMT_OSEN,
     "KeyMgmt value mismatch");
 static_assert(
+    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SAE) ==
+	WPA_KEY_MGMT_SAE,
+    "KeyMgmt value mismatch");
+static_assert(
+    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) ==
+	WPA_KEY_MGMT_IEEE8021X_SUITE_B_192,
+    "KeyMgmt value mismatch");
+static_assert(
+    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OWE) ==
+	WPA_KEY_MGMT_OWE,
+    "KeyMgmt value mismatch");
+static_assert(
+    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) ==
+	WPA_KEY_MGMT_PSK_SHA256,
+    "KeyMgmt value mismatch");
+static_assert(
+    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256) ==
+	WPA_KEY_MGMT_IEEE8021X_SHA256,
+    "KeyMgmt value mismatch");
+static_assert(
     static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
 	WPA_PROTO_WPA,
     "Proto value mismatch");
@@ -374,6 +405,10 @@
 	WPA_CIPHER_CCMP,
     "GroupCipher value mismatch");
 static_assert(
+    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GCMP_256) ==
+	WPA_CIPHER_GCMP_256,
+    "GroupCipher value mismatch");
+static_assert(
     static_cast<uint32_t>(
 	ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
 	WPA_CIPHER_GTK_NOT_USED,
@@ -390,7 +425,11 @@
     static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
 	WPA_CIPHER_CCMP,
     "PairwiseCipher value mismatch");
-
+static_assert(
+    static_cast<uint32_t>(
+	ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256) ==
+	WPA_CIPHER_GCMP_256,
+    "PairwiseCipher value mismatch");
 static_assert(
     static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::DISCONNECTED) ==
 	WPA_DISCONNECTED,
@@ -679,9 +718,9 @@
 	P2P_PROV_DISC_INFO_UNAVAILABLE,
     "P2P status code value mismatch");
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
 #endif  // WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
diff --git a/wpa_supplicant/hidl/1.1/hidl_return_util.h b/wpa_supplicant/hidl/1.2/hidl_return_util.h
similarity index 97%
rename from wpa_supplicant/hidl/1.1/hidl_return_util.h
rename to wpa_supplicant/hidl/1.2/hidl_return_util.h
index dba5f37..238646a 100644
--- a/wpa_supplicant/hidl/1.1/hidl_return_util.h
+++ b/wpa_supplicant/hidl/1.2/hidl_return_util.h
@@ -14,7 +14,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 namespace hidl_return_util {
 
@@ -91,9 +91,9 @@
 	return Void();
 }
 
-}  // namespace hidl_util
+}  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_1
+}  // namespace V1_2
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.0/iface_config_utils.cpp b/wpa_supplicant/hidl/1.2/iface_config_utils.cpp
similarity index 96%
rename from wpa_supplicant/hidl/1.0/iface_config_utils.cpp
rename to wpa_supplicant/hidl/1.2/iface_config_utils.cpp
index 7dc5a6c..43908e3 100644
--- a/wpa_supplicant/hidl/1.0/iface_config_utils.cpp
+++ b/wpa_supplicant/hidl/1.2/iface_config_utils.cpp
@@ -14,6 +14,9 @@
 #include "iface_config_utils.h"
 
 namespace {
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
 constexpr uint32_t kMaxWpsDeviceNameSize = WPS_DEV_NAME_MAX_LEN;
 constexpr uint32_t kMaxWpsManufacturerSize = WPS_MANUFACTURER_MAX_LEN;
 constexpr uint32_t kMaxWpsModelNameSize = WPS_MODEL_NAME_MAX_LEN;
@@ -78,7 +81,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
 namespace implementation {
 namespace iface_config_utils {
 SupplicantStatus setWpsDeviceName(
@@ -173,8 +176,8 @@
 }
 }  // namespace iface_config_utils
 }  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wpa_supplicant/hidl/1.0/iface_config_utils.h b/wpa_supplicant/hidl/1.2/iface_config_utils.h
similarity index 97%
rename from wpa_supplicant/hidl/1.0/iface_config_utils.h
rename to wpa_supplicant/hidl/1.2/iface_config_utils.h
index 789cc38..9e88b3e 100644
--- a/wpa_supplicant/hidl/1.0/iface_config_utils.h
+++ b/wpa_supplicant/hidl/1.2/iface_config_utils.h
@@ -14,7 +14,8 @@
 
 #include <android-base/macros.h>
 
-extern "C" {
+extern "C"
+{
 #include "utils/common.h"
 #include "utils/includes.h"
 #include "wpa_supplicant_i.h"
@@ -29,7 +30,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
 namespace implementation {
 namespace iface_config_utils {
 SupplicantStatus setWpsDeviceName(
@@ -50,9 +51,9 @@
     struct wpa_supplicant* wpa_s, bool useExternalSim);
 }  // namespace iface_config_utils
 }  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
 
diff --git a/wpa_supplicant/hidl/1.1/misc_utils.h b/wpa_supplicant/hidl/1.2/misc_utils.h
similarity index 96%
rename from wpa_supplicant/hidl/1.1/misc_utils.h
rename to wpa_supplicant/hidl/1.2/misc_utils.h
index 8b2ae3f..1360e6b 100644
--- a/wpa_supplicant/hidl/1.1/misc_utils.h
+++ b/wpa_supplicant/hidl/1.2/misc_utils.h
@@ -10,7 +10,8 @@
 #ifndef MISC_UTILS_H_
 #define MISC_UTILS_H_
 
-extern "C" {
+extern "C"
+{
 #include "wpabuf.h"
 }
 
@@ -24,7 +25,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 namespace misc_utils {
 using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
@@ -64,7 +65,7 @@
 
 }  // namespace misc_utils
 }  // namespace implementation
-}  // namespace V1_1
+}  // namespace V1_2
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.0/p2p_iface.cpp b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
similarity index 71%
rename from wpa_supplicant/hidl/1.0/p2p_iface.cpp
rename to wpa_supplicant/hidl/1.2/p2p_iface.cpp
index 7a94a31..4c16743 100644
--- a/wpa_supplicant/hidl/1.0/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
@@ -13,13 +13,20 @@
 #include "iface_config_utils.h"
 #include "misc_utils.h"
 #include "p2p_iface.h"
+#include "sta_network.h"
 
-extern "C" {
+extern "C"
+{
 #include "ap.h"
 #include "wps_supplicant.h"
 #include "wifi_display.h"
+#include "utils/eloop.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
 }
 
+#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+
 namespace {
 const char kConfigMethodStrPbc[] = "pbc";
 const char kConfigMethodStrDisplay[] = "display";
@@ -28,7 +35,11 @@
 constexpr uint8_t kWfdDeviceInfoSubelemId = 0;
 constexpr char kWfdDeviceInfoSubelemLenHexStr[] = "0006";
 
+std::function<void()> pending_join_scan_callback = NULL;
+std::function<void()> pending_scan_res_join_callback = NULL;
+
 using android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 uint8_t convertHidlMiracastModeToInternal(
     ISupplicantP2pIface::MiracastMode mode)
 {
@@ -42,20 +53,330 @@
 	};
 	WPA_ASSERT(false);
 }
+
+/**
+ * Check if the provided ssid is valid or not.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ */
+int isSsidValid(const std::vector<uint8_t>& ssid)
+{
+	if (ssid.size() == 0 ||
+	    ssid.size() >
+		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+					  SSID_MAX_LEN_IN_BYTES)) {
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * Check if the provided psk passhrase is valid or not.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ */
+int isPskPassphraseValid(const std::string &psk)
+{
+	if (psk.size() <
+		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+					  PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
+	    psk.size() >
+		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+					  PSK_PASSPHRASE_MAX_LEN_IN_BYTES)) {
+		return 0;
+	}
+	if (has_ctrl_char((u8 *)psk.c_str(), psk.size())) {
+		return 0;
+	}
+	return 1;
+}
+
+void setBandScanFreqsList(
+    struct wpa_supplicant *wpa_s,
+    enum hostapd_hw_mode band,
+    struct wpa_driver_scan_params *params)
+{
+	/* 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);
+	if (mode == NULL) {
+		/* No channels supported in this band. */
+		return;
+	}
+
+	params->freqs = (int *) os_calloc(mode->num_channels + 1, sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	for (count = 0, i = 0; i < mode->num_channels; i++) {
+		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		params->freqs[count++] = mode->channels[i].freq;
+	}
+}
+
+/**
+ * findBssBySsid - Fetch a BSS table entry based on SSID and optional BSSID.
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID, zero addr matches any bssid
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss* findBssBySsid(
+    struct wpa_supplicant *wpa_s, const u8 *bssid,
+    const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if ((is_zero_ether_addr(bssid) ||
+		    os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) &&
+		    bss->ssid_len == ssid_len &&
+		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+struct wpa_ssid* addGroupClientNetwork(
+    struct wpa_supplicant* wpa_s,
+    uint8_t *group_owner_bssid,
+    const std::vector<uint8_t>& ssid,
+    const std::string& passphrase)
+{
+	struct wpa_ssid* wpa_network = wpa_config_add_network(wpa_s->conf);
+	if (!wpa_network) {
+		return NULL;
+	}
+	// set general network defaults
+	wpa_config_set_network_defaults(wpa_network);
+
+	// set P2p network defaults
+	wpa_network->p2p_group = 1;
+	wpa_network->mode = wpa_ssid::wpas_mode::WPAS_MODE_INFRA;
+
+	wpa_network->auth_alg = WPA_AUTH_ALG_OPEN;
+	wpa_network->key_mgmt = WPA_KEY_MGMT_PSK;
+	wpa_network->proto = WPA_PROTO_RSN;
+	wpa_network->pairwise_cipher = WPA_CIPHER_CCMP;
+	wpa_network->group_cipher = WPA_CIPHER_CCMP;
+	wpa_network->disabled = 2;
+
+	// set necessary fields
+	os_memcpy(wpa_network->bssid, group_owner_bssid, ETH_ALEN);
+	wpa_network->bssid_set = 1;
+
+	wpa_network->ssid = (uint8_t *)os_malloc(ssid.size());
+	if (wpa_network->ssid == NULL) {
+		wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+		return  NULL;
+	}
+	memcpy(wpa_network->ssid, ssid.data(), ssid.size());
+	wpa_network->ssid_len = ssid.size();
+
+	wpa_network->psk_set = 0;
+	wpa_network->passphrase = dup_binstr(passphrase.c_str(), passphrase.length());
+	if (wpa_network->passphrase == NULL) {
+		wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+		return  NULL;
+	}
+	wpa_config_update_psk(wpa_network);
+
+	return wpa_network;
+
+}
+
+void joinScanWrapper(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *) eloop_ctx;
+
+	if (pending_join_scan_callback != NULL) {
+		pending_join_scan_callback();
+	}
+}
+
+void scanResJoinWrapper(
+    struct wpa_supplicant *wpa_s,
+    struct wpa_scan_results *scan_res)
+{
+	if (pending_scan_res_join_callback) {
+		pending_scan_res_join_callback();
+	}
+}
+
+int joinScanReq(
+    struct wpa_supplicant* wpa_s,
+    const std::vector<uint8_t>& ssid,
+    int freq)
+{
+	int ret;
+	struct wpa_driver_scan_params params;
+	struct wpabuf *ies;
+	size_t ielen;
+	unsigned int bands;
+
+	os_memset(&params, 0, sizeof(params));
+	if (ssid.size() > 0) {
+		params.ssids[0].ssid = ssid.data();
+		params.ssids[0].ssid_len = ssid.size();
+	} else {
+		params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+		params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+	}
+	wpa_printf(MSG_DEBUG, "Scan SSID %s for join with frequency %d (reinvoke)",
+	    wpa_ssid_txt(params.ssids[0].ssid, params.ssids[0].ssid_len), freq);
+
+	if (freq > 0) {
+		if (freq == 2 || freq == 5) {
+			if (wpa_s->hw.modes != NULL) {
+				switch (freq) {
+				case 2:
+					setBandScanFreqsList(wpa_s,
+					    HOSTAPD_MODE_IEEE80211G, &params);
+				break;
+				case 5:
+					setBandScanFreqsList(wpa_s,
+					    HOSTAPD_MODE_IEEE80211A, &params);
+				break;
+				}
+				if (!params.freqs) {
+					wpa_printf(MSG_ERROR,
+					    "P2P: No supported channels in %dG band.", freq);
+					return -1;
+				}
+			} else {
+				wpa_printf(MSG_DEBUG,
+				    "P2P: Unknown what %dG channels the driver supports.", freq);
+			}
+		} else {
+			if (0 == p2p_supported_freq_cli(wpa_s->global->p2p, freq)) {
+				wpa_printf(MSG_ERROR,
+				    "P2P: freq %d is not supported for a client.", freq);
+				return -1;
+			}
+
+			params.freqs = (int *) os_malloc(sizeof(int) * 2);
+			if (params.freqs) {
+				params.freqs[0] = freq;
+			} else {
+				wpa_printf(MSG_ERROR,
+				    "P2P: Cannot allocate memory for scan params.");
+				return -1;
+			}
+		}
+	}
+
+	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+	ies = wpabuf_alloc(ielen);
+	if (ies == NULL) {
+		if (params.freqs) {
+			os_free(params.freqs);
+		}
+		return -1;
+	}
+
+	bands = wpas_get_bands(wpa_s, params.freqs);
+	p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
+
+	params.p2p_probe = 1;
+	params.extra_ies = (u8 *) wpabuf_head(ies);
+	params.extra_ies_len = wpabuf_len(ies);
+	if (wpa_s->clear_driver_scan_cache) {
+		wpa_printf(MSG_DEBUG,
+		    "Request driver to clear scan cache due to local BSS flush");
+		params.only_new_results = 1;
+	}
+
+	ret = wpa_drv_scan(wpa_s, &params);
+	if (!ret) {
+		os_get_reltime(&wpa_s->scan_trigger_time);
+		wpa_s->scan_res_handler = scanResJoinWrapper;
+		wpa_s->own_scan_requested = 1;
+		wpa_s->clear_driver_scan_cache = 0;
+	}
+
+	if (params.freqs) {
+		os_free(params.freqs);
+	}
+
+	wpabuf_free(ies);
+
+	return ret;
+}
+
+int joinGroup(
+    struct wpa_supplicant* wpa_s,
+    uint8_t *group_owner_bssid,
+    const std::vector<uint8_t>& ssid,
+    const std::string& passphrase)
+{
+	int ret = 0;
+	int vht = wpa_s->conf->p2p_go_vht;
+	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+
+	// Construct a network for adding group.
+	// Group client follows the persistent attribute of Group Owner.
+	// If joined group is persistent, it adds a persistent network on GroupStarted.
+	struct wpa_ssid *wpa_network = addGroupClientNetwork(
+	    wpa_s, group_owner_bssid, ssid, passphrase);
+	if (wpa_network == NULL) {
+		wpa_printf(MSG_ERROR, "P2P: Cannot construct a network for group join.");
+		return -1;
+	}
+
+	// this is temporary network only for establishing the connection.
+	wpa_network->temporary = 1;
+
+	if (wpas_p2p_group_add_persistent(
+		wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
+		VHT_CHANWIDTH_USE_HT, NULL, 0, 1)) {
+		ret = -1;
+	}
+
+	// Always remove this temporary network at the end.
+	wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+	return ret;
+}
+
+void notifyGroupJoinFailure(
+    struct wpa_supplicant* wpa_s)
+{
+	u8 zero_addr[ETH_ALEN] = {0};
+	std::vector<uint8_t> ssid = {'D', 'I', 'R', 'E','C', 'T', '-'};
+	std::string passphrase = "";
+	struct wpa_ssid *wpa_network = addGroupClientNetwork(
+	    wpa_s, zero_addr, ssid, passphrase);
+	if (wpa_network) {
+		wpa_network->temporary = 1;
+		wpas_notify_p2p_group_formation_failure(wpa_s, "Failed to find the group.");
+		wpas_notify_p2p_group_removed(
+		    wpa_s, wpa_network, "client");
+		wpa_config_remove_network(
+		    wpa_s->conf, wpa_network->id);
+	} else {
+		wpa_printf(MSG_ERROR,
+		    "P2P: Cannot construct a network.");
+	}
+}
+
+void scanResJoinIgnore(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) {
+	wpa_printf(MSG_DEBUG, "P2P: Ignore group join scan results.");
+}
+
 }  // namespace
 
 namespace android {
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
 P2pIface::P2pIface(struct wpa_global* wpa_global, const char ifname[])
     : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
+{}
 
 void P2pIface::invalidate() { is_valid_ = false; }
 bool P2pIface::isValid()
@@ -505,6 +826,24 @@
 	    &P2pIface::saveConfigInternal, _hidl_cb);
 }
 
+Return<void> P2pIface::addGroup_1_2(
+    const hidl_vec<uint8_t>& ssid, const hidl_string& passphrase,
+    bool persistent, uint32_t freq, const hidl_array<uint8_t, 6>& peer_address,
+    bool join, addGroup_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &P2pIface::addGroup_1_2Internal, _hidl_cb,
+	    ssid, passphrase, persistent, freq, peer_address, join);
+}
+
+Return<void> P2pIface::setMacRandomization(bool enable, setMacRandomization_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &P2pIface::setMacRandomizationInternal, _hidl_cb, enable);
+}
+
 std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -656,6 +995,11 @@
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
 		return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
 	}
+	if (wpa_s->scan_res_handler == scanResJoinWrapper) {
+		wpa_printf(MSG_DEBUG, "P2P: Stop pending group scan for stopping find).");
+		pending_scan_res_join_callback = NULL;
+		wpa_s->scan_res_handler = scanResJoinIgnore;
+	}
 	wpas_p2p_stop_find(wpa_s);
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
@@ -699,11 +1043,12 @@
 	}
 	int vht = wpa_s->conf->p2p_go_vht;
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
-	const char* pin = pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
+	const char* pin =
+	    pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
 	int new_pin = wpas_p2p_connect(
-	    wpa_s, peer_address.data(), pin, wps_method,
-	    persistent, false, join_existing_group, false, go_intent_signed, 0, 0, -1,
-	    false, ht40, vht, VHT_CHANWIDTH_USE_HT, nullptr, 0);
+	    wpa_s, peer_address.data(), pin, wps_method, persistent, false,
+	    join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
+	    vht, VHT_CHANWIDTH_USE_HT, nullptr, 0);
 	if (new_pin < 0) {
 		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
 	}
@@ -718,6 +1063,11 @@
 SupplicantStatus P2pIface::cancelConnectInternal()
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	if (wpa_s->scan_res_handler == scanResJoinWrapper) {
+		wpa_printf(MSG_DEBUG, "P2P: Stop pending group scan for canceling connect");
+		pending_scan_res_join_callback = NULL;
+		wpa_s->scan_res_handler = scanResJoinIgnore;
+	}
 	if (wpas_p2p_cancel(wpa_s)) {
 		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 	}
@@ -868,8 +1218,8 @@
 	DestT* freq_ranges = nullptr;
 	// Empty ranges is used to enable all frequencies.
 	if (ranges.size() != 0) {
-		freq_ranges =
-		    static_cast<DestT*>(os_malloc(sizeof(DestT) * ranges.size()));
+		freq_ranges = static_cast<DestT*>(
+		    os_malloc(sizeof(DestT) * ranges.size()));
 		if (!freq_ranges) {
 			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 		}
@@ -1064,7 +1414,7 @@
 #ifdef CONFIG_AP
 	if (wpa_group_s->ap_iface) {
 		if (wpa_supplicant_ap_wps_pin(
-				wpa_group_s, nullptr, pin.c_str(), nullptr, 0, 0) < 0) {
+			wpa_group_s, nullptr, pin.c_str(), nullptr, 0, 0) < 0) {
 			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 		}
 		return {SupplicantStatusCode::SUCCESS, ""};
@@ -1256,6 +1606,179 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus P2pIface::addGroup_1_2Internal(
+    const std::vector<uint8_t>& ssid, const std::string& passphrase,
+    bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
+    bool joinExistingGroup)
+{
+	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	int vht = wpa_s->conf->p2p_go_vht;
+	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+
+	if (!isSsidValid(ssid)) {
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "SSID is invalid."};
+	}
+
+	if (!isPskPassphraseValid(passphrase)) {
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "passphrase is invalid."};
+	}
+
+	if (!joinExistingGroup) {
+		if (wpa_s->global->p2p == NULL) {
+			return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+		}
+
+		struct p2p_data *p2p = wpa_s->global->p2p;
+		os_memcpy(p2p->ssid, ssid.data(), ssid.size());
+		p2p->ssid_len = ssid.size();
+		p2p->ssid_set = 1;
+
+		os_memset(p2p->passphrase, 0, sizeof(p2p->passphrase));
+		os_memcpy(p2p->passphrase, passphrase.c_str(), passphrase.length());
+		p2p->passphrase_set = 1;
+
+		if (wpas_p2p_group_add(
+		    wpa_s, persistent, freq, 0, ht40, vht,
+		    VHT_CHANWIDTH_USE_HT)) {
+			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+		}
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+
+	// The rest is for group join.
+	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND before group join.");
+	wpas_p2p_stop_find(wpa_s);
+
+	struct wpa_bss *bss = findBssBySsid(
+	    wpa_s, peer_address.data(),
+	    ssid.data(), ssid.size());
+	if (bss != NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Join group with Group Owner " MACSTR,
+		    MAC2STR(bss->bssid));
+		if (0 != joinGroup(wpa_s, bss->bssid, ssid, passphrase)) {
+			// no need to notify group join failure here,
+			// it will be handled by wpas_p2p_group_add_persistent
+			// called in joinGroup.
+			return {SupplicantStatusCode::FAILURE_UNKNOWN, "Failed to join a group."};
+		}
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+
+	wpa_printf(MSG_INFO, "No matched BSS exists, try to find it by scan");
+
+	if (wpa_s->scan_res_handler) {
+		wpa_printf(MSG_WARNING, "There is on-going scanning, cannot start another scan.");
+		return {SupplicantStatusCode::FAILURE_UNKNOWN,
+		    "Failed to start scan due to device busy."};
+	}
+
+	if (pending_scan_res_join_callback != NULL) {
+		wpa_printf(MSG_WARNING, "There is running group join scan.");
+		return {SupplicantStatusCode::FAILURE_UNKNOWN,
+		    "Failed to start scan due to device busy."};
+	}
+
+	pending_join_scan_callback =
+	    [wpa_s, ssid, freq]() {
+		if (0 != joinScanReq(wpa_s, ssid, freq)) {
+			notifyGroupJoinFailure(wpa_s);
+			pending_scan_res_join_callback = NULL;
+		}
+	};
+
+	pending_scan_res_join_callback = [wpa_s, ssid, passphrase, peer_address, this]() {
+		if (wpa_s->global->p2p_disabled) {
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "P2P: Scan results received for join (reinvoke).");
+
+		struct wpa_bss *bss = findBssBySsid(
+		    wpa_s, peer_address.data(), ssid.data(), ssid.size());
+		if (bss) {
+			if (0 != joinGroup(wpa_s, bss->bssid, ssid, passphrase)) {
+				wpa_printf(MSG_ERROR, "P2P: Failed to join a group.");
+			}
+			// no need to notify group join failure here,
+			// it will be handled by wpas_p2p_group_add_persistent
+			// called in joinGroup.
+			pending_scan_res_join_callback = NULL;
+			return;
+		}
+
+		wpa_s->p2p_join_scan_count++;
+		wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d.", wpa_s->p2p_join_scan_count);
+		eloop_cancel_timeout(joinScanWrapper, wpa_s, NULL);
+		if (wpa_s->p2p_join_scan_count <= P2P_MAX_JOIN_SCAN_ATTEMPTS) {
+			wpa_printf(MSG_DEBUG, "P2P: Try join again later.");
+			eloop_register_timeout(1, 0, joinScanWrapper, wpa_s, this);
+			return;
+		}
+
+		wpa_printf(MSG_ERROR, "P2P: Failed to find the group with "
+		    "network name %s - stop join attempt",
+		    ssid.data());
+		notifyGroupJoinFailure(wpa_s);
+		pending_scan_res_join_callback = NULL;
+	};
+
+	wpa_s->p2p_join_scan_count = 0;
+	if (0 != joinScanReq(wpa_s, ssid, freq)) {
+		pending_scan_res_join_callback = NULL;
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, "Failed to start scan."};
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setMacRandomizationInternal(bool enable)
+{
+	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	bool currentEnabledState = !!wpa_s->conf->p2p_device_random_mac_addr;
+	u8 *addr = NULL;
+
+	// The same state, no change is needed.
+	if (currentEnabledState == enable) {
+		wpa_printf(MSG_DEBUG, "The random MAC is %s already.",
+		    (enable) ? "enabled" : "disabled");
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+
+	if (enable) {
+		wpa_s->conf->p2p_device_random_mac_addr = 1;
+		wpa_s->conf->p2p_interface_random_mac_addr = 1;
+
+		// restore config if it failed to set up MAC address.
+		if (wpas_p2p_mac_setup(wpa_s) < 0) {
+			wpa_s->conf->p2p_device_random_mac_addr = 0;
+			wpa_s->conf->p2p_interface_random_mac_addr = 0;
+			return {SupplicantStatusCode::FAILURE_UNKNOWN,
+			    "Failed to set up MAC address."};
+		}
+	} else {
+		// disable random MAC will use original MAC address
+		// regardless of any saved persistent groups.
+		if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
+			wpa_printf(MSG_ERROR, "Failed to restore MAC address");
+			return {SupplicantStatusCode::FAILURE_UNKNOWN,
+			    "Failed to restore MAC address."};
+		}
+
+		if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+			wpa_printf(MSG_INFO, "Could not update MAC address information");
+			return {SupplicantStatusCode::FAILURE_UNKNOWN,
+			    "Failed to update MAC address."};
+		}
+		wpa_s->conf->p2p_device_random_mac_addr = 0;
+		wpa_s->conf->p2p_interface_random_mac_addr = 0;
+	}
+
+	// update internal data to send out correct device address in action frame.
+	os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(wpa_s->global->p2p->cfg->dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
+
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
@@ -1277,8 +1800,8 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wpa_supplicant/hidl/1.1/p2p_iface.h b/wpa_supplicant/hidl/1.2/p2p_iface.h
similarity index 93%
rename from wpa_supplicant/hidl/1.1/p2p_iface.h
rename to wpa_supplicant/hidl/1.2/p2p_iface.h
index 019e534..bd43a5a 100644
--- a/wpa_supplicant/hidl/1.1/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.2/p2p_iface.h
@@ -15,11 +15,12 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
 
-extern "C" {
+extern "C"
+{
 #include "utils/common.h"
 #include "utils/includes.h"
 #include "p2p/p2p.h"
@@ -33,16 +34,17 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using namespace android::hardware::wifi::supplicant::V1_0;
+using namespace android::hardware::wifi::supplicant::V1_1;
 
 /**
  * Implementation of P2pIface hidl object. Each unique hidl
  * object is used for control operations on a specific interface
  * controlled by wpa_supplicant.
  */
-class P2pIface : public ISupplicantP2pIface
+class P2pIface : public V1_2::ISupplicantP2pIface
 {
 public:
 	P2pIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -185,6 +187,12 @@
 	    const hidl_vec<uint8_t>& select,
 	    reportNfcHandoverInitiation_cb _hidl_cb) override;
 	Return<void> saveConfig(saveConfig_cb _hidl_cb) override;
+	Return<void> addGroup_1_2(
+	    const hidl_vec<uint8_t>& ssid, const hidl_string& passphrase,
+	    bool persistent, uint32_t freq, const hidl_array<uint8_t, 6>& peer_address,
+	    bool joinExistingGroup, addGroup_1_2_cb _hidl_cb) override;
+	Return<void> setMacRandomization(
+	    bool enable, setMacRandomization_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -289,6 +297,11 @@
 	SupplicantStatus reportNfcHandoverInitiationInternal(
 	    const std::vector<uint8_t>& select);
 	SupplicantStatus saveConfigInternal();
+	SupplicantStatus addGroup_1_2Internal(
+	    const std::vector<uint8_t>& ssid, const std::string& passphrase,
+	    bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
+	    bool joinExistingGroup);
+	SupplicantStatus setMacRandomizationInternal(bool enable);
 
 	struct wpa_supplicant* retrieveIfacePtr();
 	struct wpa_supplicant* retrieveGroupIfacePtr(
@@ -305,9 +318,9 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
 
diff --git a/wpa_supplicant/hidl/1.1/p2p_network.cpp b/wpa_supplicant/hidl/1.2/p2p_network.cpp
similarity index 97%
rename from wpa_supplicant/hidl/1.1/p2p_network.cpp
rename to wpa_supplicant/hidl/1.2/p2p_network.cpp
index 7458fd9..693b2c0 100644
--- a/wpa_supplicant/hidl/1.1/p2p_network.cpp
+++ b/wpa_supplicant/hidl/1.2/p2p_network.cpp
@@ -11,7 +11,8 @@
 #include "hidl_return_util.h"
 #include "p2p_network.h"
 
-extern "C" {
+extern "C"
+{
 #include "config_ssid.h"
 }
 
@@ -19,7 +20,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -29,8 +30,7 @@
       ifname_(ifname),
       network_id_(network_id),
       is_valid_(true)
-{
-}
+{}
 
 void P2pNetwork::invalidate() { is_valid_ = false; }
 bool P2pNetwork::isValid()
@@ -137,9 +137,8 @@
     const sp<ISupplicantP2pNetworkCallback> &callback)
 {
 	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->addP2pNetworkCallbackHidlObject(
-		ifname_, network_id_, callback)) {
+	if (!hidl_manager || hidl_manager->addP2pNetworkCallbackHidlObject(
+				 ifname_, network_id_, callback)) {
 		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	return {SupplicantStatusCode::SUCCESS, ""};
@@ -250,8 +249,8 @@
 	    (struct wpa_global *)wpa_global_, ifname_.c_str());
 }
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wpa_supplicant/hidl/1.1/p2p_network.h b/wpa_supplicant/hidl/1.2/p2p_network.h
similarity index 96%
rename from wpa_supplicant/hidl/1.1/p2p_network.h
rename to wpa_supplicant/hidl/1.2/p2p_network.h
index 3c36f6d..e2e8ec2 100644
--- a/wpa_supplicant/hidl/1.1/p2p_network.h
+++ b/wpa_supplicant/hidl/1.2/p2p_network.h
@@ -15,7 +15,8 @@
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
 
-extern "C" {
+extern "C"
+{
 #include "utils/common.h"
 #include "utils/includes.h"
 #include "wpa_supplicant_i.h"
@@ -25,9 +26,10 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using namespace android::hardware::wifi::supplicant::V1_0;
+using namespace android::hardware::wifi::supplicant::V1_1;
 
 /**
  * Implementation of P2pNetwork hidl object. Each unique hidl
@@ -94,9 +96,9 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
 
diff --git a/wpa_supplicant/hidl/1.1/sta_iface.cpp b/wpa_supplicant/hidl/1.2/sta_iface.cpp
similarity index 78%
rename from wpa_supplicant/hidl/1.1/sta_iface.cpp
rename to wpa_supplicant/hidl/1.2/sta_iface.cpp
index 6436745..8c5178e 100644
--- a/wpa_supplicant/hidl/1.1/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.2/sta_iface.cpp
@@ -13,19 +13,22 @@
 #include "misc_utils.h"
 #include "sta_iface.h"
 
-extern "C" {
+extern "C"
+{
 #include "utils/eloop.h"
 #include "gas_query.h"
 #include "interworking.h"
 #include "hs20_supplicant.h"
 #include "wps_supplicant.h"
+#include "dpp_supplicant.h"
+#include "dpp.h"
 }
 
 namespace {
-using android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
 using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using android::hardware::wifi::supplicant::V1_1::implementation::HidlManager;
+using android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_2::implementation::HidlManager;
 
 constexpr uint32_t kMaxAnqpElems = 100;
 constexpr char kGetMacAddress[] = "MACADDR";
@@ -155,7 +158,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -165,8 +168,7 @@
 
 StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
     : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
+{}
 
 void StaIface::invalidate() { is_valid_ = false; }
 bool StaIface::isValid()
@@ -219,8 +221,8 @@
 }
 
 Return<void> StaIface::registerCallback(
-    const sp<ISupplicantStaIfaceCallback>
-    & callback, registerCallback_cb _hidl_cb)
+    const sp<ISupplicantStaIfaceCallback> &callback,
+    registerCallback_cb _hidl_cb)
 {
 	return validateAndCall(
 	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
@@ -231,12 +233,22 @@
     const sp<V1_1::ISupplicantStaIfaceCallback> &callback,
     registerCallback_cb _hidl_cb)
 {
-	sp<V1_0::ISupplicantStaIfaceCallback> callback_1_0 =  callback;
+	sp<V1_0::ISupplicantStaIfaceCallback> callback_1_0 = callback;
 	return validateAndCall(
 	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
 	    &StaIface::registerCallbackInternal, _hidl_cb, callback_1_0);
 }
 
+Return<void> StaIface::registerCallback_1_2(
+    const sp<V1_2::ISupplicantStaIfaceCallback> &callback,
+    registerCallback_cb _hidl_cb)
+{
+	sp<V1_1::ISupplicantStaIfaceCallback> callback_1_1 = callback;
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::registerCallbackInternal, _hidl_cb, callback_1_1);
+}
+
 Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
 {
 	return validateAndCall(
@@ -511,6 +523,58 @@
 	    &StaIface::enableAutoReconnectInternal, _hidl_cb, enable);
 }
 
+Return<void> StaIface::getKeyMgmtCapabilities(
+    getKeyMgmtCapabilities_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaIface::getKeyMgmtCapabilitiesInternal, _hidl_cb);
+}
+
+Return<void> StaIface::addDppPeerUri(const hidl_string& uri,
+		addDppPeerUri_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaIface::addDppPeerUriInternal, _hidl_cb, uri);
+}
+
+Return<void> StaIface::removeDppUri(uint32_t bootstrap_id,
+		removeDppUri_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaIface::removeDppUriInternal, _hidl_cb, bootstrap_id);
+}
+
+Return<void> StaIface::startDppConfiguratorInitiator(uint32_t peer_bootstrap_id,
+		uint32_t own_bootstrap_id, const hidl_string& ssid,
+		const hidl_string& password, const hidl_string& psk,
+		DppNetRole net_role, DppAkm security_akm,
+		startDppConfiguratorInitiator_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaIface::startDppConfiguratorInitiatorInternal, _hidl_cb, peer_bootstrap_id,
+		own_bootstrap_id, ssid, password, psk, net_role, security_akm);
+}
+
+Return<void> StaIface::startDppEnrolleeInitiator(uint32_t peer_bootstrap_id,
+		uint32_t own_bootstrap_id, startDppConfiguratorInitiator_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaIface::startDppEnrolleeInitiatorInternal, _hidl_cb, peer_bootstrap_id,
+		own_bootstrap_id);
+}
+
+Return<void> StaIface::stopDppInitiator(stopDppInitiator_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaIface::stopDppInitiatorInternal, _hidl_cb);
+}
+
 std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -1016,6 +1080,225 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+std::pair<SupplicantStatus, uint32_t>
+StaIface::getKeyMgmtCapabilitiesInternal()
+{
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct wpa_driver_capa capa;
+	uint32_t mask = 0;
+
+	/* Get capabilities from driver and populate the key management mask */
+	if (wpa_drv_get_capa(wpa_s, &capa) < 0) {
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, mask};
+	}
+
+	/* Logic from ctrl_iface.c, NONE and IEEE8021X have no capability
+	 * flags and always enabled.
+	 */
+	mask |=
+	    (ISupplicantStaNetwork::KeyMgmtMask::NONE |
+	     ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
+
+	if (capa.key_mgmt &
+	    (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+		mask |= ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP;
+	}
+
+	if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+			     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+		mask |= ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK;
+	}
+#ifdef CONFIG_SUITEB192
+	if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+		mask |= ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192;
+	}
+#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_OWE
+	if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+		mask |= ISupplicantStaNetwork::KeyMgmtMask::OWE;
+	}
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_SAE
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
+		mask |= ISupplicantStaNetwork::KeyMgmtMask::SAE;
+	}
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_DPP
+	if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+		mask |= ISupplicantStaNetwork::KeyMgmtMask::DPP;
+	}
+#endif
+	return {{SupplicantStatusCode::SUCCESS, ""}, mask};
+}
+
+std::pair<SupplicantStatus, uint32_t>
+StaIface::addDppPeerUriInternal(const std::string& uri)
+{
+#ifdef CONFIG_DPP
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	int32_t id;
+
+	id = wpas_dpp_qr_code(wpa_s, uri.c_str());
+
+	if (id > 0) {
+		return {{SupplicantStatusCode::SUCCESS, ""}, id};
+	}
+#endif
+	return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, -1};
+}
+
+SupplicantStatus StaIface::removeDppUriInternal(uint32_t bootstrap_id)
+{
+#ifdef CONFIG_DPP
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	std::string bootstrap_id_str;
+
+	if (bootstrap_id == 0) {
+		bootstrap_id_str = "*";
+	}
+	else {
+		bootstrap_id_str = std::to_string(bootstrap_id);
+	}
+
+	if (wpas_dpp_bootstrap_remove(wpa_s, bootstrap_id_str.c_str()) >= 0) {
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+#endif
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+SupplicantStatus StaIface::startDppConfiguratorInitiatorInternal(
+		uint32_t peer_bootstrap_id,	uint32_t own_bootstrap_id,
+		const std::string& ssid, const std::string& password,
+		const std::string& psk, DppNetRole net_role, DppAkm security_akm)
+{
+#ifdef CONFIG_DPP
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	std::string cmd = "";
+
+	if (net_role != DppNetRole::AP &&
+			net_role != DppNetRole::STA) {
+		wpa_printf(MSG_ERROR,
+			   "DPP: Error: Invalid network role specified: %d", net_role);
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+
+	cmd += " peer=" + std::to_string(peer_bootstrap_id);
+	cmd += (own_bootstrap_id > 0) ?
+			" own=" + std::to_string(own_bootstrap_id) : "";
+
+	/* Check for supported AKMs */
+	if (security_akm != DppAkm::PSK && security_akm != DppAkm::SAE &&
+			security_akm != DppAkm::PSK_SAE) {
+		wpa_printf(MSG_ERROR, "DPP: Error: invalid AKM specified: %d",
+				security_akm);
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+
+	/* SAE AKM requires SSID and password to be initialized */
+	if ((security_akm == DppAkm::SAE ||
+			security_akm == DppAkm::PSK_SAE) &&
+			(ssid.empty() || password.empty())) {
+		wpa_printf(MSG_ERROR, "DPP: Error: Password or SSID not specified");
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	} else if (security_akm == DppAkm::PSK ||
+			security_akm == DppAkm::PSK_SAE) {
+		/* PSK AKM requires SSID and password/psk to be initialized */
+		if (ssid.empty()) {
+			wpa_printf(MSG_ERROR, "DPP: Error: SSID not specified");
+			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+		}
+		if (password.empty() && psk.empty()) {
+			wpa_printf(MSG_ERROR, "DPP: Error: Password or PSK not specified");
+			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+		}
+	}
+
+	cmd += " role=configurator";
+	cmd += (ssid.empty()) ? "" : " ssid=" + ssid;
+
+	if (!psk.empty()) {
+		cmd += " psk=" + psk;
+	} else {
+		cmd += (password.empty()) ? "" : " pass=" + password;
+	}
+
+	std::string role = "";
+	if (net_role == DppNetRole::AP) {
+		role = "ap-";
+	}
+	else {
+		role = "sta-";
+	}
+
+	switch (security_akm) {
+	case DppAkm::PSK:
+		role += "psk";
+		break;
+
+	case DppAkm::SAE:
+		role += "sae";
+		break;
+
+	case DppAkm::PSK_SAE:
+		role += "psk-sae";
+		break;
+
+	default:
+		wpa_printf(MSG_ERROR,
+			   "DPP: Invalid or unsupported security AKM specified: %d", security_akm);
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+
+	cmd += " conf=";
+	cmd += role;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP initiator command: %s", cmd.c_str());
+
+	if (wpas_dpp_auth_init(wpa_s, cmd.c_str()) == 0) {
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+#endif
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+SupplicantStatus StaIface::startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id,
+			uint32_t own_bootstrap_id) {
+#ifdef CONFIG_DPP
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	std::string cmd = "";
+
+	/* Report received configuration to HIDL and create an internal profile */
+	wpa_s->conf->dpp_config_processing = 1;
+
+	cmd += " peer=" + std::to_string(peer_bootstrap_id);
+	cmd += (own_bootstrap_id > 0) ?
+			" own=" + std::to_string(own_bootstrap_id) : "";
+
+	cmd += " role=enrollee";
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP initiator command: %s", cmd.c_str());
+
+	if (wpas_dpp_auth_init(wpa_s, cmd.c_str()) == 0) {
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+#endif
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+SupplicantStatus StaIface::stopDppInitiatorInternal()
+{
+#ifdef CONFIG_DPP
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+
+	wpas_dpp_stop(wpa_s);
+	return {SupplicantStatusCode::SUCCESS, ""};
+#else
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
@@ -1027,8 +1310,8 @@
 	return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
 }
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wpa_supplicant/hidl/1.0/sta_iface.h b/wpa_supplicant/hidl/1.2/sta_iface.h
similarity index 81%
rename from wpa_supplicant/hidl/1.0/sta_iface.h
rename to wpa_supplicant/hidl/1.2/sta_iface.h
index 6e62260..5a04ee3 100644
--- a/wpa_supplicant/hidl/1.0/sta_iface.h
+++ b/wpa_supplicant/hidl/1.2/sta_iface.h
@@ -15,11 +15,12 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
 
-extern "C" {
+extern "C"
+{
 #include "utils/common.h"
 #include "utils/includes.h"
 #include "wpa_supplicant_i.h"
@@ -32,16 +33,16 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
 namespace implementation {
+using namespace android::hardware::wifi::supplicant::V1_2;
 
 /**
  * Implementation of StaIface hidl object. Each unique hidl
  * object is used for control operations on a specific interface
  * controlled by wpa_supplicant.
  */
-class StaIface
-    : public android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface
+class StaIface : public V1_2::ISupplicantStaIface
 {
 public:
 	StaIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -71,7 +72,13 @@
 	    SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
 	Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
 	Return<void> registerCallback(
-	    const sp<ISupplicantStaIfaceCallback>& callback,
+	    const sp<V1_0::ISupplicantStaIfaceCallback>& callback,
+	    registerCallback_cb _hidl_cb) override;
+	Return<void> registerCallback_1_1(
+	    const sp<V1_1::ISupplicantStaIfaceCallback>& callback,
+	    registerCallback_cb _hidl_cb) override;
+	Return<void> registerCallback_1_2(
+	    const sp<V1_2::ISupplicantStaIfaceCallback>& callback,
 	    registerCallback_cb _hidl_cb) override;
 	Return<void> reassociate(reassociate_cb _hidl_cb) override;
 	Return<void> reconnect(reconnect_cb _hidl_cb) override;
@@ -155,6 +162,21 @@
 	    uint32_t id, removeExtRadioWork_cb _hidl_cb) override;
 	Return<void> enableAutoReconnect(
 	    bool enable, enableAutoReconnect_cb _hidl_cb) override;
+	Return<void> getKeyMgmtCapabilities(
+	    getKeyMgmtCapabilities_cb _hidl_cb) override;
+	Return<void> addDppPeerUri(const hidl_string& uri,
+			addDppPeerUri_cb _hidl_cb) override;
+	Return<void> removeDppUri(uint32_t bootstrap_id,
+			removeDppUri_cb _hidl_cb) override;
+	Return<void> startDppConfiguratorInitiator(uint32_t peer_bootstrap_id,
+			uint32_t own_bootstrap_id, const hidl_string& ssid,
+			const hidl_string& password, const hidl_string& psk,
+			DppNetRole net_role, DppAkm security_akm,
+			startDppConfiguratorInitiator_cb _hidl_cb) override;
+	Return<void> startDppEnrolleeInitiator(uint32_t peer_bootstrap_id,
+			uint32_t own_bootstrap_id,
+			startDppConfiguratorInitiator_cb _hidl_cb) override;
+	Return<void> stopDppInitiator(stopDppInitiator_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -168,7 +190,9 @@
 	std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
 	listNetworksInternal();
 	SupplicantStatus registerCallbackInternal(
-	    const sp<ISupplicantStaIfaceCallback>& callback);
+	    const sp<V1_0::ISupplicantStaIfaceCallback>& callback);
+	SupplicantStatus registerCallbackInternal_1_1(
+	    const sp<V1_1::ISupplicantStaIfaceCallback>& callback);
 	SupplicantStatus reassociateInternal();
 	SupplicantStatus reconnectInternal();
 	SupplicantStatus disconnectInternal();
@@ -226,6 +250,17 @@
 	    uint32_t timeout_in_sec);
 	SupplicantStatus removeExtRadioWorkInternal(uint32_t id);
 	SupplicantStatus enableAutoReconnectInternal(bool enable);
+	std::pair<SupplicantStatus, uint32_t> getKeyMgmtCapabilitiesInternal();
+	std::pair<SupplicantStatus, uint32_t> addDppPeerUriInternal(const std::string& uri);
+	SupplicantStatus removeDppUriInternal(uint32_t bootstrap_id);
+	SupplicantStatus startDppConfiguratorInitiatorInternal(uint32_t peer_bootstrap_id,
+			uint32_t own_bootstrap_id,
+		    const std::string& ssid, const std::string& password,
+			const std::string& psk, DppNetRole net_role, DppAkm security_akm);
+	SupplicantStatus startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id,
+			uint32_t own_bootstrap_id);
+	SupplicantStatus stopDppInitiatorInternal();
+
 
 	struct wpa_supplicant* retrieveIfacePtr();
 
@@ -240,9 +275,9 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
 
diff --git a/wpa_supplicant/hidl/1.1/sta_network.cpp b/wpa_supplicant/hidl/1.2/sta_network.cpp
similarity index 87%
rename from wpa_supplicant/hidl/1.1/sta_network.cpp
rename to wpa_supplicant/hidl/1.2/sta_network.cpp
index 9d4cc91..780c5a1 100644
--- a/wpa_supplicant/hidl/1.1/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.2/sta_network.cpp
@@ -12,13 +12,15 @@
 #include "misc_utils.h"
 #include "sta_network.h"
 
-extern "C" {
+extern "C"
+{
 #include "wps_supplicant.h"
 }
 
 namespace {
-using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
+using namespace android::hardware::wifi::supplicant::V1_2;
 
 constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
 
@@ -29,7 +31,12 @@
      static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) |
      static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) |
      static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN));
+     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN) |
+     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SAE) |
+     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) |
+     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OWE) |
+     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) |
+     static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256));
 constexpr uint32_t kAllowedProtoMask =
     (static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) |
      static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) |
@@ -44,11 +51,21 @@
      static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) |
      static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) |
      static_cast<uint32_t>(
-	 ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED));
+	 ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) |
+     static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GCMP_256));
 constexpr uint32_t kAllowedPairwisewCipherMask =
     (static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
      static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
-     static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP));
+     static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) |
+     static_cast<uint32_t>(
+	 ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256));
+constexpr uint32_t kAllowedGroupMgmtCipherMask =
+	(static_cast<uint32_t>(
+			ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_128) |
+	 static_cast<uint32_t>(
+			 ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_256) |
+	 static_cast<uint32_t>(
+			 ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_CMAC_256));
 
 constexpr uint32_t kEapMethodMax =
     static_cast<uint32_t>(ISupplicantStaNetwork::EapMethod::WFA_UNAUTH_TLS) + 1;
@@ -72,7 +89,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -82,8 +99,7 @@
       ifname_(ifname),
       network_id_(network_id),
       is_valid_(true)
-{
-}
+{}
 
 void StaNetwork::invalidate() { is_valid_ = false; }
 bool StaNetwork::isValid()
@@ -250,11 +266,13 @@
 }
 
 Return<void> StaNetwork::setEapEncryptedImsiIdentity(
-    const EapSimEncryptedIdentity &identity, setEapEncryptedImsiIdentity_cb _hidl_cb)
+    const EapSimEncryptedIdentity &identity,
+    setEapEncryptedImsiIdentity_cb _hidl_cb)
 {
 	return validateAndCall(
 	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
-	    &StaNetwork::setEapEncryptedImsiIdentityInternal, _hidl_cb, identity);
+	    &StaNetwork::setEapEncryptedImsiIdentityInternal, _hidl_cb,
+	    identity);
 }
 
 Return<void> StaNetwork::setEapAnonymousIdentity(
@@ -438,6 +456,20 @@
 	    &StaNetwork::getPskInternal, _hidl_cb);
 }
 
+Return<void> StaNetwork::getSaePassword(getSaePassword_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getSaePasswordInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getSaePasswordId(getSaePasswordId_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getSaePasswordIdInternal, _hidl_cb);
+}
+
 Return<void> StaNetwork::getWepKey(uint32_t key_idx, getWepKey_cb _hidl_cb)
 {
 	return validateAndCall(
@@ -664,6 +696,101 @@
 	    identity, encrypted_imsi_identity);
 }
 
+Return<void> StaNetwork::setKeyMgmt_1_2(
+    uint32_t key_mgmt_mask, setKeyMgmt_1_2_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setKeyMgmtInternal, _hidl_cb, key_mgmt_mask);
+}
+
+Return<void> StaNetwork::setGroupCipher_1_2(
+    uint32_t group_cipher_mask, setGroupCipher_1_2_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setGroupCipherInternal, _hidl_cb, group_cipher_mask);
+}
+
+Return<void> StaNetwork::setGroupMgmtCipher(
+    uint32_t group_mgmt_cipher_mask, setGroupMgmtCipher_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setGroupMgmtCipherInternal,
+		_hidl_cb, group_mgmt_cipher_mask);
+}
+
+Return<void> StaNetwork::getGroupMgmtCipher(getGroupMgmtCipher_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getGroupMgmtCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setPairwiseCipher_1_2(
+    uint32_t pairwise_cipher_mask, setPairwiseCipher_1_2_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setPairwiseCipherInternal, _hidl_cb,
+	    pairwise_cipher_mask);
+}
+
+Return<void> StaNetwork::getKeyMgmt_1_2(getKeyMgmt_1_2_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getKeyMgmtInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getGroupCipher_1_2(getGroupCipher_1_2_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getGroupCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getPairwiseCipher_1_2(
+    getPairwiseCipher_1_2_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getPairwiseCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::enableTlsSuiteBEapPhase1Param(
+    bool enable, enableTlsSuiteBEapPhase1Param_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::enableTlsSuiteBEapPhase1ParamInternal, _hidl_cb, enable);
+}
+
+Return<void> StaNetwork::enableSuiteBEapOpenSslCiphers(
+    enableSuiteBEapOpenSslCiphers_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::enableSuiteBEapOpenSslCiphersInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setSaePassword(
+    const hidl_string &sae_password, setSaePassword_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setSaePasswordInternal, _hidl_cb, sae_password);
+}
+
+Return<void> StaNetwork::setSaePasswordId(
+    const hidl_string &sae_password_id, setSaePasswordId_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setSaePasswordIdInternal, _hidl_cb, sae_password_id);
+}
+
 std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -683,9 +810,8 @@
     const sp<ISupplicantStaNetworkCallback> &callback)
 {
 	HidlManager *hidl_manager = HidlManager::getInstance();
-	if (!hidl_manager ||
-	    hidl_manager->addStaNetworkCallbackHidlObject(
-		ifname_, network_id_, callback)) {
+	if (!hidl_manager || hidl_manager->addStaNetworkCallbackHidlObject(
+				 ifname_, network_id_, callback)) {
 		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	return {SupplicantStatusCode::SUCCESS, ""};
@@ -884,8 +1010,9 @@
 SupplicantStatus StaNetwork::setRequirePmfInternal(bool enable)
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	wpa_ssid->ieee80211w =
-	    enable ? MGMT_FRAME_PROTECTION_REQUIRED : NO_MGMT_FRAME_PROTECTION;
+	if (enable) {
+		wpa_ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+	}
 	resetInternalStateAfterParamsUpdate();
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
@@ -989,13 +1116,14 @@
 	if (setByteArrayFieldAndResetState(
 		identity.data(), identity.size(), &(wpa_ssid->eap.identity),
 		&(wpa_ssid->eap.identity_len), "eap identity")) {
-		return { SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	// plain IMSI identity
 	if (setByteArrayFieldAndResetState(
-		identity.data(), identity.size(), &(wpa_ssid->eap.imsi_identity),
+		identity.data(), identity.size(),
+		&(wpa_ssid->eap.imsi_identity),
 		&(wpa_ssid->eap.imsi_identity_len), "eap imsi identity")) {
-		return { SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
@@ -1247,6 +1375,24 @@
 	return {{SupplicantStatusCode::SUCCESS, ""}, psk};
 }
 
+std::pair<SupplicantStatus, std::string> StaNetwork::getSaePasswordInternal()
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	if (!wpa_ssid->sae_password) {
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+	}
+	return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->sae_password};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getSaePasswordIdInternal()
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	if (!wpa_ssid->sae_password_id) {
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+	}
+	return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->sae_password_id};
+}
+
 std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getWepKeyInternal(
     uint32_t key_idx)
 {
@@ -1681,13 +1827,16 @@
 }
 
 SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal_1_1(
-    const std::vector<uint8_t> &identity, const std::vector<uint8_t> &encrypted_imsi_identity)
+    const std::vector<uint8_t> &identity,
+    const std::vector<uint8_t> &encrypted_imsi_identity)
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	// format: plain identity + ":" + encrypted identity(encrypted_imsi_identity)
+	// format: plain identity + ":" + encrypted
+	// identity(encrypted_imsi_identity)
 	std::string ctrl_rsp_param =
-		std::string(identity.begin(), identity.end()) + ":" +
-		std::string(encrypted_imsi_identity.begin(), encrypted_imsi_identity.end());
+	    std::string(identity.begin(), identity.end()) + ":" +
+	    std::string(
+		encrypted_imsi_identity.begin(), encrypted_imsi_identity.end());
 	enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_EAP_IDENTITY;
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	if (wpa_supplicant_ctrl_rsp_handle(
@@ -1702,6 +1851,99 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus StaNetwork::enableTlsSuiteBEapPhase1ParamInternal(bool enable)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	int val = enable == true ? 1 : 0;
+	std::string suiteb_phase1("tls_suiteb=" + std::to_string(val));
+
+	if (setStringKeyFieldAndResetState(
+		suiteb_phase1.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::enableSuiteBEapOpenSslCiphersInternal()
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	const char openssl_suiteb_cipher[] = "SUITE_B_192";
+
+	if (setStringKeyFieldAndResetState(
+		openssl_suiteb_cipher, &(wpa_ssid->eap.openssl_ciphers),
+		"openssl_ciphers")) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setSaePasswordInternal(
+    const std::string &sae_password)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	if (sae_password.length() < 1) {
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+	}
+	if (wpa_ssid->sae_password &&
+	    os_strlen(wpa_ssid->sae_password) == sae_password.length() &&
+	    os_memcmp(
+		wpa_ssid->sae_password, sae_password.c_str(),
+		sae_password.length()) == 0) {
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+	wpa_ssid->psk_set = 1;
+	if (setStringKeyFieldAndResetState(
+		sae_password.c_str(), &(wpa_ssid->sae_password),
+		"sae password")) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setSaePasswordIdInternal(
+    const std::string &sae_password_id)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	if (sae_password_id.length() < 1) {
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+	}
+	if (wpa_ssid->sae_password_id &&
+	    os_strlen(wpa_ssid->sae_password_id) == sae_password_id.length() &&
+	    os_memcmp(
+		wpa_ssid->sae_password_id, sae_password_id.c_str(),
+		sae_password_id.length()) == 0) {
+		return {SupplicantStatusCode::SUCCESS, ""};
+	}
+	wpa_ssid->psk_set = 1;
+	if (setStringKeyFieldAndResetState(
+		sae_password_id.c_str(), &(wpa_ssid->sae_password_id),
+		"sae password id")) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setGroupMgmtCipherInternal(uint32_t
+		group_mgmt_cipher_mask)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	if (group_mgmt_cipher_mask & ~kAllowedGroupMgmtCipherMask) {
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+	}
+	wpa_ssid->group_mgmt_cipher = group_mgmt_cipher_mask;
+	wpa_printf(MSG_MSGDUMP, "group_mgmt_cipher: 0x%x",
+			wpa_ssid->group_mgmt_cipher);
+	resetInternalStateAfterParamsUpdate();
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupMgmtCipherInternal()
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	return {{SupplicantStatusCode::SUCCESS, ""},
+		wpa_ssid->group_mgmt_cipher & kAllowedGroupMgmtCipherMask};
+}
+
 /**
  * Retrieve the underlying |wpa_ssid| struct pointer for
  * this network.
@@ -1879,10 +2121,9 @@
 	resetInternalStateAfterParamsUpdate();
 	return 0;
 }
-
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wpa_supplicant/hidl/1.1/sta_network.h b/wpa_supplicant/hidl/1.2/sta_network.h
similarity index 86%
rename from wpa_supplicant/hidl/1.1/sta_network.h
rename to wpa_supplicant/hidl/1.2/sta_network.h
index b647773..a235257 100644
--- a/wpa_supplicant/hidl/1.1/sta_network.h
+++ b/wpa_supplicant/hidl/1.2/sta_network.h
@@ -15,10 +15,11 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
 
-extern "C" {
+extern "C"
+{
 #include "utils/common.h"
 #include "utils/includes.h"
 #include "config.h"
@@ -33,16 +34,17 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using namespace android::hardware::wifi::supplicant::V1_0;
+using namespace android::hardware::wifi::supplicant::V1_1;
 
 /**
  * Implementation of StaNetwork hidl object. Each unique hidl
  * object is used for control operations on a specific network
  * controlled by wpa_supplicant.
  */
-class StaNetwork : public V1_1::ISupplicantStaNetwork
+class StaNetwork : public V1_2::ISupplicantStaNetwork
 {
 public:
 	StaNetwork(
@@ -109,9 +111,9 @@
 	    const hidl_string& path, setEapClientCert_cb _hidl_cb) override;
 	Return<void> setEapPrivateKeyId(
 	    const hidl_string& id, setEapPrivateKeyId_cb _hidl_cb) override;
-        Return<void> setEapEncryptedImsiIdentity(
-            const EapSimEncryptedIdentity& identity,
-            setEapEncryptedImsiIdentity_cb _hidl_cb) override;
+	Return<void> setEapEncryptedImsiIdentity(
+	    const EapSimEncryptedIdentity& identity,
+	    setEapEncryptedImsiIdentity_cb _hidl_cb) override;
 	Return<void> setEapSubjectMatch(
 	    const hidl_string& match, setEapSubjectMatch_cb _hidl_cb) override;
 	Return<void> setEapAltSubjectMatch(
@@ -140,6 +142,8 @@
 	Return<void> getPairwiseCipher(getPairwiseCipher_cb _hidl_cb) override;
 	Return<void> getPskPassphrase(getPskPassphrase_cb _hidl_cb) override;
 	Return<void> getPsk(getPsk_cb _hidl_cb) override;
+	Return<void> getSaePassword(getSaePassword_cb _hidl_cb) override;
+	Return<void> getSaePasswordId(getSaePasswordId_cb _hidl_cb) override;
 	Return<void> getWepKey(
 	    uint32_t key_idx, getWepKey_cb _hidl_cb) override;
 	Return<void> getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb) override;
@@ -193,6 +197,34 @@
 	    const EapSimIdentity& identity,
 	    const EapSimEncryptedIdentity& imsiIdentity,
 	    sendNetworkEapIdentityResponse_1_1_cb _hidl_cb) override;
+	Return<void> setKeyMgmt_1_2(
+	    uint32_t key_mgmt_mask, setKeyMgmt_1_2_cb _hidl_cb) override;
+	Return<void> getKeyMgmt_1_2(getKeyMgmt_1_2_cb _hidl_cb) override;
+	Return<void> setPairwiseCipher_1_2(
+	    uint32_t pairwise_cipher_mask,
+	    setPairwiseCipher_1_2_cb _hidl_cb) override;
+	Return<void> getPairwiseCipher_1_2(
+	    getPairwiseCipher_1_2_cb _hidl_cb) override;
+	Return<void> setGroupCipher_1_2(
+	    uint32_t group_cipher_mask,
+	    setGroupCipher_1_2_cb _hidl_cb) override;
+	Return<void> getGroupCipher_1_2(
+	    getGroupCipher_1_2_cb _hidl_cb) override;
+	Return<void> setGroupMgmtCipher(
+	    uint32_t group_mgmt_cipher_mask,
+	    setGroupMgmtCipher_cb _hidl_cb) override;
+	Return<void> getGroupMgmtCipher(
+	    getGroupMgmtCipher_cb _hidl_cb) override;
+	Return<void> enableTlsSuiteBEapPhase1Param(
+	    bool enable, enableTlsSuiteBEapPhase1Param_cb _hidl_cb) override;
+	Return<void> enableSuiteBEapOpenSslCiphers(
+	    enableSuiteBEapOpenSslCiphers_cb _hidl_cb) override;
+	Return<void> setSaePassword(
+	    const hidl_string& sae_password,
+	    setSaePassword_cb _hidl_cb) override;
+	Return<void> setSaePasswordId(
+	    const hidl_string& sae_password_id,
+	    setSaePasswordId_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -222,7 +254,7 @@
 	    ISupplicantStaNetwork::EapPhase2Method method);
 	SupplicantStatus setEapIdentityInternal(
 	    const std::vector<uint8_t>& identity);
-        SupplicantStatus setEapEncryptedImsiIdentityInternal(
+	SupplicantStatus setEapEncryptedImsiIdentityInternal(
 	    const std::vector<uint8_t>& identity);
 	SupplicantStatus setEapAnonymousIdentityInternal(
 	    const std::vector<uint8_t>& identity);
@@ -252,6 +284,8 @@
 	std::pair<SupplicantStatus, uint32_t> getPairwiseCipherInternal();
 	std::pair<SupplicantStatus, std::string> getPskPassphraseInternal();
 	std::pair<SupplicantStatus, std::array<uint8_t, 32>> getPskInternal();
+	std::pair<SupplicantStatus, std::string> getSaePasswordInternal();
+	std::pair<SupplicantStatus, std::string> getSaePasswordIdInternal();
 	std::pair<SupplicantStatus, std::vector<uint8_t>> getWepKeyInternal(
 	    uint32_t key_idx);
 	std::pair<SupplicantStatus, uint32_t> getWepTxKeyIdxInternal();
@@ -299,6 +333,14 @@
 	SupplicantStatus sendNetworkEapIdentityResponseInternal_1_1(
 	    const std::vector<uint8_t>& identity,
 	    const std::vector<uint8_t>& imsi_identity);
+	SupplicantStatus enableTlsSuiteBEapPhase1ParamInternal(bool enable);
+	SupplicantStatus enableSuiteBEapOpenSslCiphersInternal();
+	SupplicantStatus setSaePasswordInternal(
+	    const std::string& sae_password);
+	SupplicantStatus setSaePasswordIdInternal(
+	    const std::string& sae_password_id);
+	SupplicantStatus setGroupMgmtCipherInternal(uint32_t group_mgmt_cipher_mask);
+	std::pair<SupplicantStatus, uint32_t> getGroupMgmtCipherInternal();
 
 	struct wpa_ssid* retrieveNetworkPtr();
 	struct wpa_supplicant* retrieveIfacePtr();
@@ -335,9 +377,9 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
 
diff --git a/wpa_supplicant/hidl/1.1/supplicant.cpp b/wpa_supplicant/hidl/1.2/supplicant.cpp
similarity index 96%
rename from wpa_supplicant/hidl/1.1/supplicant.cpp
rename to wpa_supplicant/hidl/1.2/supplicant.cpp
index 4785c37..9342ace 100644
--- a/wpa_supplicant/hidl/1.1/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.2/supplicant.cpp
@@ -16,6 +16,8 @@
 #include <sys/stat.h>
 
 namespace {
+using namespace android::hardware::wifi::supplicant::V1_2;
+
 // Pre-populated interface params for interfaces controlled by wpa_supplicant.
 // Note: This may differ for other OEM's. So, modify this accordingly.
 constexpr char kIfaceDriverName[] = "nl80211";
@@ -32,10 +34,8 @@
     "/system/etc/wifi/wpa_supplicant.conf";
 constexpr char kVendorTemplateConfPath[] =
     "/vendor/etc/wifi/wpa_supplicant.conf";
-constexpr char kOldStaIfaceConfPath[] =
-    "/data/misc/wifi/wpa_supplicant.conf";
-constexpr char kOldP2pIfaceConfPath[] =
-    "/data/misc/wifi/p2p_supplicant.conf";
+constexpr char kOldStaIfaceConfPath[] = "/data/misc/wifi/wpa_supplicant.conf";
+constexpr char kOldP2pIfaceConfPath[] = "/data/misc/wifi/p2p_supplicant.conf";
 constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
 
 int copyFile(
@@ -157,7 +157,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -347,8 +347,9 @@
 			return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
 				iface};
 		}
-		// Set this flag true here, since there is no HIDL initialize method for the p2p
-		// config, and the supplicant interface is not ready when the p2p iface is created.
+		// Set this flag true here, since there is no HIDL initialize
+		// method for the p2p config, and the supplicant interface is
+		// not ready when the p2p iface is created.
 		wpa_s->conf->persistent_reconnect = true;
 		return {{SupplicantStatusCode::SUCCESS, ""}, iface};
 	} else {
@@ -416,8 +417,8 @@
 	return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
 }
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wpa_supplicant/hidl/1.1/supplicant.h b/wpa_supplicant/hidl/1.2/supplicant.h
similarity index 92%
rename from wpa_supplicant/hidl/1.1/supplicant.h
rename to wpa_supplicant/hidl/1.2/supplicant.h
index 327e061..8985854 100644
--- a/wpa_supplicant/hidl/1.1/supplicant.h
+++ b/wpa_supplicant/hidl/1.2/supplicant.h
@@ -10,13 +10,15 @@
 #ifndef WPA_SUPPLICANT_HIDL_SUPPLICANT_H
 #define WPA_SUPPLICANT_HIDL_SUPPLICANT_H
 
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantIface.h>
+#include <android/hardware/wifi/supplicant/1.0/types.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicant.h>
+#include <android-base/macros.h>
+#include <hidl/Status.h>
 
-extern "C" {
+extern "C"
+{
 #include "utils/common.h"
 #include "utils/includes.h"
 #include "utils/wpa_debug.h"
@@ -27,7 +29,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 using namespace android::hardware::wifi::supplicant::V1_0;
 
@@ -36,7 +38,7 @@
  * object is used core for global control operations on
  * wpa_supplicant.
  */
-class Supplicant : public V1_1::ISupplicant
+class Supplicant : public V1_2::ISupplicant
 {
 public:
 	Supplicant(struct wpa_global* global);
@@ -90,9 +92,9 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
+}  // namespace V1_2
 }  // namespace supplicant
+}  // namespace wifi
 }  // namespace hardware
 }  // namespace android
 
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index f9b7e4c..814d18e 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -50,9 +50,12 @@
 	u8 bssid[ETH_ALEN];
 	u8 osu_ssid[SSID_MAX_LEN];
 	u8 osu_ssid_len;
+	u8 osu_ssid2[SSID_MAX_LEN];
+	u8 osu_ssid2_len;
 	char server_uri[256];
 	u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
 	char osu_nai[256];
+	char osu_nai2[256];
 	struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
 	size_t friendly_name_count;
 	struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
@@ -119,6 +122,22 @@
 }
 
 
+void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
+				 const struct wpa_ssid *ssid)
+{
+	if (!ssid->roaming_consortium_selection ||
+	    !ssid->roaming_consortium_selection_len)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+	wpabuf_put_u8(buf, 4 + ssid->roaming_consortium_selection_len);
+	wpabuf_put_be24(buf, OUI_WFA);
+	wpabuf_put_u8(buf, HS20_ROAMING_CONS_SEL_OUI_TYPE);
+	wpabuf_put_data(buf, ssid->roaming_consortium_selection,
+			ssid->roaming_consortium_selection_len);
+}
+
+
 int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
 		    struct wpa_bss *bss)
 {
@@ -249,7 +268,7 @@
 	if (buf == NULL)
 		return -1;
 
-	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+	res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
 		wpabuf_free(buf);
@@ -650,6 +669,25 @@
 					       wpa_s, NULL);
 		}
 		break;
+	case HS20_STYPE_OPERATOR_ICON_METADATA:
+		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+			" Operator Icon Metadata", MAC2STR(sa));
+		wpa_hexdump(MSG_DEBUG, "Operator Icon Metadata", pos, slen);
+		if (anqp) {
+			wpabuf_free(anqp->hs20_operator_icon_metadata);
+			anqp->hs20_operator_icon_metadata =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
+		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+			" OSU Providers NAI List", MAC2STR(sa));
+		if (anqp) {
+			wpabuf_free(anqp->hs20_osu_providers_nai_list);
+			anqp->hs20_osu_providers_nai_list =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
 		break;
@@ -729,8 +767,15 @@
 				wpa_ssid_txt(osu->osu_ssid,
 					     osu->osu_ssid_len));
 		}
+		if (osu->osu_ssid2_len) {
+			fprintf(f, "osu_ssid2=%s\n",
+				wpa_ssid_txt(osu->osu_ssid2,
+					     osu->osu_ssid2_len));
+		}
 		if (osu->osu_nai[0])
 			fprintf(f, "osu_nai=%s\n", osu->osu_nai);
+		if (osu->osu_nai2[0])
+			fprintf(f, "osu_nai2=%s\n", osu->osu_nai2);
 		for (j = 0; j < osu->friendly_name_count; j++) {
 			fprintf(f, "friendly_name=%s:%s\n",
 				osu->friendly_name[j].lang,
@@ -794,6 +839,7 @@
 
 static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			      const u8 *osu_ssid, u8 osu_ssid_len,
+			      const u8 *osu_ssid2, u8 osu_ssid2_len,
 			      const u8 *pos, size_t len)
 {
 	struct osu_provider *prov;
@@ -815,6 +861,9 @@
 	os_memcpy(prov->bssid, bss->bssid, ETH_ALEN);
 	os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len);
 	prov->osu_ssid_len = osu_ssid_len;
+	if (osu_ssid2)
+		os_memcpy(prov->osu_ssid2, osu_ssid2, osu_ssid2_len);
+	prov->osu_ssid2_len = osu_ssid2_len;
 
 	/* OSU Friendly Name Length */
 	if (end - pos < 2) {
@@ -996,18 +1045,30 @@
 	struct wpabuf *prov_anqp;
 	const u8 *pos, *end;
 	u16 len;
-	const u8 *osu_ssid;
-	u8 osu_ssid_len;
+	const u8 *osu_ssid, *osu_ssid2;
+	u8 osu_ssid_len, osu_ssid2_len;
 	u8 num_providers;
 
 	hs20_free_osu_prov(wpa_s);
 
 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		struct wpa_ie_data data;
+		const u8 *ie;
+
 		if (bss->anqp == NULL)
 			continue;
 		prov_anqp = bss->anqp->hs20_osu_providers_list;
 		if (prov_anqp == NULL)
 			continue;
+		ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &data) == 0 &&
+		    (data.key_mgmt & WPA_KEY_MGMT_OSEN)) {
+			osu_ssid2 = bss->ssid;
+			osu_ssid2_len = bss->ssid_len;
+		} else {
+			osu_ssid2 = NULL;
+			osu_ssid2_len = 0;
+		}
 		wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from "
 			   MACSTR, MAC2STR(bss->bssid));
 		wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list",
@@ -1049,7 +1110,8 @@
 			if (len > (unsigned int) (end - pos))
 				break;
 			hs20_osu_add_prov(wpa_s, bss, osu_ssid,
-					  osu_ssid_len, pos, len);
+					  osu_ssid_len, osu_ssid2,
+					  osu_ssid2_len, pos, len);
 			pos += len;
 		}
 
@@ -1058,6 +1120,35 @@
 				   "extra data after OSU Providers",
 				   (int) (end - pos));
 		}
+
+		prov_anqp = bss->anqp->hs20_osu_providers_nai_list;
+		if (!prov_anqp)
+			continue;
+		wpa_printf(MSG_DEBUG,
+			   "HS 2.0: Parsing OSU Providers NAI List from "
+			   MACSTR, MAC2STR(bss->bssid));
+		wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers NAI List",
+				prov_anqp);
+		pos = wpabuf_head(prov_anqp);
+		end = pos + wpabuf_len(prov_anqp);
+		num_providers = 0;
+		while (end - pos > 0) {
+			len = *pos++;
+			if (end - pos < len) {
+				wpa_printf(MSG_DEBUG,
+					   "HS 2.0: Not enough room for OSU_NAI");
+				break;
+			}
+			if (num_providers >= wpa_s->osu_prov_count) {
+				wpa_printf(MSG_DEBUG,
+					   "HS 2.0: Ignore unexpected OSU Provider NAI List entries");
+				break;
+			}
+			os_memcpy(wpa_s->osu_prov[num_providers].osu_nai2,
+				  pos, len);
+			pos += len;
+			num_providers++;
+		}
 	}
 
 	wpa_s->fetch_osu_icon_in_progress = 1;
@@ -1213,6 +1304,18 @@
 }
 
 
+void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url)
+{
+	if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
+		wpa_printf(MSG_DEBUG,
+			   "HS 2.0: Ignore Terms and Conditions Acceptance since PMF was not enabled");
+		return;
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url);
+}
+
+
 void hs20_init(struct wpa_supplicant *wpa_s)
 {
 	dl_list_init(&wpa_s->icon_head);
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 0dd559f..66fc540 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -10,6 +10,8 @@
 
 void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s);
 void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id);
+void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
+				 const struct wpa_ssid *ssid);
 
 int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
 		       const u8 *payload, size_t payload_len, int inmem);
@@ -27,6 +29,7 @@
 				      const char *url, u8 osu_method);
 void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
 				    u16 reauth_delay, const char *url);
+void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url);
 
 void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
 void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 4c79356..ebb3a50 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -148,6 +148,8 @@
 			return 1;
 		if (cred->required_roaming_consortium_len)
 			return 1;
+		if (cred->num_roaming_consortiums)
+			return 1;
 	}
 	return 0;
 }
@@ -301,8 +303,10 @@
 			wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
 		if (all)
 			wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
-		if (all)
+		if (all) {
 			wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST);
+			wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
+		}
 		gas_anqp_set_element_len(extra, len_pos);
 	}
 #endif /* CONFIG_HS20 */
@@ -312,7 +316,7 @@
 	if (buf == NULL)
 		return -1;
 
-	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
+	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf,
 			    interworking_anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
@@ -1145,6 +1149,23 @@
 }
 
 
+static int cred_roaming_consortiums_match(const u8 *ie,
+					  const struct wpabuf *anqp,
+					  const struct wpa_cred *cred)
+{
+	unsigned int i;
+
+	for (i = 0; i < cred->num_roaming_consortiums; i++) {
+		if (roaming_consortium_match(ie, anqp,
+					     cred->roaming_consortiums[i],
+					     cred->roaming_consortiums_len[i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+
 static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
 {
 	const u8 *ie;
@@ -1349,27 +1370,28 @@
 {
 	struct wpa_cred *cred, *selected = NULL;
 	const u8 *ie;
+	const struct wpabuf *anqp;
 	int is_excluded = 0;
 
 	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+	anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
 
-	if (ie == NULL &&
-	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+	if (!ie && !anqp)
 		return NULL;
 
 	if (wpa_s->conf->cred == NULL)
 		return NULL;
 
 	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
-		if (cred->roaming_consortium_len == 0)
+		if (cred->roaming_consortium_len == 0 &&
+		    cred->num_roaming_consortiums == 0)
 			continue;
 
-		if (!roaming_consortium_match(ie,
-					      bss->anqp ?
-					      bss->anqp->roaming_consortium :
-					      NULL,
-					      cred->roaming_consortium,
-					      cred->roaming_consortium_len))
+		if ((cred->roaming_consortium_len == 0 ||
+		     !roaming_consortium_match(ie, anqp,
+					       cred->roaming_consortium,
+					       cred->roaming_consortium_len)) &&
+		    !cred_roaming_consortiums_match(ie, anqp, cred))
 			continue;
 
 		if (cred_no_required_oi_match(cred, bss))
@@ -1535,6 +1557,9 @@
 	struct wpa_bss *bss, int only_add)
 {
 	struct wpa_ssid *ssid;
+	const u8 *ie;
+	const struct wpabuf *anqp;
+	unsigned int i;
 
 	wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
 		" based on roaming consortium match", MAC2STR(bss->bssid));
@@ -1564,6 +1589,26 @@
 	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
 		goto fail;
 
+	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+	anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
+	for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) {
+		if (!roaming_consortium_match(
+			    ie, anqp, cred->roaming_consortiums[i],
+			    cred->roaming_consortiums_len[i]))
+			continue;
+
+		ssid->roaming_consortium_selection =
+			os_malloc(cred->roaming_consortiums_len[i]);
+		if (!ssid->roaming_consortium_selection)
+			goto fail;
+		os_memcpy(ssid->roaming_consortium_selection,
+			  cred->roaming_consortiums[i],
+			  cred->roaming_consortiums_len[i]);
+		ssid->roaming_consortium_selection_len =
+			cred->roaming_consortiums_len[i];
+		break;
+	}
+
 	if (cred->eap_method == NULL) {
 		wpa_msg(wpa_s, MSG_DEBUG,
 			"Interworking: No EAP method set for credential using roaming consortium");
@@ -2752,7 +2797,7 @@
 	if (buf == NULL)
 		return -1;
 
-	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+	res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
 		wpabuf_free(buf);
@@ -2801,6 +2846,31 @@
 }
 
 
+static void interworking_parse_venue_url(struct wpa_supplicant *wpa_s,
+					 const u8 *data, size_t len)
+{
+	const u8 *pos = data, *end = data + len;
+	char url[255];
+
+	while (end - pos >= 2) {
+		u8 slen, num;
+
+		slen = *pos++;
+		if (slen < 1 || slen > end - pos) {
+			wpa_printf(MSG_DEBUG,
+				   "ANQP: Truncated Venue URL Duple field");
+			return;
+		}
+
+		num = *pos++;
+		os_memcpy(url, pos, slen - 1);
+		url[slen - 1] = '\0';
+		wpa_msg(wpa_s, MSG_INFO, RX_VENUE_URL "%u %s", num, url);
+		pos += slen - 1;
+	}
+}
+
+
 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
 					    struct wpa_bss *bss, const u8 *sa,
 					    u16 info_id,
@@ -2907,6 +2977,18 @@
 		}
 		break;
 #endif /* CONFIG_FILS */
+	case ANQP_VENUE_URL:
+		wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL",
+			MAC2STR(sa));
+		anqp_add_extra(wpa_s, anqp, info_id, pos, slen);
+
+		if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
+			wpa_printf(MSG_DEBUG,
+				   "ANQP: Ignore Venue URL since PMF was not enabled");
+			break;
+		}
+		interworking_parse_venue_url(wpa_s, pos, slen);
+		break;
 	case ANQP_VENDOR_SPECIFIC:
 		if (slen < 3)
 			return;
@@ -3155,7 +3237,7 @@
 	} else
 		wpabuf_put_le16(buf, 0);
 
-	res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
+	res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s);
 	if (res < 0) {
 		wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
 		wpabuf_free(buf);
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 129d205..5adf61e 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -38,6 +38,19 @@
 }
 
 
+const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr)
+{
+	const u8 *mbo;
+	u8 ie_len = mbo_ie[1];
+
+	if (ie_len < MBO_IE_HEADER - 2)
+		return NULL;
+	mbo = mbo_ie + MBO_IE_HEADER;
+
+	return get_ie(mbo, 2 + ie_len - MBO_IE_HEADER, attr);
+}
+
+
 const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
 {
 	const u8 *mbo, *end;
@@ -149,7 +162,8 @@
 }
 
 
-int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
+		int add_oce_capa)
 {
 	struct wpabuf *mbo;
 	int res;
@@ -175,7 +189,7 @@
 	wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa);
 
 	/* Add OCE capability indication attribute if OCE is enabled */
-	if (wpa_s->enable_oce & OCE_STA) {
+	if ((wpa_s->enable_oce & OCE_STA) && add_oce_capa) {
 		wpabuf_put_u8(mbo, OCE_ATTR_ID_CAPA_IND);
 		wpabuf_put_u8(mbo, 1);
 		wpabuf_put_u8(mbo, OCE_RELEASE);
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index c0c8f91..38b9fb3 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -157,6 +157,7 @@
 	struct mesh_conf *mconf;
 	int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
 	static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
+	const char *password;
 	size_t len;
 	int rate_len;
 	int frequency;
@@ -168,7 +169,7 @@
 		return 0;
 	}
 
-	wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
+	wpa_s->ifmsh = ifmsh = hostapd_alloc_iface();
 	if (!ifmsh)
 		return -ENOMEM;
 
@@ -183,6 +184,7 @@
 	if (!bss)
 		goto out_free;
 
+	ifmsh->bss[0]->msg_ctx = wpa_s;
 	os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
 	bss->driver = wpa_s->driver;
 	bss->drv_priv = wpa_s->drv_priv;
@@ -291,7 +293,10 @@
 	}
 
 	if (mconf->security != MESH_CONF_SEC_NONE) {
-		if (ssid->passphrase == NULL) {
+		password = ssid->sae_password;
+		if (!password)
+			password = ssid->passphrase;
+		if (!password) {
 			wpa_printf(MSG_ERROR,
 				   "mesh: Passphrase for SAE not configured");
 			goto out_free;
@@ -311,9 +316,9 @@
 				goto out_free;
 		}
 
-		len = os_strlen(ssid->passphrase);
+		len = os_strlen(password);
 		bss->conf->ssid.wpa_passphrase =
-			dup_binstr(ssid->passphrase, len);
+			dup_binstr(password, len);
 
 		wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
 		if (!wpa_s->mesh_rsn)
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index bc3cc5e..d166cfe 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -437,7 +437,7 @@
 			break;
 		}
 		reason = WLAN_REASON_MESH_MAX_RETRIES;
-		/* fall through on else */
+		/* fall through */
 
 	case PLINK_CNF_RCVD:
 		/* confirm timer */
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 25dcde5..e74cb16 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -332,8 +332,14 @@
 		return -1;
 	}
 
+	if (sta->sae->tmp && !sta->sae->tmp->pw_id && ssid->sae_password_id) {
+		sta->sae->tmp->pw_id = os_strdup(ssid->sae_password_id);
+		if (!sta->sae->tmp->pw_id)
+			return -1;
+	}
 	return sae_prepare_commit(wpa_s->own_addr, sta->addr,
 				  (u8 *) password, os_strlen(password),
+				  ssid->sae_password_id,
 				  sta->sae);
 }
 
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 3832a33..30bdb6d 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -887,6 +887,7 @@
 		     status, parameter);
 }
 
+
 void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code)
 {
 	wpa_dbg(wpa_s, MSG_ERROR,
@@ -894,6 +895,7 @@
 	wpas_hidl_notify_eap_error(wpa_s, error_code);
 }
 
+
 void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
 					   struct wpa_ssid *ssid)
 {
@@ -1024,3 +1026,112 @@
 }
 
 #endif /* CONFIG_MESH */
+
+/*
+ * DPP Notifications
+ */
+
+/* DPP Success notifications */
+
+void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+	    struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_config_received(wpa_s, ssid);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_config_sent(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+/* DPP Progress notifications */
+void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_auth_success(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_resp_pending(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+/* DPP Failure notifications */
+void wpas_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_not_compatible(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_missing_auth(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_configuration_failure(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_timeout(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_timeout(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_auth_failure(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_failure(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+	if (!wpa_s)
+		return;
+
+	wpas_hidl_notify_dpp_fail(wpa_s);
+#endif /* CONFIG_DPP */
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index c3ac3d1..703ef8f 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -167,4 +167,16 @@
 void wpas_notify_hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s,
 						u8 code, u16 reauth_delay,
 						const char *url);
+void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+	    struct wpa_ssid *ssid);
+void wpas_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_timeout(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_failure(struct wpa_supplicant *wpa_s);
+
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 0eccd52..3626ea3 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -748,6 +748,7 @@
 				conncap = P2PS_SETUP_GROUP_OWNER;
 				goto grp_owner;
 			}
+			/* fall through */
 
 		default:
 			return P2PS_SETUP_NONE;
@@ -1713,14 +1714,23 @@
 
 static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
 {
+	char buf[20 + P2P_MAX_CHANNELS * 6];
+	char *pos, *end;
 	unsigned int i;
+	int res;
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
-		wpa_s->p2p_group_common_freqs_num);
+	pos = buf;
+	end = pos + sizeof(buf);
+	for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+		res = os_snprintf(pos, end - pos, " %d",
+				  wpa_s->p2p_group_common_freqs[i]);
+		if (os_snprintf_error(end - pos, res))
+			break;
+		pos += res;
+	}
+	*pos = '\0';
 
-	for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++)
-		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d",
-			i, wpa_s->p2p_group_common_freqs[i]);
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies:%s", buf);
 }
 
 
@@ -2065,6 +2075,17 @@
 		return -1;
 	}
 
+	if (wpa_s->conf->p2p_interface_random_mac_addr) {
+		if (random_mac_addr(wpa_s->pending_interface_addr) < 0) {
+			wpa_printf(MSG_ERROR, "P2P: Failed to generate random MAC address "
+					      "for the group interface");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Generate random MAC address " MACSTR " for the group",
+			MAC2STR(wpa_s->pending_interface_addr));
+	}
+
+
 	if (force_ifname[0]) {
 		wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
 			   force_ifname);
@@ -2143,6 +2164,25 @@
 
 	wpas_p2p_clone_config(group_wpa_s, wpa_s);
 
+	if (wpa_s->conf->p2p_interface_random_mac_addr) {
+		if (wpa_drv_set_mac_addr(group_wpa_s, wpa_s->pending_interface_addr) < 0) {
+			wpa_msg(group_wpa_s, MSG_INFO,
+				"Failed to set random MAC address");
+			wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s, 0);
+			return NULL;
+		}
+
+		if (wpa_supplicant_update_mac_addr(group_wpa_s) < 0) {
+			wpa_msg(group_wpa_s, MSG_INFO,
+				"Could not update MAC address information");
+			wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s, 0);
+			return NULL;
+		}
+
+		wpa_printf(MSG_DEBUG, "P2P: Using random MAC address " MACSTR " for the group",
+			MAC2STR(wpa_s->pending_interface_addr));
+	}
+
 	return group_wpa_s;
 }
 
@@ -4304,6 +4344,53 @@
 					  WPA_IF_P2P_CLIENT, len, freq_list);
 }
 
+int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
+{
+	u8 addr[ETH_ALEN] = {0};
+
+	if (wpa_s->conf->p2p_device_random_mac_addr == 0)
+		return 0;
+
+	if (wpa_s->conf->ssid == NULL) {
+		if (random_mac_addr(addr) < 0) {
+			wpa_msg(wpa_s, MSG_INFO,
+				"Failed to generate random MAC address");
+			return -EINVAL;
+		}
+
+		/* Store generated MAC address. */
+		os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr, addr,
+			  ETH_ALEN);
+	} else {
+		/* If there are existing saved groups, restore last MAC address.
+		 * if there is no last used MAC address, the last one is
+		 * factory MAC. */
+		if (is_zero_ether_addr(
+			    wpa_s->conf->p2p_device_persistent_mac_addr))
+			return 0;
+		os_memcpy(addr, wpa_s->conf->p2p_device_persistent_mac_addr,
+			  ETH_ALEN);
+		wpa_msg(wpa_s, MSG_DEBUG, "Restore last used MAC address.");
+	}
+
+	if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"Failed to set random MAC address");
+		return -EINVAL;
+	}
+
+	if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"Could not update MAC address information");
+		return -EINVAL;
+	}
+
+	wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
+		MAC2STR(addr));
+
+	return 0;
+}
+
 
 /**
  * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
@@ -4325,6 +4412,12 @@
 	if (global->p2p)
 		return 0;
 
+	if (wpas_p2p_mac_setup(wpa_s) < 0) {
+		wpa_msg(wpa_s, MSG_ERROR,
+			"Failed to initialize P2P random MAC address.");
+		return -1;
+	}
+
 	os_memset(&p2p, 0, sizeof(p2p));
 	p2p.cb_ctx = wpa_s;
 	p2p.debug_print = wpas_p2p_debug_print;
@@ -5214,7 +5307,8 @@
 			ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
 		if (!ret) {
 			if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
-			    ieee80211_is_dfs(freq)) {
+			    ieee80211_is_dfs(freq, wpa_s->hw.modes,
+					     wpa_s->hw.num_modes)) {
 				/*
 				 * If freq is a DFS channel and DFS is offloaded
 				 * to the driver, allow P2P GO to use it.
@@ -5702,7 +5796,8 @@
 
 	if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
 		if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
-		    ieee80211_is_dfs(freq)) {
+		    ieee80211_is_dfs(freq, wpa_s->hw.modes,
+				     wpa_s->hw.num_modes)) {
 			/*
 			 * If freq is a DFS channel and DFS is offloaded to the
 			 * driver, allow P2P GO to use it.
@@ -5807,6 +5902,19 @@
 }
 
 
+static int wpas_same_band(int freq1, int freq2)
+{
+	enum hostapd_hw_mode mode1, mode2;
+	u8 chan1, chan2;
+
+	mode1 = ieee80211_freq_to_chan(freq1, &chan1);
+	mode2 = ieee80211_freq_to_chan(freq2, &chan2);
+	if (mode1 == NUM_HOSTAPD_MODES)
+		return 0;
+	return mode1 == mode2;
+}
+
+
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 				   struct p2p_go_neg_results *params,
 				   int freq, int vht_center_freq2, int ht40,
@@ -5866,7 +5974,8 @@
 		}
 		if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
 			if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
-			    ieee80211_is_dfs(freq)) {
+			    ieee80211_is_dfs(freq, wpa_s->hw.modes,
+					     wpa_s->hw.num_modes)) {
 				/*
 				 * If freq is a DFS channel and DFS is offloaded
 				 * to the driver, allow P2P GO to use it.
@@ -6006,6 +6115,80 @@
 		goto success;
 	}
 
+	/* Try using a channel that allows VHT to be used with 80 MHz */
+	if (wpa_s->hw.modes && wpa_s->p2p_group_common_freqs) {
+		for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+			enum hostapd_hw_mode mode;
+			struct hostapd_hw_modes *hwmode;
+			u8 chan;
+
+			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);
+			if (!hwmode ||
+			    wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+						    BW80) != ALLOWED)
+				continue;
+			if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+				params->freq = cand;
+				wpa_printf(MSG_DEBUG,
+					   "P2P: Use freq %d MHz common with the peer and allowing VHT80",
+					   params->freq);
+				goto success;
+			}
+		}
+	}
+
+	/* Try using a channel that allows HT to be used with 40 MHz on the same
+	 * band so that CSA can be used */
+	if (wpa_s->current_ssid && wpa_s->hw.modes &&
+	    wpa_s->p2p_group_common_freqs) {
+		for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+			enum hostapd_hw_mode mode;
+			struct hostapd_hw_modes *hwmode;
+			u8 chan;
+
+			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);
+			if (!wpas_same_band(wpa_s->current_ssid->frequency,
+					    cand) ||
+			    !hwmode ||
+			    (wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+						     BW40MINUS) != ALLOWED &&
+			     wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+						     BW40PLUS) != ALLOWED))
+				continue;
+			if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+				params->freq = cand;
+				wpa_printf(MSG_DEBUG,
+					   "P2P: Use freq %d MHz common with the peer, allowing HT40, and maintaining same band",
+					   params->freq);
+				goto success;
+			}
+		}
+	}
+
+	/* Try using one of the group common freqs on the same band so that CSA
+	 * can be used */
+	if (wpa_s->current_ssid && wpa_s->p2p_group_common_freqs) {
+		for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+			cand = wpa_s->p2p_group_common_freqs[i];
+			if (!wpas_same_band(wpa_s->current_ssid->frequency,
+					    cand))
+				continue;
+			if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+				params->freq = cand;
+				wpa_printf(MSG_DEBUG,
+					   "P2P: Use freq %d MHz common with the peer and maintaining same band",
+					   params->freq);
+				goto success;
+			}
+		}
+	}
+
 	/* Try using one of the group common freqs */
 	if (wpa_s->p2p_group_common_freqs) {
 		for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
@@ -6075,6 +6258,12 @@
 		return NULL;
 	}
 
+	if (go && wpa_s->p2p_go_do_acs) {
+		group_wpa_s->p2p_go_do_acs = wpa_s->p2p_go_do_acs;
+		group_wpa_s->p2p_go_acs_band = wpa_s->p2p_go_acs_band;
+		wpa_s->p2p_go_do_acs = 0;
+	}
+
 	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
 		group_wpa_s->ifname);
 	group_wpa_s->p2p_first_connection_timeout = 0;
@@ -6112,9 +6301,11 @@
 	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
 	wpas_p2p_stop_find_oper(wpa_s);
 
-	freq = wpas_p2p_select_go_freq(wpa_s, freq);
-	if (freq < 0)
-		return -1;
+	if (!wpa_s->p2p_go_do_acs) {
+		freq = wpas_p2p_select_go_freq(wpa_s, freq);
+		if (freq < 0)
+			return -1;
+	}
 
 	if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
 				    ht40, vht, max_oper_chwidth, NULL))
@@ -9089,7 +9280,7 @@
 
 	freq = wpa_s->current_ssid->frequency;
 	dfs_offload = (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
-		ieee80211_is_dfs(freq);
+		ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
 	for (i = 0, invalid_freq = 0; i < num; i++) {
 		if (freqs[i].freq == freq) {
 			flags = freqs[i].flags;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 63910d1..0a08a88 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -211,6 +211,7 @@
 		      unsigned int period, unsigned int interval,
 		      unsigned int count);
 int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
+int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s);
 
 #else /* CONFIG_P2P */
 
diff --git a/wpa_supplicant/p2p_supplicant_sd.c b/wpa_supplicant/p2p_supplicant_sd.c
index f8675e6..fb30584 100644
--- a/wpa_supplicant/p2p_supplicant_sd.c
+++ b/wpa_supplicant/p2p_supplicant_sd.c
@@ -559,9 +559,9 @@
 			    const u8 *query, size_t query_len)
 {
 	struct p2ps_advertisement *adv_data;
-	const u8 *svc = &query[1];
+	const u8 *svc;
 	const u8 *info = NULL;
-	size_t svc_len = query[0];
+	size_t svc_len;
 	size_t info_len = 0;
 	int prefix = 0;
 	u8 *count_pos = NULL;
@@ -569,6 +569,15 @@
 
 	wpa_hexdump(MSG_DEBUG, "P2P: SD Request for ASP", query, query_len);
 
+	if (query_len < 1) {
+		wpa_printf(MSG_DEBUG, "P2P: ASP bad request");
+		wpas_sd_add_bad_request(resp, P2P_SERV_P2PS, srv_trans_id);
+		return;
+	}
+
+	svc_len = query[0];
+	svc = &query[1];
+
 	if (!wpa_s->global->p2p) {
 		wpa_printf(MSG_DEBUG, "P2P: ASP protocol not available");
 		wpas_sd_add_proto_not_avail(resp, P2P_SERV_P2PS, srv_trans_id);
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index a213a30..f2fff55 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -348,7 +348,7 @@
 		ret = -2;
 	else {
 		ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0,
-					      NULL) ? 0 : -3;
+					      NULL, 0) ? 0 : -3;
 	}
 
 	test_eapol_clean(&wpa_s);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 104b258..ee39e0c 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -455,6 +455,33 @@
 #endif /* CONFIG_INTERWORKING */
 
 
+#ifdef CONFIG_MBO
+static void wpas_fils_req_param_add_max_channel(struct wpa_supplicant *wpa_s,
+						struct wpabuf **ie)
+{
+	if (wpabuf_resize(ie, 5)) {
+		wpa_printf(MSG_DEBUG,
+			   "Failed to allocate space for FILS Request Parameters element");
+		return;
+	}
+
+	/* FILS Request Parameters element */
+	wpabuf_put_u8(*ie, WLAN_EID_EXTENSION);
+	wpabuf_put_u8(*ie, 3); /* FILS Request attribute length */
+	wpabuf_put_u8(*ie, WLAN_EID_EXT_FILS_REQ_PARAMS);
+	/* Parameter control bitmap */
+	wpabuf_put_u8(*ie, 0);
+	/* Max Channel Time field - contains the value of MaxChannelTime
+	 * parameter of the MLME-SCAN.request primitive represented in units of
+	 * TUs, as an unsigned integer. A Max Channel Time field value of 255
+	 * is used to indicate any duration of more than 254 TUs, or an
+	 * unspecified or unknown duration. (IEEE Std 802.11ai-2016, 9.4.2.178)
+	 */
+	wpabuf_put_u8(*ie, 255);
+}
+#endif /* CONFIG_MBO */
+
+
 void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
 {
 	struct wpabuf *default_ies = NULL;
@@ -476,6 +503,8 @@
 		wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
 
 #ifdef CONFIG_MBO
+	if (wpa_s->enable_oce & OCE_STA)
+		wpas_fils_req_param_add_max_channel(wpa_s, &default_ies);
 	/* Send MBO and OCE capabilities */
 	if (wpabuf_resize(&default_ies, 12) == 0)
 		wpas_mbo_scan_ie(wpa_s, default_ies);
@@ -517,6 +546,11 @@
 		wpas_add_interworking_elements(wpa_s, extra_ie);
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_MBO
+	if (wpa_s->enable_oce & OCE_STA)
+		wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie);
+#endif /* CONFIG_MBO */
+
 #ifdef CONFIG_WPS
 	wps = wpas_wps_in_use(wpa_s, &req_type);
 
@@ -643,6 +677,87 @@
 }
 
 
+static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s,
+			      struct wpa_driver_scan_params *params,
+			      size_t max_ssids, const u8 *ssid, size_t ssid_len)
+{
+	unsigned int j;
+
+	for (j = 0; j < params->num_ssids; j++) {
+		if (params->ssids[j].ssid_len == ssid_len &&
+		    params->ssids[j].ssid &&
+		    os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0)
+			return; /* already in the list */
+	}
+
+	if (params->num_ssids + 1 > max_ssids) {
+		wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
+		   wpa_ssid_txt(ssid, ssid_len));
+
+	params->ssids[params->num_ssids].ssid = ssid;
+	params->ssids[params->num_ssids].ssid_len = ssid_len;
+	params->num_ssids++;
+}
+
+
+static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
+				  struct wpa_driver_scan_params *params,
+				  struct wpa_ssid *ssid, size_t max_ssids)
+{
+#ifdef CONFIG_OWE
+	struct wpa_bss *bss;
+
+	if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+		return;
+
+	wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s",
+		   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		const u8 *owe, *pos, *end;
+		const u8 *owe_ssid;
+		size_t owe_ssid_len;
+
+		if (bss->ssid_len != ssid->ssid_len ||
+		    os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0)
+			continue;
+
+		owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+		if (!owe || owe[1] < 4)
+			continue;
+
+		pos = owe + 6;
+		end = owe + 2 + owe[1];
+
+		/* Must include BSSID and ssid_len */
+		if (end - pos < ETH_ALEN + 1)
+			return;
+
+		/* Skip BSSID */
+		pos += ETH_ALEN;
+		owe_ssid_len = *pos++;
+		owe_ssid = pos;
+
+		if ((size_t) (end - pos) < owe_ssid_len ||
+		    owe_ssid_len > SSID_MAX_LEN)
+			return;
+
+		wpa_printf(MSG_DEBUG,
+			   "OWE: scan_ssids: transition mode OWE ssid=%s",
+			   wpa_ssid_txt(owe_ssid, owe_ssid_len));
+
+		wpa_add_scan_ssid(wpa_s, params, max_ssids,
+				  owe_ssid, owe_ssid_len);
+		return;
+	}
+#endif /* CONFIG_OWE */
+}
+
+
 static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
 			       struct wpa_driver_scan_params *params,
 			       size_t max_ssids)
@@ -657,33 +772,17 @@
 	max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
 
 	for (i = 0; i < wpa_s->scan_id_count; i++) {
-		unsigned int j;
-
 		ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]);
-		if (!ssid || !ssid->scan_ssid)
+		if (!ssid)
 			continue;
-
-		for (j = 0; j < params->num_ssids; j++) {
-			if (params->ssids[j].ssid_len == ssid->ssid_len &&
-			    params->ssids[j].ssid &&
-			    os_memcmp(params->ssids[j].ssid, ssid->ssid,
-				      ssid->ssid_len) == 0)
-				break;
-		}
-		if (j < params->num_ssids)
-			continue; /* already in the list */
-
-		if (params->num_ssids + 1 > max_ssids) {
-			wpa_printf(MSG_DEBUG,
-				   "Over max scan SSIDs for manual request");
-			break;
-		}
-
-		wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
-			   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-		params->ssids[params->num_ssids].ssid = ssid->ssid;
-		params->ssids[params->num_ssids].ssid_len = ssid->ssid_len;
-		params->num_ssids++;
+		if (ssid->scan_ssid)
+			wpa_add_scan_ssid(wpa_s, params, max_ssids,
+					  ssid->ssid, ssid->ssid_len);
+		/*
+		 * Also add the SSID of the OWE BSS, to allow discovery of
+		 * transition mode APs more quickly.
+		 */
+		wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids);
 	}
 
 	wpa_s->scan_id_count = 0;
@@ -950,6 +1049,17 @@
 				if (params.num_ssids + 1 >= max_ssids)
 					break;
 			}
+
+			if (!wpas_network_disabled(wpa_s, ssid)) {
+				/*
+				 * Also add the SSID of the OWE BSS, to allow
+				 * discovery of transition mode APs more
+				 * quickly.
+				 */
+				wpa_add_owe_scan_ssid(wpa_s, &params, ssid,
+						      max_ssids);
+			}
+
 			ssid = ssid->next;
 			if (ssid == start)
 				break;
@@ -1077,6 +1187,11 @@
 		}
 	}
 
+#ifdef CONFIG_MBO
+	if (wpa_s->enable_oce & OCE_STA)
+		params.oce_scan = 1;
+#endif /* CONFIG_MBO */
+
 	params.filter_ssids = wpa_supplicant_build_filter_ssids(
 		wpa_s->conf, &params.num_filter_ssids);
 	if (extra_ie) {
@@ -1486,6 +1601,11 @@
 		int_array_concat(&params.freqs, wpa_s->conf->freq_list);
 	}
 
+#ifdef CONFIG_MBO
+	if (wpa_s->enable_oce & OCE_STA)
+		params.oce_scan = 1;
+#endif /* CONFIG_MBO */
+
 	scan_params = &params;
 
 scan:
@@ -2401,6 +2521,7 @@
 	params->low_priority = src->low_priority;
 	params->duration = src->duration;
 	params->duration_mandatory = src->duration_mandatory;
+	params->oce_scan = src->oce_scan;
 
 	if (src->sched_scan_plans_num > 0) {
 		params->sched_scan_plans =
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index da0e8eb..d23dc06 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -83,7 +83,7 @@
 
 static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
 						 struct wpa_ssid *ssid,
-						 const u8 *bssid)
+						 const u8 *bssid, int external)
 {
 	struct wpabuf *buf;
 	size_t len;
@@ -117,25 +117,31 @@
 
 	if (sae_prepare_commit(wpa_s->own_addr, bssid,
 			       (u8 *) password, os_strlen(password),
+			       ssid->sae_password_id,
 			       &wpa_s->sme.sae) < 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
 		return NULL;
 	}
 
 	len = wpa_s->sme.sae_token ? 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);
 	if (buf == NULL)
 		return NULL;
-
-	wpabuf_put_le16(buf, 1); /* Transaction seq# */
-	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
-	sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
+	if (!external) {
+		wpabuf_put_le16(buf, 1); /* Transaction seq# */
+		wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+	}
+	sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+			 ssid->sae_password_id);
 
 	return buf;
 }
 
 
-static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s,
+						  int external)
 {
 	struct wpabuf *buf;
 
@@ -143,8 +149,10 @@
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_le16(buf, 2); /* Transaction seq# */
-	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+	if (!external) {
+		wpabuf_put_le16(buf, 2); /* Transaction seq# */
+		wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+	}
 	sae_write_confirm(&wpa_s->sme.sae, buf);
 
 	return buf;
@@ -232,6 +240,11 @@
 	u8 ext_capab[18];
 	int ext_capab_len;
 	int skip_auth;
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+#ifdef CONFIG_MBO
+	const u8 *mbo_ie;
+#endif /* CONFIG_MBO */
 
 	if (bss == NULL) {
 		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -329,7 +342,8 @@
 #endif /* CONFIG_FILS */
 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
 					    wpa_s->current_ssid,
-					    try_opportunistic, cache_id) == 0)
+					    try_opportunistic, cache_id,
+					    0) == 0)
 			eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
 		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -379,6 +393,28 @@
 		wpa_s->sme.assoc_req_ie_len = 0;
 	}
 
+	/* In case the WPA vendor IE is used, it should be placed after all the
+	 * non-vendor IEs, as the lower layer expects the IEs to be ordered as
+	 * defined in the standard. Store the WPA IE so it can later be
+	 * inserted at the correct location.
+	 */
+	wpa_ie = NULL;
+	wpa_ie_len = 0;
+	if (wpa_s->wpa_proto == WPA_PROTO_WPA) {
+		wpa_ie = os_memdup(wpa_s->sme.assoc_req_ie,
+				   wpa_s->sme.assoc_req_ie_len);
+		if (wpa_ie) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Storing WPA IE");
+
+			wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+			wpa_s->sme.assoc_req_ie_len = 0;
+		} else {
+			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed copy WPA IE");
+			wpas_connect_work_done(wpa_s);
+			return;
+		}
+	}
+
 #ifdef CONFIG_IEEE80211R
 	ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
 	if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
@@ -495,12 +531,13 @@
 	if (is_hs20_network(wpa_s, ssid, bss)) {
 		struct wpabuf *hs20;
 
-		hs20 = wpabuf_alloc(20);
+		hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
 		if (hs20) {
 			int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
 			size_t len;
 
 			wpas_hs20_add_indication(hs20, pps_mo_id);
+			wpas_hs20_add_roam_cons_sel(hs20, ssid);
 			len = sizeof(wpa_s->sme.assoc_req_ie) -
 				wpa_s->sme.assoc_req_ie_len;
 			if (wpabuf_len(hs20) <= len) {
@@ -514,6 +551,26 @@
 	}
 #endif /* CONFIG_HS20 */
 
+	if (wpa_ie) {
+		size_t len;
+
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Reinsert WPA IE");
+
+		len = sizeof(wpa_s->sme.assoc_req_ie) -
+			wpa_s->sme.assoc_req_ie_len;
+
+		if (len > wpa_ie_len) {
+			os_memcpy(wpa_s->sme.assoc_req_ie +
+				  wpa_s->sme.assoc_req_ie_len,
+				  wpa_ie, wpa_ie_len);
+			wpa_s->sme.assoc_req_ie_len += wpa_ie_len;
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Failed to add WPA IE");
+		}
+
+		os_free(wpa_ie);
+	}
+
 	if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
 		struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
 		size_t len;
@@ -529,13 +586,16 @@
 	}
 
 #ifdef CONFIG_MBO
-	if (wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+	mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+	if (mbo_ie) {
 		int len;
 
 		len = wpas_mbo_ie(wpa_s, 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);
+				  wpa_s->sme.assoc_req_ie_len,
+				  !!mbo_attr_from_mbo_ie(mbo_ie,
+							 OCE_ATTR_ID_CAPA_IND));
 		if (len >= 0)
 			wpa_s->sme.assoc_req_ie_len += len;
 	}
@@ -544,9 +604,10 @@
 #ifdef CONFIG_SAE
 	if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
 	    pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0,
-				    NULL) == 0) {
+				    NULL, WPA_KEY_MGMT_SAE) == 0) {
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
+		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 		params.auth_alg = WPA_AUTH_ALG_OPEN;
 		wpa_s->sme.sae_pmksa_caching = 1;
 	}
@@ -554,9 +615,9 @@
 	if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
 		if (start)
 			resp = sme_auth_build_sae_commit(wpa_s, ssid,
-							 bss->bssid);
+							 bss->bssid, 0);
 		else
-			resp = sme_auth_build_sae_confirm(wpa_s);
+			resp = sme_auth_build_sae_confirm(wpa_s, 0);
 		if (resp == NULL) {
 			wpas_connection_failed(wpa_s, bss->bssid);
 			return;
@@ -580,6 +641,9 @@
 	    wpa_key_mgmt_fils(ssid->key_mgmt)) {
 		const u8 *indic;
 		u16 fils_info;
+		const u8 *realm, *username, *rrk;
+		size_t realm_len, username_len, rrk_len;
+		u16 next_seq_num;
 
 		/*
 		 * Check FILS Indication element (FILS Information field) bits
@@ -609,10 +673,23 @@
 			goto no_fils;
 		}
 
+		if (wpa_s->last_con_fail_realm &&
+		    eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+					  &username, &username_len,
+					  &realm, &realm_len, &next_seq_num,
+					  &rrk, &rrk_len) == 0 &&
+		    realm && realm_len == wpa_s->last_con_fail_realm_len &&
+		    os_memcmp(realm, wpa_s->last_con_fail_realm,
+			      realm_len) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "SME: FILS authentication for this realm failed last time - try to regenerate ERP key hierarchy");
+			goto no_fils;
+		}
+
 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
 					    ssid, 0,
-					    wpa_bss_get_fils_cache_id(bss)) ==
-		    0)
+					    wpa_bss_get_fils_cache_id(bss),
+					    0) == 0)
 			wpa_printf(MSG_DEBUG,
 				   "SME: Try to use FILS with PMKSA caching");
 		resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md);
@@ -789,8 +866,150 @@
 
 #ifdef CONFIG_SAE
 
+static int sme_external_auth_build_buf(struct wpabuf *buf,
+				       struct wpabuf *params,
+				       const u8 *sa, const u8 *da,
+				       u16 auth_transaction, u16 seq_num)
+{
+	struct ieee80211_mgmt *resp;
+
+	resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+					u.auth.variable));
+
+	resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+					   (WLAN_FC_STYPE_AUTH << 4));
+	os_memcpy(resp->da, da, ETH_ALEN);
+	os_memcpy(resp->sa, sa, ETH_ALEN);
+	os_memcpy(resp->bssid, da, ETH_ALEN);
+	resp->u.auth.auth_alg = WLAN_AUTH_SAE;
+	resp->seq_ctrl = seq_num << 4;
+	resp->u.auth.auth_transaction = auth_transaction;
+	resp->u.auth.status_code = WLAN_STATUS_SUCCESS;
+	if (params)
+		wpabuf_put_buf(buf, params);
+
+	return 0;
+}
+
+
+static void sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
+					      const u8 *bssid,
+					      struct wpa_ssid *ssid)
+{
+	struct wpabuf *resp, *buf;
+
+	resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1);
+	if (!resp)
+		return;
+
+	wpa_s->sme.sae.state = SAE_COMMITTED;
+	buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp));
+	if (!buf) {
+		wpabuf_free(resp);
+		return;
+	}
+
+	wpa_s->sme.seq_num++;
+	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
+				    bssid, 1, wpa_s->sme.seq_num);
+	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+	wpabuf_free(resp);
+	wpabuf_free(buf);
+}
+
+
+static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s,
+					  u16 status)
+{
+	struct external_auth params;
+
+	os_memset(&params, 0, sizeof(params));
+	params.status = status;
+	os_memcpy(params.ssid, wpa_s->sme.ext_auth.ssid,
+		  wpa_s->sme.ext_auth.ssid_len);
+	params.ssid_len = wpa_s->sme.ext_auth.ssid_len;
+	os_memcpy(params.bssid, wpa_s->sme.ext_auth.bssid, ETH_ALEN);
+	wpa_drv_send_external_auth_status(wpa_s, &params);
+}
+
+
+static void sme_handle_external_auth_start(struct wpa_supplicant *wpa_s,
+					   union wpa_event_data *data)
+{
+	struct wpa_ssid *ssid;
+	size_t ssid_str_len = data->external_auth.ssid_len;
+	u8 *ssid_str = data->external_auth.ssid;
+
+	/* Get the SSID conf from the ssid string obtained */
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!wpas_network_disabled(wpa_s, ssid) &&
+		    ssid_str_len == ssid->ssid_len &&
+		    os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
+			break;
+	}
+	if (ssid)
+		sme_external_auth_send_sae_commit(wpa_s,
+						  data->external_auth.bssid,
+						  ssid);
+	else
+		sme_send_external_auth_status(wpa_s,
+					      WLAN_STATUS_UNSPECIFIED_FAILURE);
+}
+
+
+static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
+					       const u8 *da)
+{
+	struct wpabuf *resp, *buf;
+
+	resp = sme_auth_build_sae_confirm(wpa_s, 1);
+	if (!resp) {
+		wpa_printf(MSG_DEBUG, "SAE: Confirm message buf alloc failure");
+		return;
+	}
+
+	wpa_s->sme.sae.state = SAE_CONFIRMED;
+	buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp));
+	if (!buf) {
+		wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure");
+		wpabuf_free(resp);
+		return;
+	}
+	wpa_s->sme.seq_num++;
+	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
+				    da, 2, wpa_s->sme.seq_num);
+	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+	wpabuf_free(resp);
+	wpabuf_free(buf);
+}
+
+
+void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+			       union wpa_event_data *data)
+{
+	if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) !=
+	    RSN_AUTH_KEY_MGMT_SAE)
+		return;
+
+	if (data->external_auth.action == EXT_AUTH_START) {
+		os_memcpy(&wpa_s->sme.ext_auth, data,
+			  sizeof(struct external_auth));
+		wpa_s->sme.seq_num = 0;
+		wpa_s->sme.sae.state = SAE_NOTHING;
+		wpa_s->sme.sae.send_confirm = 0;
+		wpa_s->sme.sae_group_index = 0;
+		sme_handle_external_auth_start(wpa_s, data);
+	} else if (data->external_auth.action == EXT_AUTH_ABORT) {
+		/* Report failure to driver for the wrong trigger */
+		sme_send_external_auth_status(wpa_s,
+					      WLAN_STATUS_UNSPECIFIED_FAILURE);
+	}
+}
+
+
 static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
-			u16 status_code, const u8 *data, size_t len)
+			u16 status_code, const u8 *data, size_t len,
+			int external, const u8 *sa)
 {
 	int *groups;
 
@@ -800,7 +1019,7 @@
 	if (auth_transaction == 1 &&
 	    status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
 	    wpa_s->sme.sae.state == SAE_COMMITTED &&
-	    wpa_s->current_bss && wpa_s->current_ssid) {
+	    (external || wpa_s->current_bss) && wpa_s->current_ssid) {
 		int default_groups[] = { 19, 20, 21, 25, 26, 0 };
 		u16 group;
 
@@ -827,25 +1046,45 @@
 		wpabuf_free(wpa_s->sme.sae_token);
 		wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
 							 len - sizeof(le16));
-		sme_send_authentication(wpa_s, wpa_s->current_bss,
-					wpa_s->current_ssid, 1);
+		if (!external)
+			sme_send_authentication(wpa_s, wpa_s->current_bss,
+						wpa_s->current_ssid, 1);
+		else
+			sme_external_auth_send_sae_commit(
+				wpa_s, wpa_s->sme.ext_auth.bssid,
+				wpa_s->current_ssid);
 		return 0;
 	}
 
 	if (auth_transaction == 1 &&
 	    status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
 	    wpa_s->sme.sae.state == SAE_COMMITTED &&
-	    wpa_s->current_bss && wpa_s->current_ssid) {
+	    (external || wpa_s->current_bss) && wpa_s->current_ssid) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
 		wpa_s->sme.sae_group_index++;
 		if (sme_set_sae_group(wpa_s) < 0)
 			return -1; /* no other groups enabled */
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
-		sme_send_authentication(wpa_s, wpa_s->current_bss,
-					wpa_s->current_ssid, 1);
+		if (!external)
+			sme_send_authentication(wpa_s, wpa_s->current_bss,
+						wpa_s->current_ssid, 1);
+		else
+			sme_external_auth_send_sae_commit(
+				wpa_s, wpa_s->sme.ext_auth.bssid,
+				wpa_s->current_ssid);
 		return 0;
 	}
 
+	if (auth_transaction == 1 &&
+	    status_code == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
+		const u8 *bssid = sa ? sa : wpa_s->pending_bssid;
+
+		wpa_msg(wpa_s, MSG_INFO,
+			WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER MACSTR,
+			MAC2STR(bssid));
+		return -1;
+	}
+
 	if (status_code != WLAN_STATUS_SUCCESS)
 		return -1;
 
@@ -855,7 +1094,7 @@
 		groups = wpa_s->conf->sae_groups;
 
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
-		if (wpa_s->current_bss == NULL ||
+		if ((!external && wpa_s->current_bss == NULL) ||
 		    wpa_s->current_ssid == NULL)
 			return -1;
 		if (wpa_s->sme.sae.state != SAE_COMMITTED)
@@ -880,8 +1119,11 @@
 
 		wpabuf_free(wpa_s->sme.sae_token);
 		wpa_s->sme.sae_token = NULL;
-		sme_send_authentication(wpa_s, wpa_s->current_bss,
-					wpa_s->current_ssid, 0);
+		if (!external)
+			sme_send_authentication(wpa_s, wpa_s->current_bss,
+						wpa_s->current_ssid, 0);
+		else
+			sme_external_auth_send_sae_confirm(wpa_s, sa);
 		return 0;
 	} else if (auth_transaction == 2) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
@@ -891,11 +1133,59 @@
 			return -1;
 		wpa_s->sme.sae.state = SAE_ACCEPTED;
 		sae_clear_temp_data(&wpa_s->sme.sae);
+
+		if (external) {
+			/* Report success to driver */
+			sme_send_external_auth_status(wpa_s,
+						      WLAN_STATUS_SUCCESS);
+		}
+
 		return 1;
 	}
 
 	return -1;
 }
+
+
+void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+			       const u8 *auth_frame, size_t len)
+{
+	const struct ieee80211_mgmt *header;
+	size_t auth_length;
+
+	header = (const struct ieee80211_mgmt *) auth_frame;
+	auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
+
+	if (len < auth_length) {
+		/* Notify failure to the driver */
+		sme_send_external_auth_status(wpa_s,
+					      WLAN_STATUS_UNSPECIFIED_FAILURE);
+		return;
+	}
+
+	if (header->u.auth.auth_alg == WLAN_AUTH_SAE) {
+		int res;
+
+		res = sme_sae_auth(wpa_s, header->u.auth.auth_transaction,
+				   header->u.auth.status_code,
+				   header->u.auth.variable,
+				   len - auth_length, 1, header->sa);
+		if (res < 0) {
+			/* Notify failure to the driver */
+			sme_send_external_auth_status(
+				wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE);
+			return;
+		}
+		if (res != 1)
+			return;
+
+		wpa_printf(MSG_DEBUG,
+			   "SME: SAE completed - setting PMK for 4-way handshake");
+		wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+			       wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+	}
+}
+
 #endif /* CONFIG_SAE */
 
 
@@ -936,7 +1226,7 @@
 		int res;
 		res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
 				   data->auth.status_code, data->auth.ies,
-				   data->auth.ies_len);
+				   data->auth.ies_len, 0, NULL);
 		if (res < 0) {
 			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
@@ -971,6 +1261,12 @@
 			ie_txt ? ie_txt : "");
 		os_free(ie_txt);
 
+#ifdef CONFIG_FILS
+		if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
+		    wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS)
+			fils_connection_failure(wpa_s);
+#endif /* CONFIG_FILS */
+
 		if (data->auth.status_code !=
 		    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
 		    wpa_s->sme.auth_alg == data->auth.auth_type ||
@@ -1204,10 +1500,20 @@
 	if (auth_type == WLAN_AUTH_OPEN &&
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
 		struct wpabuf *owe_ie;
-		u16 group = OWE_DH_GROUP;
+		u16 group;
 
-		if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group)
+		if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) {
 			group = wpa_s->current_ssid->owe_group;
+		} else {
+			if (wpa_s->last_owe_group == 19)
+				group = 20;
+			else if (wpa_s->last_owe_group == 20)
+				group = 21;
+			else
+				group = OWE_DH_GROUP;
+		}
+		wpa_s->last_owe_group = group;
+		wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
 		owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
 		if (!owe_ie) {
 			wpa_printf(MSG_ERROR,
@@ -1509,7 +1815,7 @@
 	sae_clear_data(&wpa_s->sme.sae);
 #endif /* CONFIG_SAE */
 #ifdef CONFIG_IEEE80211R
-	if (wpa_s->sme.ft_ies)
+	if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used)
 		sme_update_ft_ies(wpa_s, NULL, NULL, 0);
 #endif /* CONFIG_IEEE80211R */
 }
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index fd5c3b4..f3c8220 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -38,6 +38,10 @@
 
 int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
 void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+			       union wpa_event_data *data);
+void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+			       const u8 *auth_frame, size_t len);
 
 #else /* CONFIG_SME */
 
@@ -113,6 +117,16 @@
 {
 }
 
+static inline void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+					     union wpa_event_data *data)
+{
+}
+
+static inline void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+					     const u8 *auth_frame, size_t len)
+{
+}
+
 #endif /* CONFIG_SME */
 
 #endif /* SME_H */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 28346ea..912f4c4 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -338,6 +338,9 @@
 	wpa_s->wnm_num_neighbor_report = 0;
 	os_free(wpa_s->wnm_neighbor_report_elements);
 	wpa_s->wnm_neighbor_report_elements = NULL;
+
+	wpabuf_free(wpa_s->coloc_intf_elems);
+	wpa_s->coloc_intf_elems = NULL;
 }
 
 
@@ -373,6 +376,10 @@
 		rep->preference_present = 1;
 		break;
 	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
+		if (elen < 10) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short bss_term_tsf");
+			break;
+		}
 		rep->bss_term_tsf = WPA_GET_LE64(pos);
 		rep->bss_term_dur = WPA_GET_LE16(pos + 8);
 		rep->bss_term_present = 1;
@@ -1644,6 +1651,32 @@
 			pos = next;
 			continue;
 		}
+
+		if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
+		    WPA_GET_BE24(pos) == OUI_WFA &&
+		    pos[3] == HS20_WNM_T_C_ACCEPTANCE) {
+			const u8 *ie_end;
+			u8 url_len;
+			char *url;
+
+			ie_end = pos + ie_len;
+			pos += 4;
+			url_len = *pos++;
+			wpa_printf(MSG_DEBUG,
+				   "WNM: HS 2.0 Terms and Conditions Acceptance (URL Length %u)",
+				   url_len);
+			if (url_len > ie_end - pos)
+				break;
+			url = os_malloc(url_len + 1);
+			if (!url)
+				break;
+			os_memcpy(url, pos, url_len);
+			url[url_len] = '\0';
+			hs20_rx_t_c_acceptance(wpa_s, url);
+			os_free(url);
+			pos = next;
+			continue;
+		}
 #endif /* CONFIG_HS20 */
 
 		pos = next;
@@ -1691,6 +1724,46 @@
 }
 
 
+static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s,
+					     const u8 *sa, const u8 *frm,
+					     int len)
+{
+	u8 dialog_token, req_info, auto_report, timeout;
+
+	if (!wpa_s->conf->coloc_intf_reporting)
+		return;
+
+	/* Dialog Token [1] | Request Info [1] */
+
+	if (len < 2)
+		return;
+	dialog_token = frm[0];
+	req_info = frm[1];
+	auto_report = req_info & 0x03;
+	timeout = req_info >> 2;
+
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")",
+		dialog_token, auto_report, timeout, MAC2STR(sa));
+
+	if (dialog_token == 0)
+		return; /* only nonzero values are used for request */
+
+	if (wpa_s->wpa_state != WPA_COMPLETED ||
+	    os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WNM: Collocated Interference Request frame not from current AP - ignore it");
+		return;
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u",
+		dialog_token, auto_report, timeout);
+	wpa_s->coloc_intf_dialog_token = dialog_token;
+	wpa_s->coloc_intf_auto_report = auto_report;
+	wpa_s->coloc_intf_timeout = timeout;
+}
+
+
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
 			      const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -1724,8 +1797,75 @@
 	case WNM_NOTIFICATION_REQ:
 		ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
 		break;
+	case WNM_COLLOCATED_INTERFERENCE_REQ:
+		ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos,
+						 end - pos);
+		break;
 	default:
 		wpa_printf(MSG_ERROR, "WNM: Unknown request");
 		break;
 	}
 }
+
+
+int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
+			       const struct wpabuf *elems)
+{
+	struct wpabuf *buf;
+	int ret;
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to "
+		   MACSTR " (dialog token %u)",
+		   MAC2STR(wpa_s->bssid), dialog_token);
+
+	buf = wpabuf_alloc(3 + wpabuf_len(elems));
+	if (!buf)
+		return -1;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+	wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT);
+	wpabuf_put_u8(buf, dialog_token);
+	wpabuf_put_buf(buf, elems);
+
+	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				  wpa_s->own_addr, wpa_s->bssid,
+				  wpabuf_head_u8(buf), wpabuf_len(buf), 0);
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
+			      struct wpabuf *elems)
+{
+	wpabuf_free(wpa_s->coloc_intf_elems);
+	if (elems && wpabuf_len(elems) == 0) {
+		wpabuf_free(elems);
+		elems = NULL;
+	}
+	wpa_s->coloc_intf_elems = elems;
+
+	if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems &&
+	    wpa_s->coloc_intf_dialog_token &&
+	    (wpa_s->coloc_intf_auto_report == 1 ||
+	     wpa_s->coloc_intf_auto_report == 3)) {
+		/* TODO: Check that there has not been less than
+		 * wpa_s->coloc_intf_timeout * 200 TU from the last report.
+		 */
+		wnm_send_coloc_intf_report(wpa_s,
+					   wpa_s->coloc_intf_dialog_token,
+					   wpa_s->coloc_intf_elems);
+	}
+}
+
+
+void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+	wpa_s->coloc_intf_dialog_token = 0;
+	wpa_s->coloc_intf_auto_report = 0;
+#endif /* CONFIG_WNM */
+}
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 02cd1cd..29625f8 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -65,11 +65,16 @@
 				       int cand_list);
 
 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
+			       const struct wpabuf *elems);
+void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
+			      struct wpabuf *elems);
 
 
 #ifdef CONFIG_WNM
 
 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s);
 
 #else /* CONFIG_WNM */
 
@@ -79,6 +84,10 @@
 	return 0;
 }
 
+static inline void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
+{
+}
+
 #endif /* CONFIG_WNM */
 
 #endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6b345af..05e3ebf 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -60,6 +60,7 @@
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(creds); /* struct cli_txt_entry */
 #ifdef CONFIG_AP
 static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
 #endif /* CONFIG_AP */
@@ -70,6 +71,7 @@
 static void wpa_cli_close_connection(void);
 static char * wpa_cli_get_default_ifname(void);
 static char ** wpa_list_cmd_list(void);
+static void update_creds(struct wpa_ctrl *ctrl);
 static void update_networks(struct wpa_ctrl *ctrl);
 static void update_stations(struct wpa_ctrl *ctrl);
 
@@ -474,7 +476,7 @@
 #endif /* CONFIG_P2P */
 		"country", "bss_max_count", "bss_expiration_age",
 		"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
-		"max_num_sta", "disassoc_low_ack",
+		"max_num_sta", "disassoc_low_ack", "ap_isolate",
 #ifdef CONFIG_HS20
 		"hs20",
 #endif /* CONFIG_HS20 */
@@ -571,7 +573,7 @@
 #endif /* CONFIG_P2P */
 		"bss_max_count", "bss_expiration_age",
 		"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
-		"max_num_sta", "disassoc_low_ack",
+		"max_num_sta", "disassoc_low_ack", "ap_isolate",
 #ifdef CONFIG_HS20
 		"hs20",
 #endif /* CONFIG_HS20 */
@@ -1519,14 +1521,56 @@
 
 static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	return wpa_ctrl_command(ctrl, "ADD_CRED");
+	int res = wpa_ctrl_command(ctrl, "ADD_CRED");
+	if (interactive)
+		update_creds(ctrl);
+	return res;
 }
 
 
 static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
 				   char *argv[])
 {
-	return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+	int res = wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+	if (interactive)
+		update_creds(ctrl);
+	return res;
+}
+
+
+static const char * const cred_fields[] = {
+	"temporary", "priority", "sp_priority", "pcsc", "eap",
+	"update_identifier", "min_dl_bandwidth_home", "min_ul_bandwidth_home",
+	"min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming", "max_bss_load",
+	"req_conn_capab", "ocsp", "sim_num", "realm", "username", "password",
+	"ca_cert", "client_cert", "private_key", "private_key_passwd", "imsi",
+	"milenage", "domain_suffix_match", "domain", "phase1", "phase2",
+	"roaming_consortium", "required_roaming_consortium", "excluded_ssid",
+	"roaming_partner", "provisioning_sp"
+};
+
+
+static char ** wpa_cli_complete_cred(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	int i, num_fields = ARRAY_SIZE(cred_fields);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&creds);
+		break;
+	case 2:
+		res = os_calloc(num_fields + 1, sizeof(char *));
+		if (res == NULL)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(cred_fields[i]);
+			if (res[i] == NULL)
+				break;
+		}
+	}
+	return res;
 }
 
 
@@ -2443,6 +2487,8 @@
 	return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
 }
 
+#endif /* CONFIG_P2P */
+
 
 static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc,
 				       char *argv[])
@@ -2464,7 +2510,6 @@
 	return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv);
 }
 
-#endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WIFI_DISPLAY
 
@@ -2903,6 +2948,13 @@
 }
 
 
+static int wpa_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, int argc,
+						char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
 				    char *argv[])
 {
@@ -3093,10 +3145,10 @@
 	{ "remove_cred", wpa_cli_cmd_remove_cred, NULL,
 	  cli_cmd_flag_none,
 	  "<cred id> = remove a credential" },
-	{ "set_cred", wpa_cli_cmd_set_cred, NULL,
+	{ "set_cred", wpa_cli_cmd_set_cred, wpa_cli_complete_cred,
 	  cli_cmd_flag_sensitive,
 	  "<cred id> <variable> <value> = set credential variables" },
-	{ "get_cred", wpa_cli_cmd_get_cred, NULL,
+	{ "get_cred", wpa_cli_cmd_get_cred, wpa_cli_complete_cred,
 	  cli_cmd_flag_none,
 	  "<cred id> <variable> = get credential variables" },
 	{ "save_config", wpa_cli_cmd_save_config, NULL,
@@ -3377,6 +3429,7 @@
 	{ "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
 	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
 	  "<address|iface=address> = remove a peer from all groups" },
+#endif /* CONFIG_P2P */
 	{ "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL,
 	  cli_cmd_flag_none,
 	  "<frame id> <hexdump of elem(s)> = add vendor specific IEs to frame(s)\n"
@@ -3389,7 +3442,6 @@
 	  cli_cmd_flag_none,
 	  "<frame id> <hexdump of elem(s)> = remove vendor specific IE(s) in frame(s)\n"
 	  VENDOR_ELEM_FRAME_ID },
-#endif /* CONFIG_P2P */
 #ifdef CONFIG_WIFI_DISPLAY
 	{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
 	  cli_cmd_flag_none,
@@ -3559,6 +3611,9 @@
 	{ "dpp_configurator_remove", wpa_cli_cmd_dpp_configurator_remove, NULL,
 	  cli_cmd_flag_none,
 	  "*|<id> = remove DPP configurator" },
+	{ "dpp_configurator_get_key", wpa_cli_cmd_dpp_configurator_get_key,
+	  NULL, cli_cmd_flag_none,
+	  "<id> = Get DPP configurator's private key" },
 	{ "dpp_pkex_add", wpa_cli_cmd_dpp_pkex_add, NULL,
 	  cli_cmd_flag_sensitive,
 	  "add PKEX code" },
@@ -3900,6 +3955,8 @@
 		wpa_cli_exec(action_file, ifname, pos);
 	} else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
 		wpa_cli_exec(action_file, ifname, pos);
+	} else if (str_starts(pos, HS20_T_C_ACCEPTANCE)) {
+		wpa_cli_exec(action_file, ifname, pos);
 	} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
 		printf("wpa_supplicant is terminating - stop monitoring\n");
 		wpa_cli_quit = 1;
@@ -4206,6 +4263,38 @@
 }
 
 
+static void update_creds(struct wpa_ctrl *ctrl)
+{
+	char buf[4096];
+	size_t len = sizeof(buf);
+	int ret;
+	const char *cmd = "LIST_CREDS";
+	char *pos, *end;
+	int header = 1;
+
+	cli_txt_list_flush(&creds);
+
+	if (ctrl == NULL)
+		return;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+	if (ret < 0)
+		return;
+	buf[len] = '\0';
+
+	pos = buf;
+	while (pos) {
+		end = os_strchr(pos, '\n');
+		if (end == NULL)
+			break;
+		*end = '\0';
+		if (!header)
+			cli_txt_list_add_word(&creds, pos, '\t');
+		header = 0;
+		pos = end + 1;
+	}
+}
+
+
 static void update_networks(struct wpa_ctrl *ctrl)
 {
 	char buf[4096];
@@ -4279,6 +4368,7 @@
 	}
 
 	update_bssid_list(ctrl_conn);
+	update_creds(ctrl_conn);
 	update_networks(ctrl_conn);
 	update_stations(ctrl_conn);
 
@@ -4302,6 +4392,7 @@
 	cli_txt_list_flush(&p2p_groups);
 	cli_txt_list_flush(&bsses);
 	cli_txt_list_flush(&ifnames);
+	cli_txt_list_flush(&creds);
 	cli_txt_list_flush(&networks);
 	if (edit_started)
 		edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index ee5710f..4432ec3 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -244,10 +244,30 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
 		"%d usec", sec, usec);
 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+	wpa_s->last_auth_timeout_sec = sec;
 	eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
 }
 
 
+/*
+ * wpas_auth_timeout_restart - Restart and change timeout for authentication
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec_diff: difference in seconds applied to original timeout value
+ */
+void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff)
+{
+	int new_sec = wpa_s->last_auth_timeout_sec + sec_diff;
+
+	if (eloop_is_timeout_registered(wpa_supplicant_timeout, wpa_s, NULL)) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Authentication timeout restart: %d sec", new_sec);
+		eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+		eloop_register_timeout(new_sec, 0, wpa_supplicant_timeout,
+				       wpa_s, NULL);
+	}
+}
+
+
 /**
  * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
  * @wpa_s: Pointer to wpa_supplicant data
@@ -261,6 +281,9 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
 	wpa_blacklist_del(wpa_s, wpa_s->bssid);
+	os_free(wpa_s->last_con_fail_realm);
+	wpa_s->last_con_fail_realm = NULL;
+	wpa_s->last_con_fail_realm_len = 0;
 }
 
 
@@ -485,6 +508,10 @@
 	os_free(wpa_s->confanother);
 	wpa_s->confanother = NULL;
 
+	os_free(wpa_s->last_con_fail_realm);
+	wpa_s->last_con_fail_realm = NULL;
+	wpa_s->last_con_fail_realm_len = 0;
+
 	wpa_sm_set_eapol(wpa_s->wpa, NULL);
 	eapol_sm_deinit(wpa_s->eapol);
 	wpa_s->eapol = NULL;
@@ -1011,7 +1038,13 @@
 			"file '%s' - exiting", wpa_s->confname);
 		return -1;
 	}
-	wpa_config_read(wpa_s->confanother, conf);
+	if (wpa_s->confanother &&
+	    !wpa_config_read(wpa_s->confanother, conf)) {
+		wpa_msg(wpa_s, MSG_ERROR,
+			"Failed to parse the configuration file '%s' - exiting",
+			wpa_s->confanother);
+		return -1;
+	}
 
 	conf->changed_parameters = (unsigned int) -1;
 
@@ -1192,6 +1225,13 @@
 		ie.pairwise_cipher = WPA_CIPHER_CCMP;
 		ie.key_mgmt = WPA_KEY_MGMT_OSEN;
 		proto = WPA_PROTO_OSEN;
+	} else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) &&
+	    wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
+	    (ie.group_cipher & ssid->group_cipher) &&
+	    (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+	    (ie.key_mgmt & ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)");
+		proto = WPA_PROTO_RSN;
 #endif /* CONFIG_HS20 */
 	} else if (bss) {
 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
@@ -1262,6 +1302,16 @@
 						WPA_CIPHER_AES_128_CMAC;
 			}
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OWE
+			if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+			    !ssid->owe_only &&
+			    !bss_wpa && !bss_rsn && !bss_osen) {
+				wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+				wpa_s->wpa_proto = 0;
+				*wpa_ie_len = 0;
+				return 0;
+			}
+#endif /* CONFIG_OWE */
 			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
 				"based on configuration");
 		} else
@@ -1351,9 +1401,29 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
 #endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SHA384
+	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT FT/802.1X-SHA384");
+		if (pmksa_cache_get_current(wpa_s->wpa)) {
+			/* PMKSA caching with FT is not fully functional, so
+			 * disable the case for now. */
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"WPA: Disable PMKSA caching for FT/802.1X connection");
+			pmksa_cache_clear_current(wpa_s->wpa);
+		}
+#endif /* CONFIG_SHA384 */
 	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
+		if (pmksa_cache_get_current(wpa_s->wpa)) {
+			/* PMKSA caching with FT is not fully functional, so
+			 * disable the case for now. */
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"WPA: Disable PMKSA caching for FT/802.1X connection");
+			pmksa_cache_clear_current(wpa_s->wpa);
+		}
 	} else if (sel & WPA_KEY_MGMT_FT_PSK) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
@@ -1451,19 +1521,27 @@
 
 	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
 		int psk_set = 0;
+		int sae_only;
 
-		if (ssid->psk_set) {
+		sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK |
+					      WPA_KEY_MGMT_FT_PSK |
+					      WPA_KEY_MGMT_PSK_SHA256)) == 0;
+
+		if (ssid->psk_set && !sae_only) {
+			wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
+					ssid->psk, PMK_LEN);
 			wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
 				       NULL);
 			psk_set = 1;
 		}
 
-		if (wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password)
+		if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+		    (ssid->sae_password || ssid->passphrase))
 			psk_set = 1;
 
 #ifndef CONFIG_NO_PBKDF2
 		if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
-		    ssid->passphrase) {
+		    ssid->passphrase && !sae_only) {
 			u8 psk[PMK_LEN];
 		        pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
 				    4096, psk, PMK_LEN);
@@ -1475,7 +1553,7 @@
 		}
 #endif /* CONFIG_NO_PBKDF2 */
 #ifdef CONFIG_EXT_PASSWORD
-		if (ssid->ext_psk) {
+		if (ssid->ext_psk && !sae_only) {
 			struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
 							     ssid->ext_psk);
 			char pw_str[64 + 1];
@@ -1521,6 +1599,9 @@
 					ext_password_free(pw);
 					return -1;
 				}
+				wpa_hexdump_key(MSG_MSGDUMP,
+						"PSK (from external PSK)",
+						psk, PMK_LEN);
 				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
 					       NULL);
 				psk_set = 1;
@@ -1541,6 +1622,7 @@
 		if (!psk_set) {
 			wpa_msg(wpa_s, MSG_INFO,
 				"No PSK available for association");
+			wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
 			return -1;
 		}
 #ifdef CONFIG_OWE
@@ -1564,6 +1646,10 @@
 	case 0: /* Bits 0-7 */
 		break;
 	case 1: /* Bits 8-15 */
+		if (wpa_s->conf->coloc_intf_reporting) {
+			/* Bit 13 - Collocated Interference Reporting */
+			*pos |= 0x20;
+		}
 		break;
 	case 2: /* Bits 16-23 */
 #ifdef CONFIG_WNM
@@ -1582,7 +1668,7 @@
 		break;
 	case 4: /* Bits 32-39 */
 #ifdef CONFIG_INTERWORKING
-		if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING)
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)
 			*pos |= 0x01; /* Bit 32 - QoS Map */
 #endif /* CONFIG_INTERWORKING */
 		break;
@@ -1607,7 +1693,8 @@
 		break;
 	case 9: /* Bits 72-79 */
 #ifdef CONFIG_FILS
-		*pos |= 0x01;
+		if (!wpa_s->disable_fils)
+			*pos |= 0x01;
 #endif /* CONFIG_FILS */
 		break;
 	}
@@ -2328,6 +2415,27 @@
 
 	return ie_len;
 }
+
+
+int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
+{
+	return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+		 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
+		(!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+		 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
+}
+
+
+int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_FILS_SK_PFS
+	return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
+#else /* CONFIG_FILS_SK_PFS */
+	return 0;
+#endif /* CONFIG_FILS_SK_PFS */
+}
+
 #endif /* CONFIG_FILS */
 
 
@@ -2341,6 +2449,9 @@
 	size_t max_wpa_ie_len = 500;
 	size_t wpa_ie_len;
 	int algs = WPA_AUTH_ALG_OPEN;
+#ifdef CONFIG_MBO
+	const u8 *mbo_ie;
+#endif
 #ifdef CONFIG_FILS
 	const u8 *realm, *username, *rrk;
 	size_t realm_len, username_len, rrk_len;
@@ -2378,7 +2489,7 @@
 #endif /* CONFIG_FILS */
 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
 					    ssid, try_opportunistic,
-					    cache_id) == 0)
+					    cache_id, 0) == 0)
 			eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
 		wpa_ie_len = max_wpa_ie_len;
 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -2449,7 +2560,10 @@
 	    ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
 	    eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
 				  &username_len, &realm, &realm_len,
-				  &next_seq_num, &rrk, &rrk_len) == 0) {
+				  &next_seq_num, &rrk, &rrk_len) == 0 &&
+	    (!wpa_s->last_con_fail_realm ||
+	     wpa_s->last_con_fail_realm_len != realm_len ||
+	     os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) {
 		algs = WPA_AUTH_ALG_FILS;
 		params->fils_erp_username = username;
 		params->fils_erp_username_len = username_len;
@@ -2464,6 +2578,10 @@
 	}
 #endif /* CONFIG_FILS */
 #endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_SAE
+	if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
+		algs = WPA_AUTH_ALG_SAE;
+#endif /* CONFIG_SAE */
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
 	if (ssid->auth_alg) {
@@ -2544,12 +2662,13 @@
 	if (is_hs20_network(wpa_s, ssid, bss)) {
 		struct wpabuf *hs20;
 
-		hs20 = wpabuf_alloc(20);
+		hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
 		if (hs20) {
 			int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
 			size_t len;
 
 			wpas_hs20_add_indication(hs20, pps_mo_id);
+			wpas_hs20_add_roam_cons_sel(hs20, ssid);
 			len = max_wpa_ie_len - wpa_ie_len;
 			if (wpabuf_len(hs20) <= len) {
 				os_memcpy(wpa_ie + wpa_ie_len,
@@ -2588,11 +2707,14 @@
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_MBO
-	if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+	mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
+	if (mbo_ie) {
 		int len;
 
 		len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
-				  max_wpa_ie_len - wpa_ie_len);
+				  max_wpa_ie_len - wpa_ie_len,
+				  !!mbo_attr_from_mbo_ie(mbo_ie,
+							 OCE_ATTR_ID_CAPA_IND));
 		if (len >= 0)
 			wpa_ie_len += len;
 	}
@@ -2609,13 +2731,28 @@
 #endif /* CONFIG_FILS */
 
 #ifdef CONFIG_OWE
+#ifdef CONFIG_TESTING_OPTIONS
+	if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
+		wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
+	} else
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (algs == WPA_AUTH_ALG_OPEN &&
 	    ssid->key_mgmt == WPA_KEY_MGMT_OWE) {
 		struct wpabuf *owe_ie;
-		u16 group = OWE_DH_GROUP;
+		u16 group;
 
-		if (ssid->owe_group)
+		if (ssid->owe_group) {
 			group = ssid->owe_group;
+		} else {
+			if (wpa_s->last_owe_group == 19)
+				group = 20;
+			else if (wpa_s->last_owe_group == 20)
+				group = 21;
+			else
+				group = OWE_DH_GROUP;
+		}
+		wpa_s->last_owe_group = group;
+		wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
 		owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
 		if (owe_ie &&
 		    wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
@@ -2627,6 +2764,39 @@
 	}
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_IEEE80211R
+	/*
+	 * Add MDIE under these conditions: the network profile allows FT,
+	 * the AP supports FT, and the mobility domain ID matches.
+	 */
+	if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) {
+		const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+
+		if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
+			size_t len = 0;
+			const u8 *md = mdie + 2;
+			const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa);
+
+			if (os_memcmp(md, wpa_md,
+				      MOBILITY_DOMAIN_ID_LEN) == 0) {
+				/* Add mobility domain IE */
+				len = wpa_ft_add_mdie(
+					wpa_s->wpa, wpa_ie + wpa_ie_len,
+					max_wpa_ie_len - wpa_ie_len, mdie);
+				wpa_ie_len += len;
+			}
+#ifdef CONFIG_SME
+			if (len > 0 && wpa_s->sme.ft_used &&
+			    wpa_sm_has_ptk(wpa_s->wpa)) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"SME: Trying to use FT over-the-air");
+				algs |= WPA_AUTH_ALG_FT;
+			}
+#endif /* CONFIG_SME */
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
 	params->wpa_ie = wpa_ie;
 	params->wpa_ie_len = wpa_ie_len;
 	params->auth_alg = algs;
@@ -2910,6 +3080,11 @@
 				"MFP: require MFP");
 			params.mgmt_frame_protection =
 				MGMT_FRAME_PROTECTION_REQUIRED;
+#ifdef CONFIG_OWE
+		} else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+			   !ssid->owe_only) {
+			params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_OWE */
 		}
 	}
 #endif /* CONFIG_IEEE80211W */
@@ -3137,6 +3312,7 @@
 		return;
 
 	ssid->disabled = 0;
+	ssid->owe_transition_bss_select_count = 0;
 	wpas_clear_temp_disabled(wpa_s, ssid, 1);
 	wpas_notify_network_enabled_changed(wpa_s, ssid);
 
@@ -3400,6 +3576,9 @@
 
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
+	wpa_s->last_owe_group = 0;
+	if (ssid)
+		ssid->owe_transition_bss_select_count = 0;
 
 	if (wpa_s->connect_without_scan ||
 	    wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -3957,6 +4136,11 @@
 					   wpa_supplicant_rx_eapol, wpa_s, 0);
 		if (wpa_s->l2 == NULL)
 			return -1;
+
+		if (l2_packet_set_packet_filter(wpa_s->l2,
+						L2_PACKET_FILTER_PKTTYPE))
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Failed to attach pkt_type filter");
 	} else {
 		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
 		if (addr)
@@ -4712,7 +4896,7 @@
 	if (work->started) {
 		work->wpa_s->radio->num_active_works--;
 		wpa_dbg(work->wpa_s, MSG_DEBUG,
-			"radio_work_free('%s'@%p: num_active_works --> %u",
+			"radio_work_free('%s'@%p): num_active_works --> %u",
 			work->type, work,
 			work->wpa_s->radio->num_active_works);
 	}
@@ -4919,6 +5103,22 @@
 }
 
 
+void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
+{
+	struct wpa_radio_work *work;
+	struct wpa_radio *radio = wpa_s->radio;
+
+	dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+		if (work->ctx != ctx)
+			continue;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
+			work->type, work, work->started ? " (started)" : "");
+		radio_work_free(work);
+		break;
+	}
+}
+
+
 static void radio_remove_interface(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_radio *radio = wpa_s->radio;
@@ -5071,7 +5271,7 @@
 
 
 static int wpas_init_driver(struct wpa_supplicant *wpa_s,
-			    struct wpa_interface *iface)
+			    const struct wpa_interface *iface)
 {
 	const char *ifname, *driver, *rn;
 
@@ -5155,7 +5355,7 @@
 #endif /* CONFIG_GAS_SERVER */
 
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
-				     struct wpa_interface *iface)
+				     const struct wpa_interface *iface)
 {
 	struct wpa_driver_capa capa;
 	int capa_res;
@@ -5189,7 +5389,13 @@
 			return -1;
 		}
 		wpa_s->confanother = os_rel2abs_path(iface->confanother);
-		wpa_config_read(wpa_s->confanother, wpa_s->conf);
+		if (wpa_s->confanother &&
+		    !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to read or parse configuration '%s'.",
+				   wpa_s->confanother);
+			return -1;
+		}
 
 		/*
 		 * Override ctrl_interface and driver_param if set on command
@@ -5350,8 +5556,6 @@
 	 */
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
 		wpa_s->p2p_mgmt = iface->p2p_mgmt;
-	else
-		iface->p2p_mgmt = 1;
 
 	if (wpa_s->num_multichan_concurrent == 0)
 		wpa_s->num_multichan_concurrent = 1;
@@ -5360,10 +5564,7 @@
 		return -1;
 
 #ifdef CONFIG_TDLS
-	if ((!iface->p2p_mgmt ||
-	     !(wpa_s->drv_flags &
-	       WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
-	    wpa_tdls_init(wpa_s->wpa))
+	if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
 		return -1;
 #endif /* CONFIG_TDLS */
 
@@ -5435,7 +5636,9 @@
 		return -1;
 	}
 
-	if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+	if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
+	     wpa_s->p2p_mgmt) &&
+	    wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
 		return -1;
 	}
@@ -6332,6 +6535,35 @@
 }
 
 
+#ifdef CONFIG_FILS
+void fils_connection_failure(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const u8 *realm, *username, *rrk;
+	size_t realm_len, username_len, rrk_len;
+	u16 next_seq_num;
+
+	if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) ||
+	    eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+				  &username, &username_len,
+				  &realm, &realm_len, &next_seq_num,
+				  &rrk, &rrk_len) != 0 ||
+	    !realm)
+		return;
+
+	wpa_hexdump_ascii(MSG_DEBUG,
+			  "FILS: Store last connection failure realm",
+			  realm, realm_len);
+	os_free(wpa_s->last_con_fail_realm);
+	wpa_s->last_con_fail_realm = os_malloc(realm_len);
+	if (wpa_s->last_con_fail_realm) {
+		wpa_s->last_con_fail_realm_len = realm_len;
+		os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len);
+	}
+}
+#endif /* CONFIG_FILS */
+
+
 int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
 {
 	return wpa_s->conf->ap_scan == 2 ||
@@ -6691,6 +6923,7 @@
 	wpa_s->extra_blacklist_count = 0;
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
+	wpa_s->last_owe_group = 0;
 
 	if (wpa_supplicant_fast_associate(wpa_s) != 1)
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 61eb38f..4f59160 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -597,6 +597,20 @@
 #	pre-configured with the credential since the NAI Realm information
 #	may not be available or fetched.
 #
+# required_roaming_consortium: Required Roaming Consortium OI
+#	If required_roaming_consortium_len is non-zero, this field contains the
+#	Roaming Consortium OI that is required to be advertised by the AP for
+#	the credential to be considered matching.
+#
+# roaming_consortiums: Roaming Consortium OI(s) memberships
+#	This string field contains one or more comma delimited OIs (hexdump)
+#	identifying the roaming consortiums of which the provider is a member.
+#	The list is sorted from the most preferred one to the least preferred
+#	one. A match between the Roaming Consortium OIs advertised by an AP and
+#	the OIs in this list indicates that successful authentication is
+#	possible.
+#	(Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+#
 # eap: Pre-configured EAP method
 #	This optional field can be used to specify which EAP method will be
 #	used with this credential. If not set, the EAP method is selected
@@ -851,6 +865,7 @@
 # proto: list of accepted protocols
 # WPA = WPA/IEEE 802.11i/D3.0
 # RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
+# Note that RSN is used also for WPA3.
 # If not set, this defaults to: WPA RSN
 #
 # key_mgmt: list of accepted authenticated key management protocols
@@ -863,11 +878,13 @@
 #	instead)
 # FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key
 # FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+# FT-EAP-SHA384 = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+#	and using SHA384
 # WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
 # WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
 # SAE = Simultaneous authentication of equals; pre-shared key/password -based
 #	authentication with stronger security than WPA-PSK especially when using
-#	not that strong password
+#	not that strong password; a.k.a. WPA3-Personal
 # FT-SAE = SAE with FT
 # WPA-EAP-SUITE-B = Suite B 128-bit level
 # WPA-EAP-SUITE-B-192 = Suite B 192-bit level
@@ -876,6 +893,8 @@
 # FILS-SHA384 = Fast Initial Link Setup with SHA384
 # FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
 # FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+# DPP = Device Provisioning Protocol
 # If not set, this defaults to: WPA-PSK WPA-EAP
 #
 # ieee80211w: whether management frame protection is enabled
@@ -936,9 +955,14 @@
 #
 # sae_password: SAE password
 # This parameter can be used to set a password for SAE. By default, the
-# passphrase value is used if this separate parameter is not used, but
-# passphrase follows the WPA-PSK constraints (8..63 characters) even
-# though SAE passwords do not have such constraints.
+# passphrase from the psk parameter is used if this separate parameter is not
+# used, but psk follows the WPA-PSK constraints (8..63 characters) even though
+# SAE passwords do not have such constraints.
+#
+# sae_password_id: SAE password identifier
+# This parameter can be used to set an identifier for the SAE password. By
+# default, no such identifier is used. If set, the specified identifier value
+# is used by the other peer to select which password to use for authentication.
 #
 # eapol_flags: IEEE 802.1X/EAPOL options (bit field)
 # Dynamic WEP key required for non-WPA mode
@@ -1196,6 +1220,8 @@
 #	that have issues interoperating with updated TLS version)
 # tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
 #	that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_3=1 - disable use of TLSv1.3 (a workaround for AAA servers
+#	that have issues interoperating with updated TLS version)
 # tls_ext_cert_check=0 - No external server certificate validation (default)
 # tls_ext_cert_check=1 - External server certificate validation enabled; this
 #	requires an external program doing validation of server certificate
@@ -1273,6 +1299,10 @@
 
 # update_identifier: PPS MO ID
 #	(Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+#
+# roaming_consortium_selection: Roaming Consortium Selection
+#	The matching Roaming Consortium OI that was used to generate this
+#	network profile.
 
 # Station inactivity limit
 #
@@ -1765,15 +1795,26 @@
 }
 
 
-# Example MACsec configuration
-#network={
-#	key_mgmt=IEEE8021X
-#	eap=TTLS
-#	phase2="auth=PAP"
-#	anonymous_identity="anonymous@example.com"
-#	identity="user@example.com"
-#	password="secretr"
-#	ca_cert="/etc/cert/ca.pem"
-#	eapol_flags=0
-#	macsec_policy=1
-#}
+# Example configuration using EAP-TTLS for authentication and key
+# generation for MACsec
+network={
+	key_mgmt=IEEE8021X
+	eap=TTLS
+	phase2="auth=PAP"
+	anonymous_identity="anonymous@example.com"
+	identity="user@example.com"
+	password="secretr"
+	ca_cert="/etc/cert/ca.pem"
+	eapol_flags=0
+	macsec_policy=1
+}
+
+# Example configuration for MACsec with preshared key
+network={
+	key_mgmt=NONE
+	eapol_flags=0
+	macsec_policy=1
+	mka_cak=0123456789ABCDEF0123456789ABCDEF
+	mka_ckn=6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435
+	mka_priority=128
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index acde7c5..abacaa9 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -345,6 +345,7 @@
 void radio_work_done(struct wpa_radio_work *work);
 void radio_remove_works(struct wpa_supplicant *wpa_s,
 			const char *type, int remove_all);
+void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx);
 void radio_work_check_next(struct wpa_supplicant *wpa_s);
 struct wpa_radio_work *
 radio_work_pending(struct wpa_supplicant *wpa_s, const char *type);
@@ -531,6 +532,8 @@
 	struct wpa_bss *current_bss;
 	int ap_ies_from_associnfo;
 	unsigned int assoc_freq;
+	u8 *last_con_fail_realm;
+	size_t last_con_fail_realm_len;
 
 	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
 	int pairwise_cipher;
@@ -740,6 +743,8 @@
 	unsigned int mac_addr_changed:1;
 	unsigned int added_vif:1;
 	unsigned int wnmsleep_used:1;
+	unsigned int owe_transition_select:1;
+	unsigned int owe_transition_search:1;
 
 	struct os_reltime last_mac_addr_change;
 	int last_mac_addr_style;
@@ -751,6 +756,7 @@
 	int set_ap_uapsd;
 	int ap_uapsd;
 	int auth_alg;
+	u16 last_owe_group;
 
 #ifdef CONFIG_SME
 	struct {
@@ -788,6 +794,8 @@
 		struct wpabuf *sae_token;
 		int sae_group_index;
 		unsigned int sae_pmksa_caching:1;
+		u16 seq_num;
+		struct external_auth ext_auth;
 #endif /* CONFIG_SAE */
 	} sme;
 #endif /* CONFIG_SME */
@@ -897,6 +905,7 @@
 
 	unsigned int p2p_auto_join:1;
 	unsigned int p2p_auto_pd:1;
+	unsigned int p2p_go_do_acs:1;
 	unsigned int p2p_persistent_group:1;
 	unsigned int p2p_fallback_to_go_neg:1;
 	unsigned int p2p_pd_before_go_neg:1;
@@ -912,6 +921,7 @@
 	unsigned int p2p_disable_ip_addr_req:1;
 	unsigned int p2ps_method_config_any:1;
 	unsigned int p2p_cli_probe:1;
+	enum hostapd_hw_mode p2p_go_acs_band;
 	int p2p_persistent_go_freq;
 	int p2p_persistent_id;
 	int p2p_go_intent;
@@ -1051,6 +1061,10 @@
 	struct neighbor_report *wnm_neighbor_report_elements;
 	struct os_reltime wnm_cand_valid_until;
 	u8 wnm_cand_from_bss[ETH_ALEN];
+	struct wpabuf *coloc_intf_elems;
+	u8 coloc_intf_dialog_token;
+	u8 coloc_intf_auto_report;
+	u8 coloc_intf_timeout;
 #ifdef CONFIG_MBO
 	unsigned int wnm_mbo_trans_reason_present:1;
 	u8 wnm_mbo_transition_reason;
@@ -1178,6 +1192,8 @@
 	/* RIC elements for FT protocol */
 	struct wpabuf *ric_ies;
 
+	int last_auth_timeout_sec;
+
 #ifdef CONFIG_DPP
 	struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
 	struct dl_list dpp_configurator; /* struct dpp_configurator */
@@ -1190,7 +1206,9 @@
 	int dpp_qr_mutual;
 	int dpp_netrole_ap;
 	int dpp_auth_ok_on_ack;
+	int dpp_in_response_listen;
 	int dpp_gas_client;
+	int dpp_gas_dialog_token;
 	u8 dpp_intro_bssid[ETH_ALEN];
 	void *dpp_intro_network;
 	struct dpp_pkex *dpp_pkex;
@@ -1199,6 +1217,13 @@
 	char *dpp_pkex_identifier;
 	char *dpp_pkex_auth_cmd;
 	char *dpp_configurator_params;
+	struct os_reltime dpp_last_init;
+	struct os_reltime dpp_init_iter_start;
+	unsigned int dpp_init_max_tries;
+	unsigned int dpp_init_retry_time;
+	unsigned int dpp_resp_wait_time;
+	unsigned int dpp_resp_max_tries;
+	unsigned int dpp_resp_retry_time;
 #ifdef CONFIG_TESTING_OPTIONS
 	char *dpp_config_obj_override;
 	char *dpp_discovery_override;
@@ -1206,6 +1231,11 @@
 	unsigned int dpp_ignore_netaccesskey_mismatch:1;
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_DPP */
+
+#ifdef CONFIG_FILS
+	unsigned int disable_fils:1;
+#endif /* CONFIG_FILS */
+	unsigned int ieee80211ac:1;
 };
 
 
@@ -1238,6 +1268,7 @@
 void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
 void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
 				     int sec, int usec);
+void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff);
 void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 			      enum wpa_states state);
@@ -1295,6 +1326,7 @@
 void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
 void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void fils_connection_failure(struct wpa_supplicant *wpa_s);
 int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
 int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
 void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason);
@@ -1335,7 +1367,9 @@
 
 
 /* MBO functions */
-int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len);
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
+		int add_oce_capa);
+const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
 const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
 int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
 				  const char *non_pref_chan);
@@ -1472,4 +1506,7 @@
 						unsigned int *num,
 						unsigned int *freq_list);
 
+int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
+int wpa_is_fils_sk_pfs_supported(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 e29f13b..4634ed7 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1037,6 +1037,7 @@
 	wpas_notify_eap_status(wpa_s, status, parameter);
 }
 
+
 static void wpa_supplicant_eap_error_cb(void *ctx, int error_code)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -1044,6 +1045,7 @@
 	wpas_notify_eap_error(wpa_s, error_code);
 }
 
+
 static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index 587e5c3..d3d06b8 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -5,7 +5,7 @@
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  */
-#include <openssl/ssl.h>
+
 #include "utils/includes.h"
 
 #include "utils/common.h"
@@ -268,7 +268,7 @@
 		return -1;
 	}
 
-	need_len = 1 + 2 * SSL3_RANDOM_SIZE;
+	need_len = 1 + 2 * 32 /* random size */;
 	if (need_len > id_len) {
 		wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
 		return -1;
@@ -392,25 +392,25 @@
 {
 	struct mka_key *cak;
 	struct mka_key_name *ckn;
-	void *res;
+	void *res = NULL;
 
 	if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
-		return NULL;
-
-	if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0)
-		return NULL;
-
-	if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
-		return NULL;
+		goto end;
 
 	ckn = os_zalloc(sizeof(*ckn));
 	if (!ckn)
-		goto dealloc;
+		goto end;
 
 	cak = os_zalloc(sizeof(*cak));
 	if (!cak)
 		goto free_ckn;
 
+	if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0 || !wpa_s->kay)
+		goto free_cak;
+
+	if (wpa_s->kay->policy == DO_NOT_SECURE)
+		goto dealloc;
+
 	cak->len = MACSEC_CAK_LEN;
 	os_memcpy(cak->key, ssid->mka_cak, cak->len);
 
@@ -419,17 +419,15 @@
 
 	res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
 	if (res)
-		return res;
+		goto free_cak;
 
+dealloc:
 	/* Failed to create MKA */
+	ieee802_1x_dealloc_kay_sm(wpa_s);
+free_cak:
 	os_free(cak);
-
-	/* fallthrough */
-
 free_ckn:
 	os_free(ckn);
-dealloc:
-	ieee802_1x_dealloc_kay_sm(wpa_s);
-
-	return NULL;
+end:
+	return res;
 }
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index bd8af83..4fffd80 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -203,6 +203,9 @@
 	if (ssid->ssid == NULL)
 		return;
 	bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
+	if (!bss)
+		bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+				  ssid->ssid, ssid->ssid_len);
 	if (bss == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
 			   "table - use credential as-is");
@@ -490,6 +493,16 @@
 			ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
 			ssid->group_cipher |= WPA_CIPHER_GCMP;
 		}
+		if (wpa_s->drv_capa_known &&
+		    (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256)) {
+			ssid->pairwise_cipher |= WPA_CIPHER_GCMP_256;
+			ssid->group_cipher |= WPA_CIPHER_GCMP_256;
+		}
+		if (wpa_s->drv_capa_known &&
+		    (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256)) {
+			ssid->pairwise_cipher |= WPA_CIPHER_CCMP_256;
+			ssid->group_cipher |= WPA_CIPHER_CCMP_256;
+		}
 		break;
 	}