[wpa_supplicant] Cumulative patch from 89bbe6f87

Bug: 130294744
Test: Device boots up and connects to WPA3/OWE wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: DPP test: act.py -c ../WifiDppConfig.json -tc WifiDppTest
Test: Regression test passed (Bug: 130312227)

89bbe6f87 EAP-pwd: Get rid of unnecessary allocation of temporary buffer
4396f74a3 EAP-pwd: Enforce 1 < rand,mask < r and rand+mask mod r > 1
72056f69a tests: Module tests for const_time_*() functions
16d4f1069 EAP-pwd: Check element x,y coordinates explicitly
8ad8585f9 EAP-pwd client: Verify received scalar and element
d63edfa90 EAP-pwd server: Detect reflection attacks
70ff850e8 EAP-pwd server: Verify received scalar and element
ac8fa9ef1 SAE: Fix confirm message validation in error cases
cff138b07 SAE: Use constant time operations in sae_test_pwd_seed_ffc()
f8f20717f SAE: Use const_time selection for PWE in FFC
90839597c SAE: Mask timing of MODP groups 22, 23, 24
362704dda SAE: Avoid branches in is_quadratic_residue_blind()
6513db3e9 SAE: Minimize timing differences in PWE derivation
aaf65feac EAP-pwd: Use constant time and memory access for finding the PWE
c93461c1d OpenSSL: Use constant time selection for crypto_bignum_legendre()
6e34f618d Add helper functions for constant time operations
d42c477cc OpenSSL: Use constant time operations for private bignums
242e85728 Extend domain_match and domain_suffix_match to allow list of values
dcc0ccd5b wolfSSL: Fix dNSName matching with domain_match and domain_suffix_match
83f13e4ff tests: Fix build without CONFIG_SAE
3580ed826 RADIUS server: Accept ERP keyName-NAI as user identity
bbde461d7 Fix a typo in the Multiple BSSID Index element ID define
1326cb765 DPP: Fix a regression in non-DPP, non-OpenSSL builds
db54db11a SAE: Reject unsuitable groups based on REVmd changes
6bb9d9a8d AP: Avoid NULL use with snprintf string
0a42f1ede scan: Use normal scans after connection failure
bbed23aee hostapd: Reduce minimum beacon interval from 15 to 10 TUs
048796715 OWE: Fix a possible memory leak on error path
277fa92b3 crypto: Fix unreachable code in tls_prf_sha1_md5()
3d93e26e6 tests: SAE test vector from IEEE P802.11-REVmd/D2.1, Annex J.10
e5711b618 Add a QCA vendor attribute to carry the reason for roaming
005585d60 nl80211: Add SAE, FT-SAE, FT-EAP-SHA384 AKMs in connect request
edcaf16f9 P2P: Enable HE for both 2G and 5G bands
822c756e8 MBO: Update connect params with new MBO attributes to driver
74f8e768f MBO: Always include Non-preferred Channel Report attribute in AssocReq
bd23daa8e DPP: Move GAS encapsulation into dpp_build_conf_req()
be609c6fc SAE: Fix commit message override with external authentication
9af1eea37 Prefer FT-SAE over FT-PSK if both are enabled
853bd19f2 Add more debug prints on suite selector selection
6d77014e7 Suite B: Prefer FT-EAP-SHA384 over WPA-EAP-SUITE-B-192
ab3aebcce SAE: Fix PMKSA cache entry search for FT-SAE case
253ce212e Add AKM info in the debug message noting PMKSA caching entry addition
6fe3f0f79 FT-SAE: Use PMK as XXKey in AP when SAE PMKSA caching is used
bcf190005 FT-SAE: Enable external auth support for FT-SAE also
6d14b98fc nl80211: Do not add WMM parameters when updating an existing STA entry
2ffd8076d FT/RRB: Pad RRB messages to at least minimum Ethernet frame length
555c93e2d FT/RRB: Add more debug prints for RRB message encryption/decryptiom
76fd782ab SAE: Reorder SAE and FT-SAE AKM selection to prefer the FT option
322d328e7 FT: Fix SAE + FT-SAE behavior in association parameter selection
87d8435cf DPP: Common configurator/bootstrapping data management
08dc8efd2 Fix memcpy regression in PMK handling
130444738 FILS: Fix KEK2 derivation for FILS+FT
bf84e78cb OpenSSL: Fix build with current BoringSSL
b750dde64 OWE: Move Association Response frame IE addition to appropriate place
10ec6a5f3 DPP2: PFS for PTK derivation
ecacd9ccd DPP2: Extend wpa_pmk_to_ptk() to support extra Z.x component in context
16a4e931f OWE: Allow Diffie-Hellman Parameter element to be included with DPP
808bdb308 Add TEST_FAIL() to aes_encrypt_init() with internal crypto
32f476066 TLS: Add support for RFC 5705 TLS exporter context with internal TLS
a916ff5cd Add support for an optional context parameter to TLS exporter
18015fc8a DPP2: Support new legacy+DPP config object credentials
dd6c59800 DPP: Support DPP and SAE in the same network profile
9305c2332 DPP: Clean up configuration parsing
f5db77504 Remove pending connect and sme-connect radio works on disconnect
c675397cc OpenSSL: Fix build with OpenSSL 1.0.2
ff5f54e15 SAE: Reduce queue wait time for pending Authentication frames
5e3a759cd SAE: Improved queuing policy for pending authentication frames
67b3bcc95 DPP2: Testing option for Config Object rejction
22f90b32f DPP2: Configuration Result message generation and processing
c98617b48 DPP2: Make DPP version number support available over control interface
673631b8a More robust timer_tick_enabled tracking
b5e57699a FILS+FT: STA mode validation of PMKR1Name in initial MD association
365366393 FILS+FT: AP mode processing of PMKR1Name in initial MD association
aabbdb818 FILS: Do not try to add PMKSA cache entry if caching is disabled
02bde9581 Vendor attribute to enable or disable TWT request support
4efade315 nl80211: Clear keys from heap memory before freeing it for get_seqnum
2b7fa0355 P2P: Fix ACS offloading behavior with p2p_no_group_iface=1
c6ec9759c nl80211: Exclude PMK when sending NL80211_CMD_DEL_PMKSA explicitly
0b4a906de DPP2: Protocol version indication
ce7effd08 DPP2: Build configuration flags for DPP version 2 support
bf0021ede Allow fragmentation/RTS threshold to be disabled explicitly
48102f65e Add a vendor subcommand QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG
f10a4af1b Add QCA vendor command/event and attributes for peer rate statistics
56a33496f Sync with mac80211-next.git include/uapi/linux/nl80211.h
841205a1c OpenSSL: Add 'check_cert_subject' support for TLS server
0173423f4 Use char pointers for EAP configuration parameters without length
cd6a5866e Remove forgotten os_strncpy() implementations
ca9efe113 roboswitch: Check some read operation results
9571f945c mesh: Check that SAE state initialization succeeded for PMKID check
fafad8527 defconfig: Enable DBus
6a8dee76d wpa_supplicant: Drop the old D-Bus interface support
954c535a5 DPP: Update wpa_supplicant configuration file after provisioning
4d379be4a Clarify AP mode Action frame handling
cc833a236 Minor cleanup to return after WNM Action frame handling
700b3f395 Move SA Query frame length check to the shared handler function
002edb630 Fix AP MLME in driver handling of FT and SA Query Action frames
1e653daa3 EAP-pwd server: Fix memory leak with salted passwords
96d6dfa8e SAE: Add Finite Cyclic Group field in status code 77 response
fda766010 EAP-pwd: Fix a memory leak in hunting-and-pecking loop
339dc8bd6 WPS: Allow SAE configuration to be added automatically for PSK
fc30f99b3 WPS: Allow AP SAE configuration to be added automatically for PSK
b9cd4f5e7 Vendor feature capability for TWT (Target Wake Time)
877502a6a Vendor attribute to indicate a set_blacklist of BSSID only as a hint
a9247bcdf Vendor attribute to configure HE testbed default capabilities
8a7510cc0 Vendor attribute to configure support to enable VHT in 2.4G band
8919ec616 Vendor attribute to configure HE OMI UL MU data disable
f21436158 SAE: Reuse previously generated PWE on a retry with the same STA
fd8308912 SAE: Reuse previously generated PWE on a retry with the same AP
a9af1da0b SAE: Enforce single use for anti-clogging tokens
ff9f40aee SAE: Process received commit message through a queue
a9fe13035 SAE: Enable only groups 19, 20, and 21 in station mode
941bad5ef SAE: Enable only group 19 by default in AP mode
b11fa98bc Add explicit checks for peer's DH public key
4a9531a75 bignum: Fix documentation for bignum_cmp_d()
611308365 defconfig: Enable IEEE 802.11w management frame protection (wpa_supplicant)
9515fa925 defconfig: enable IEEE 802.11r fast BSS transition (wpa_supplicant)
6b7a0da75 defconfig: Enable IEEE 802.11n and 802.11ac (wpa_supplicant)
467004d63 defconfig: Enable Hotspot 2.0 (wpa_supplicant)
ec52faa2b defconfig: Enable RSN on IBSS networks (wpa_supplicant)
67d99d2e0 defconfig: Remove obsolete notes about OpenSSL requirements for EAP-FAST
eafc5fec2 defconfig: Enable a handful of EAP methods (wpa_supplicant)
f64050da0 defconfig: Enable logging to file and syslog (wpa_supplicant)
ae5240db8 defconfig: Enable simple bgscan module (wpa_supplicant)
2d6d47219 defconfig: Enable AP (wpa_supplicant)
f87450a73 defconfig: Enable WPS (wpa_supplicant)
d989e67d0 defconfig: Fix typos in Wi-Fi Display description
c4eafad09 defconfig: Enable P2P and Wi-Fi Display (wpa_supplicant)
bf46c6fca defconfig: Add SAE (wpa_supplicant)
ca098ee45 defconfig: Add DPP (wpa_supplicant)
2f7bc0681 UBSan: Avoid a warning on unsigned integer overflow
bb05d0360 Fix a regression from VLAN assignment using WPA/WPA2 passphrase/PSK
429ed54a3 UBSan: Avoid a warning on signed left shift
b3957edbe UBSan: Split loop index decrementation into a separate step
5ac13f6d0 atheros: Avoid clang compiler warning on address of array check
aaa6b1498 Avoid compiler warning about potentially unaligned pointer value
cce974d36 UBSan: Define FST LLT macros without integer overflow
9140caf5f UBSan: Avoid integer overflow in a loop index counter
8fc22fdde UBSan: Avoid NULL pointer dereferences on an error path
43216777e UBSan: Avoid unsigned integer overflow in base64 encoding
fed7d8fcb UBSan: Avoid unsigned integer overflow in utf8_{,un}escape()
cc4cdefc7 UBSan: Avoid unnecessary warning
a9377bc38 UBSan: Avoid memcpy(ptr, NULL, 0)
5a23c2528 UBSan: Avoid an unsigned integer overflow warning
abde4eba4 UBSan: Pack MACsec peer id structure
c4fccfc7a UBSan: Avoid memcmp(ptr, NULL, 0)
1b85cad29 UBSan: Use typecast to avoid unsigned integer overflow
e3b5bd81b UBSan: Fix RRM beacon processing attempt without scan_info
01d01a311 UBSan: Avoid size_t variable overflow in control interface
ec2e7c4cf UBSan: Avoid unsigned integer overflow is throughput estimation
3b6b3ae58 Modify dl_list_for_each() to not use unaligned access with WPA_TRACE
1415d4b82 Multi-AP: Avoid memcpy(ptr, NULL, 0) in WPS Registrar initialization
2c129a1b7 Fix cipher suite selector default value in RSNE for DMG
239794018 Add new QCA vendor attributes for coex configuration
d939a8cb4 Add a vendor attribute for specifying ethernet protocol type
8682f384c hostapd: Add README-MULTI-AP
66819b07b hostapd: Support Multi-AP backhaul STA onboarding with WPS
83ebf5586 wpa_supplicant: Support Multi-AP backhaul STA onboarding with WPS
56a2d788f WPS: Add multi_ap_subelem to wps_build_wfa_ext()
bfcdac1c8 Multi-AP: Don't reject backhaul STA on fronthaul BSS
7ad7aa0e1 HS 2.0: Make hs20-osu-client SP and <FQDN> directories group writable
0f9632ceb mesh: More consistent checking of wpa_s->ifmsh in completion handler
2fae58fdc Fix wpa_psk_file parser error case handling
b0e91e387 SAE: VLAN assignment based on SAE Password Identifier
947b5a153 P2P: Stop listen state if Action frame TX is needed on another channel
b3e8ca65a P2P: Fix a typo in a debug message
464064c7e hostapd: Document openssl_ecdh_curves configuration parameter
31ee2992c Add QCA vendor subcmd/attribute to check wlan firmware state
3f8ceff54 Indicate wifi_generation in wpa_supplicant STATUS output
ccaf77476 Add HE Capabilities into ieee802_11_parse_elems()
5d68c0acd nl80211: (Re)Association Request frame IEs from association event
dbfa691df VLAN assignment based on used WPA/WPA2 passphrase/PSK
dd2aedeb5 HS 2.0 server: Add X-WFA-Hotspot20-Filtering header line to T&C

Change-Id: I4efde950845354673694f025ca07c3dddb6039e9
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 9611dc0..e640e99 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -200,8 +200,8 @@
 	conf->num_bss = 1;
 
 	conf->beacon_int = 100;
-	conf->rts_threshold = -1; /* use driver default: 2347 */
-	conf->fragm_threshold = -1; /* user driver default: 2346 */
+	conf->rts_threshold = -2; /* use driver default: 2347 */
+	conf->fragm_threshold = -2; /* user driver default: 2346 */
 	/* Set to invalid value means do not add Power Constraint IE */
 	conf->local_pwr_constraint = -1;
 
@@ -279,6 +279,8 @@
 	}
 
 	while (fgets(buf, sizeof(buf), f)) {
+		int vlan_id = 0;
+
 		line++;
 
 		if (buf[0] == '#')
@@ -301,11 +303,15 @@
 				break;
 			context2 = NULL;
 			name = str_token(token, "=", &context2);
+			if (!name)
+				break;
 			value = str_token(token, "", &context2);
 			if (!value)
 				value = "";
 			if (!os_strcmp(name, "keyid")) {
 				keyid = value;
+			} else if (!os_strcmp(name, "vlanid")) {
+				vlan_id = atoi(value);
 			} else {
 				wpa_printf(MSG_ERROR,
 					   "Unrecognized '%s=%s' on line %d in '%s'",
@@ -333,6 +339,7 @@
 			ret = -1;
 			break;
 		}
+		psk->vlan_id = vlan_id;
 		if (is_zero_ether_addr(addr))
 			psk->group = 1;
 		else
@@ -588,6 +595,7 @@
 	os_free(conf->server_cert);
 	os_free(conf->private_key);
 	os_free(conf->private_key_passwd);
+	os_free(conf->check_cert_subject);
 	os_free(conf->ocsp_stapling_response);
 	os_free(conf->ocsp_stapling_response_multi);
 	os_free(conf->dh_file);
@@ -637,6 +645,8 @@
 	os_free(conf->ap_pin);
 	os_free(conf->extra_cred);
 	os_free(conf->ap_settings);
+	hostapd_config_clear_wpa_psk(&conf->multi_ap_backhaul_ssid.wpa_psk);
+	str_clear_free(conf->multi_ap_backhaul_ssid.wpa_passphrase);
 	os_free(conf->upnp_iface);
 	os_free(conf->friendly_name);
 	os_free(conf->manufacturer_url);
@@ -858,11 +868,14 @@
 
 const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 			   const u8 *addr, const u8 *p2p_dev_addr,
-			   const u8 *prev_psk)
+			   const u8 *prev_psk, int *vlan_id)
 {
 	struct hostapd_wpa_psk *psk;
 	int next_ok = prev_psk == NULL;
 
+	if (vlan_id)
+		*vlan_id = 0;
+
 	if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
 		wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
 			   " p2p_dev_addr=" MACSTR " prev_psk=%p",
@@ -880,8 +893,11 @@
 		     (addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
 		     (!addr && p2p_dev_addr &&
 		      os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
-		      0)))
+		      0))) {
+			if (vlan_id)
+				*vlan_id = psk->vlan_id;
 			return psk->psk;
+		}
 
 		if (psk->psk == prev_psk)
 			next_ok = 1;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 6963df4..509677a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -152,6 +152,7 @@
 	u8 psk[PMK_LEN];
 	u8 addr[ETH_ALEN];
 	u8 p2p_dev_addr[ETH_ALEN];
+	int vlan_id;
 };
 
 struct hostapd_eap_user {
@@ -248,6 +249,7 @@
 	char *password;
 	char *identifier;
 	u8 peer_addr[ETH_ALEN];
+	int vlan_id;
 };
 
 /**
@@ -390,6 +392,7 @@
 	char *server_cert;
 	char *private_key;
 	char *private_key_passwd;
+	char *check_cert_subject;
 	int check_crl;
 	int check_crl_strict;
 	unsigned int crl_reload_interval;
@@ -462,9 +465,11 @@
 	u8 *extra_cred;
 	size_t extra_cred_len;
 	int wps_cred_processing;
+	int wps_cred_add_sae;
 	int force_per_enrollee_psk;
 	u8 *ap_settings;
 	size_t ap_settings_len;
+	struct hostapd_ssid multi_ap_backhaul_ssid;
 	char *upnp_iface;
 	char *friendly_name;
 	char *manufacturer_url;
@@ -872,7 +877,7 @@
 int hostapd_rate_found(int *list, int rate);
 const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 			   const u8 *addr, const u8 *p2p_dev_addr,
-			   const u8 *prev_psk);
+			   const u8 *prev_psk, int *vlan_id);
 int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
 int hostapd_vlan_valid(struct hostapd_vlan *vlan,
 		       struct vlan_description *vlan_desc);
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 1bb3d9f..eced6c7 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -233,6 +233,7 @@
 			hapd->conf->ocsp_stapling_response;
 		params.ocsp_stapling_response_multi =
 			hapd->conf->ocsp_stapling_response_multi;
+		params.check_cert_subject = hapd->conf->check_cert_subject;
 
 		if (tls_global_set_params(hapd->ssl_ctx, &params)) {
 			wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 3128aed..c693715 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -451,11 +451,11 @@
 	if (stype == WLAN_FC_STYPE_DEAUTH) {
 		mgmt->u.deauth.reason_code =
 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-		pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+		pos = mgmt->u.deauth.variable;
 	} else {
 		mgmt->u.disassoc.reason_code =
 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-		pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+		pos = mgmt->u.disassoc.variable;
 	}
 
 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 149f389..75edbc9 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -28,34 +28,6 @@
 static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 
-static struct dpp_configurator *
-hostapd_dpp_configurator_get_id(struct hostapd_data *hapd, unsigned int id)
-{
-	struct dpp_configurator *conf;
-
-	dl_list_for_each(conf, &hapd->iface->interfaces->dpp_configurator,
-			 struct dpp_configurator, list) {
-		if (conf->id == id)
-			return conf;
-	}
-	return NULL;
-}
-
-
-static unsigned int hapd_dpp_next_id(struct hostapd_data *hapd)
-{
-	struct dpp_bootstrap_info *bi;
-	unsigned int max_id = 0;
-
-	dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
-			 struct dpp_bootstrap_info, list) {
-		if (bi->id > max_id)
-			max_id = bi->id;
-	}
-	return max_id + 1;
-}
-
-
 /**
  * hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
  * @hapd: Pointer to hostapd_data
@@ -67,13 +39,10 @@
 	struct dpp_bootstrap_info *bi;
 	struct dpp_authentication *auth = hapd->dpp_auth;
 
-	bi = dpp_parse_qr_code(cmd);
+	bi = dpp_add_qr_code(hapd->iface->interfaces->dpp, cmd);
 	if (!bi)
 		return -1;
 
-	bi->id = hapd_dpp_next_id(hapd);
-	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,
@@ -92,195 +61,6 @@
 }
 
 
-static char * get_param(const char *cmd, const char *param)
-{
-	const char *pos, *end;
-	char *val;
-	size_t len;
-
-	pos = os_strstr(cmd, param);
-	if (!pos)
-		return NULL;
-
-	pos += os_strlen(param);
-	end = os_strchr(pos, ' ');
-	if (end)
-		len = end - pos;
-	else
-		len = os_strlen(pos);
-	val = os_malloc(len + 1);
-	if (!val)
-		return NULL;
-	os_memcpy(val, pos, len);
-	val[len] = '\0';
-	return val;
-}
-
-
-int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd)
-{
-	char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
-	char *key = NULL;
-	u8 *privkey = NULL;
-	size_t privkey_len = 0;
-	size_t len;
-	int ret = -1;
-	struct dpp_bootstrap_info *bi;
-
-	bi = os_zalloc(sizeof(*bi));
-	if (!bi)
-		goto fail;
-
-	if (os_strstr(cmd, "type=qrcode"))
-		bi->type = DPP_BOOTSTRAP_QR_CODE;
-	else if (os_strstr(cmd, "type=pkex"))
-		bi->type = DPP_BOOTSTRAP_PKEX;
-	else
-		goto fail;
-
-	chan = get_param(cmd, " chan=");
-	mac = get_param(cmd, " mac=");
-	info = get_param(cmd, " info=");
-	curve = get_param(cmd, " curve=");
-	key = get_param(cmd, " key=");
-
-	if (key) {
-		privkey_len = os_strlen(key) / 2;
-		privkey = os_malloc(privkey_len);
-		if (!privkey ||
-		    hexstr2bin(key, privkey, privkey_len) < 0)
-			goto fail;
-	}
-
-	pk = dpp_keygen(bi, curve, privkey, privkey_len);
-	if (!pk)
-		goto fail;
-
-	len = 4; /* "DPP:" */
-	if (chan) {
-		if (dpp_parse_uri_chan_list(bi, chan) < 0)
-			goto fail;
-		len += 3 + os_strlen(chan); /* C:...; */
-	}
-	if (mac) {
-		if (dpp_parse_uri_mac(bi, mac) < 0)
-			goto fail;
-		len += 3 + os_strlen(mac); /* M:...; */
-	}
-	if (info) {
-		if (dpp_parse_uri_info(bi, info) < 0)
-			goto fail;
-		len += 3 + os_strlen(info); /* I:...; */
-	}
-	len += 4 + os_strlen(pk);
-	bi->uri = os_malloc(len + 1);
-	if (!bi->uri)
-		goto fail;
-	os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
-		    chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
-		    mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
-		    info ? "I:" : "", info ? info : "", info ? ";" : "",
-		    pk);
-	bi->id = hapd_dpp_next_id(hapd);
-	dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
-	ret = bi->id;
-	bi = NULL;
-fail:
-	os_free(curve);
-	os_free(pk);
-	os_free(chan);
-	os_free(mac);
-	os_free(info);
-	str_clear_free(key);
-	bin_clear_free(privkey, privkey_len);
-	dpp_bootstrap_info_free(bi);
-	return ret;
-}
-
-
-static struct dpp_bootstrap_info *
-dpp_bootstrap_get_id(struct hostapd_data *hapd, unsigned int id)
-{
-	struct dpp_bootstrap_info *bi;
-
-	dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
-			 struct dpp_bootstrap_info, list) {
-		if (bi->id == id)
-			return bi;
-	}
-	return NULL;
-}
-
-
-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, &ifaces->dpp_bootstrap,
-			      struct dpp_bootstrap_info, list) {
-		if (id && bi->id != id)
-			continue;
-		found = 1;
-		dl_list_del(&bi->list);
-		dpp_bootstrap_info_free(bi);
-	}
-
-	if (id == 0)
-		return 0; /* flush succeeds regardless of entries found */
-	return found ? 0 : -1;
-}
-
-
-int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id)
-{
-	unsigned int id_val;
-
-	if (os_strcmp(id, "*") == 0) {
-		id_val = 0;
-	} else {
-		id_val = atoi(id);
-		if (id_val == 0)
-			return -1;
-	}
-
-	return dpp_bootstrap_del(hapd->iface->interfaces, id_val);
-}
-
-
-const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
-					   unsigned int id)
-{
-	struct dpp_bootstrap_info *bi;
-
-	bi = dpp_bootstrap_get_id(hapd, id);
-	if (!bi)
-		return NULL;
-	return bi->uri;
-}
-
-
-int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
-			       char *reply, int reply_size)
-{
-	struct dpp_bootstrap_info *bi;
-
-	bi = dpp_bootstrap_get_id(hapd, id);
-	if (!bi)
-		return -1;
-	return os_snprintf(reply, reply_size, "type=%s\n"
-			   "mac_addr=" MACSTR "\n"
-			   "info=%s\n"
-			   "num_freq=%u\n"
-			   "curve=%s\n",
-			   dpp_bootstrap_type_txt(bi->type),
-			   MAC2STR(bi->mac_addr),
-			   bi->info ? bi->info : "",
-			   bi->num_freq,
-			   bi->curve->name);
-}
-
-
 static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
 						void *timeout_ctx)
 {
@@ -354,6 +134,16 @@
 		return;
 	}
 
+#ifdef CONFIG_DPP2
+	if (auth->connect_on_tx_status) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Complete exchange on configuration result");
+		dpp_auth_deinit(hapd->dpp_auth);
+		hapd->dpp_auth = NULL;
+		return;
+	}
+#endif /* CONFIG_DPP2 */
+
 	if (hapd->dpp_auth->remove_on_tx_status) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Terminate authentication exchange due to an earlier error");
@@ -505,178 +295,6 @@
 }
 
 
-static int hostapd_dpp_set_configurator(struct hostapd_data *hapd,
-					struct dpp_authentication *auth,
-					const char *cmd)
-{
-	const char *pos, *end;
-	struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
-	struct dpp_configurator *conf = NULL;
-	u8 ssid[32] = { "test" };
-	size_t ssid_len = 4;
-	char pass[64] = { };
-	size_t pass_len = 0;
-	u8 psk[PMK_LEN];
-	int psk_set = 0;
-	char *group_id = NULL;
-
-	if (!cmd)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
-	pos = os_strstr(cmd, " ssid=");
-	if (pos) {
-		pos += 6;
-		end = os_strchr(pos, ' ');
-		ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
-		ssid_len /= 2;
-		if (ssid_len > sizeof(ssid) ||
-		    hexstr2bin(pos, ssid, ssid_len) < 0)
-			goto fail;
-	}
-
-	pos = os_strstr(cmd, " pass=");
-	if (pos) {
-		pos += 6;
-		end = os_strchr(pos, ' ');
-		pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
-		pass_len /= 2;
-		if (pass_len > sizeof(pass) - 1 || pass_len < 8 ||
-		    hexstr2bin(pos, (u8 *) pass, pass_len) < 0)
-			goto fail;
-	}
-
-	pos = os_strstr(cmd, " psk=");
-	if (pos) {
-		pos += 5;
-		if (hexstr2bin(pos, psk, PMK_LEN) < 0)
-			goto fail;
-		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") ||
-		    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 {
-				conf_sta->passphrase = os_strdup(pass);
-				if (!conf_sta->passphrase)
-					goto fail;
-			}
-		} else if (os_strstr(cmd, " conf=sta-dpp")) {
-			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-")) {
-		conf_ap = os_zalloc(sizeof(struct dpp_configuration));
-		if (!conf_ap)
-			goto fail;
-		os_memcpy(conf_ap->ssid, ssid, ssid_len);
-		conf_ap->ssid_len = ssid_len;
-		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 if (pass_len > 0) {
-				conf_ap->passphrase = os_strdup(pass);
-				if (!conf_ap->passphrase)
-					goto fail;
-			} else {
-				goto fail;
-			}
-		} else if (os_strstr(cmd, " conf=ap-dpp")) {
-			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=");
-	if (pos) {
-		long int val;
-
-		pos += 8;
-		val = strtol(pos, NULL, 0);
-		if (val <= 0)
-			goto fail;
-		if (conf_sta)
-			conf_sta->netaccesskey_expiry = val;
-		if (conf_ap)
-			conf_ap->netaccesskey_expiry = val;
-	}
-
-	pos = os_strstr(cmd, " configurator=");
-	if (pos) {
-		auth->configurator = 1;
-		pos += 14;
-		conf = hostapd_dpp_configurator_get_id(hapd, atoi(pos));
-		if (!conf) {
-			wpa_printf(MSG_INFO,
-				   "DPP: Could not find the specified configurator");
-			goto fail;
-		}
-	}
-	auth->conf_sta = conf_sta;
-	auth->conf_ap = conf_ap;
-	auth->conf = conf;
-	os_free(group_id);
-	return 0;
-
-fail:
-	wpa_msg(hapd->msg_ctx, MSG_INFO,
-		"DPP: Failed to set configurator parameters");
-	dpp_configuration_free(conf_sta);
-	dpp_configuration_free(conf_ap);
-	os_free(group_id);
-	return -1;
-}
-
-
 static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct hostapd_data *hapd = eloop_ctx;
@@ -786,7 +404,7 @@
 	if (!pos)
 		return -1;
 	pos += 6;
-	peer_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
+	peer_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
 	if (!peer_bi) {
 		wpa_printf(MSG_INFO,
 			   "DPP: Could not find bootstrapping info for the identified peer");
@@ -796,7 +414,8 @@
 	pos = os_strstr(cmd, " own=");
 	if (pos) {
 		pos += 5;
-		own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
+		own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
+					      atoi(pos));
 		if (!own_bi) {
 			wpa_printf(MSG_INFO,
 				   "DPP: Could not find bootstrapping info for the identified local entry");
@@ -846,7 +465,8 @@
 	if (!hapd->dpp_auth)
 		goto fail;
 	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
-	if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd) < 0) {
+	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+				 hapd->dpp_auth, cmd) < 0) {
 		dpp_auth_deinit(hapd->dpp_auth);
 		hapd->dpp_auth = NULL;
 		goto fail;
@@ -905,7 +525,10 @@
 {
 	const u8 *r_bootstrap, *i_bootstrap;
 	u16 r_bootstrap_len, i_bootstrap_len;
-	struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
+	struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+	if (!hapd->iface->interfaces->dpp)
+		return;
 
 	wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
 		   MAC2STR(src));
@@ -932,28 +555,8 @@
 
 	/* Try to find own and peer bootstrapping key matches based on the
 	 * received hash values */
-	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) {
-			wpa_printf(MSG_DEBUG,
-				   "DPP: Found matching own bootstrapping information");
-			own_bi = bi;
-		}
-
-		if (!peer_bi && !bi->own &&
-		    os_memcmp(bi->pubkey_hash, i_bootstrap,
-			      SHA256_MAC_LEN) == 0) {
-			wpa_printf(MSG_DEBUG,
-				   "DPP: Found matching peer bootstrapping information");
-			peer_bi = bi;
-		}
-
-		if (own_bi && peer_bi)
-			break;
-	}
-
+	dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
+				r_bootstrap, &own_bi, &peer_bi);
 	if (!own_bi) {
 		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
 			"No matching own bootstrapping key found - ignore message");
@@ -975,8 +578,9 @@
 		return;
 	}
 	hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
-	if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth,
-					 hapd->dpp_configurator_params) < 0) {
+	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+				 hapd->dpp_auth,
+				 hapd->dpp_configurator_params) < 0) {
 		dpp_auth_deinit(hapd->dpp_auth);
 		hapd->dpp_auth = NULL;
 		return;
@@ -1072,6 +676,7 @@
 	struct hostapd_data *hapd = ctx;
 	const u8 *pos;
 	struct dpp_authentication *auth = hapd->dpp_auth;
+	enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
 
 	if (!auth || !auth->auth_success) {
 		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
@@ -1107,12 +712,41 @@
 	}
 
 	hostapd_dpp_handle_config_obj(hapd, auth);
-	dpp_auth_deinit(hapd->dpp_auth);
-	hapd->dpp_auth = NULL;
-	return;
-
+	status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_REJECT_CONFIG) {
+		wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
+		status = DPP_STATUS_CONFIG_REJECTED;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 fail:
-	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+	if (status != DPP_STATUS_OK)
+		wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+#ifdef CONFIG_DPP2
+	if (auth->peer_version >= 2 &&
+	    auth->conf_resp_status == DPP_STATUS_OK) {
+		struct wpabuf *msg;
+
+		wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+		msg = dpp_build_conf_result(auth, status);
+		if (!msg)
+			goto fail2;
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+			MAC2STR(addr), auth->curr_freq,
+			DPP_PA_CONFIGURATION_RESULT);
+		hostapd_drv_send_action(hapd, auth->curr_freq, 0,
+					addr, wpabuf_head(msg),
+					wpabuf_len(msg));
+		wpabuf_free(msg);
+
+		/* This exchange will be terminated in the TX status handler */
+		auth->connect_on_tx_status = 1;
+		return;
+	}
+fail2:
+#endif /* CONFIG_DPP2 */
 	dpp_auth_deinit(hapd->dpp_auth);
 	hapd->dpp_auth = NULL;
 }
@@ -1121,7 +755,7 @@
 static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
 {
 	struct dpp_authentication *auth = hapd->dpp_auth;
-	struct wpabuf *buf, *conf_req;
+	struct wpabuf *buf;
 	char json[100];
 	int res;
 	int netrole_ap = 1;
@@ -1133,34 +767,13 @@
 		    netrole_ap ? "ap" : "sta");
 	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
 
-	conf_req = dpp_build_conf_req(auth, json);
-	if (!conf_req) {
+	buf = dpp_build_conf_req(auth, json);
+	if (!buf) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: No configuration request data available");
 		return;
 	}
 
-	buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
-	if (!buf) {
-		wpabuf_free(conf_req);
-		return;
-	}
-
-	/* Advertisement Protocol IE */
-	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-	wpabuf_put_u8(buf, 8); /* Length */
-	wpabuf_put_u8(buf, 0x7f);
-	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
-	wpabuf_put_u8(buf, 5);
-	wpabuf_put_be24(buf, OUI_WFA);
-	wpabuf_put_u8(buf, DPP_OUI_TYPE);
-	wpabuf_put_u8(buf, 0x01);
-
-	/* GAS Query */
-	wpabuf_put_le16(buf, wpabuf_len(conf_req));
-	wpabuf_put_buf(buf, conf_req);
-	wpabuf_free(conf_req);
-
 	wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
 		   MAC2STR(auth->peer_mac_addr), auth->curr_freq);
 
@@ -1281,6 +894,63 @@
 }
 
 
+#ifdef CONFIG_DPP2
+
+static void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
+						   void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct dpp_authentication *auth = hapd->dpp_auth;
+
+	if (!auth || !auth->waiting_conf_result)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Timeout while waiting for Configuration Result");
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+	dpp_auth_deinit(auth);
+	hapd->dpp_auth = NULL;
+}
+
+
+static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
+				       const u8 *hdr, const u8 *buf, size_t len)
+{
+	struct dpp_authentication *auth = hapd->dpp_auth;
+	enum dpp_status_error status;
+
+	wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
+		   MAC2STR(src));
+
+	if (!auth || !auth->waiting_conf_result) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No DPP Configuration waiting for result - drop");
+		return;
+	}
+
+	if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+			   MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+		return;
+	}
+
+	status = dpp_conf_result_rx(auth, hdr, buf, len);
+
+	hostapd_drv_send_action_cancel_wait(hapd);
+	hostapd_dpp_listen_stop(hapd);
+	if (status == DPP_STATUS_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(auth);
+	hapd->dpp_auth = NULL;
+	eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
+			     NULL);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
 static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
 					    const u8 *src, unsigned int freq,
 					    u8 trans_id,
@@ -1596,24 +1266,10 @@
 				wpabuf_head(msg), wpabuf_len(msg));
 	wpabuf_free(msg);
 
-	bi = os_zalloc(sizeof(*bi));
+	bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
 	if (!bi)
 		return;
-	bi->id = hapd_dpp_next_id(hapd);
-	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);
 	hapd->dpp_pkex = NULL;
-	if (dpp_bootstrap_key_hash(bi) < 0) {
-		dpp_bootstrap_info_free(bi);
-		return;
-	}
-	dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
 }
 
 
@@ -1623,7 +1279,7 @@
 				       unsigned int freq)
 {
 	int res;
-	struct dpp_bootstrap_info *bi, *own_bi;
+	struct dpp_bootstrap_info *bi;
 	struct dpp_pkex *pkex = hapd->dpp_pkex;
 	char cmd[500];
 
@@ -1641,26 +1297,10 @@
 		return;
 	}
 
-	own_bi = pkex->own_bi;
-
-	bi = os_zalloc(sizeof(*bi));
+	bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
 	if (!bi)
 		return;
-	bi->id = hapd_dpp_next_id(hapd);
-	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);
 	hapd->dpp_pkex = NULL;
-	if (dpp_bootstrap_key_hash(bi) < 0) {
-		dpp_bootstrap_info_free(bi);
-		return;
-	}
-	dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
 
 	os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
 		    bi->id,
@@ -1744,6 +1384,11 @@
 		hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
 						       freq);
 		break;
+#ifdef CONFIG_DPP2
+	case DPP_PA_CONFIGURATION_RESULT:
+		hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
+		break;
+#endif /* CONFIG_DPP2 */
 	default:
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Ignored unsupported frame subtype %d", type);
@@ -1790,11 +1435,28 @@
 
 void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
 {
-	if (!hapd->dpp_auth)
+	struct dpp_authentication *auth = hapd->dpp_auth;
+
+	if (!auth)
 		return;
 
+	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
+		   ok);
 	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
 	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+#ifdef CONFIG_DPP2
+	if (ok && auth->peer_version >= 2 &&
+	    auth->conf_resp_status == DPP_STATUS_OK) {
+		wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+		auth->waiting_conf_result = 1;
+		eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
+				     hapd, NULL);
+		eloop_register_timeout(2, 0,
+				       hostapd_dpp_config_result_wait_timeout,
+				       hapd, NULL);
+		return;
+	}
+#endif /* CONFIG_DPP2 */
 	hostapd_drv_send_action_cancel_wait(hapd);
 
 	if (ok)
@@ -1806,93 +1468,6 @@
 }
 
 
-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->iface->interfaces->dpp_configurator,
-			 struct dpp_configurator, list) {
-		if (conf->id > max_id)
-			max_id = conf->id;
-	}
-	return max_id + 1;
-}
-
-
-int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd)
-{
-	char *curve = NULL;
-	char *key = NULL;
-	u8 *privkey = NULL;
-	size_t privkey_len = 0;
-	int ret = -1;
-	struct dpp_configurator *conf = NULL;
-
-	curve = get_param(cmd, " curve=");
-	key = get_param(cmd, " key=");
-
-	if (key) {
-		privkey_len = os_strlen(key) / 2;
-		privkey = os_malloc(privkey_len);
-		if (!privkey ||
-		    hexstr2bin(key, privkey, privkey_len) < 0)
-			goto fail;
-	}
-
-	conf = dpp_keygen_configurator(curve, privkey, privkey_len);
-	if (!conf)
-		goto fail;
-
-	conf->id = hostapd_dpp_next_configurator_id(hapd);
-	dl_list_add(&hapd->iface->interfaces->dpp_configurator, &conf->list);
-	ret = conf->id;
-	conf = NULL;
-fail:
-	os_free(curve);
-	str_clear_free(key);
-	bin_clear_free(privkey, privkey_len);
-	dpp_configurator_free(conf);
-	return ret;
-}
-
-
-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, &ifaces->dpp_configurator,
-			      struct dpp_configurator, list) {
-		if (id && conf->id != id)
-			continue;
-		found = 1;
-		dl_list_del(&conf->list);
-		dpp_configurator_free(conf);
-	}
-
-	if (id == 0)
-		return 0; /* flush succeeds regardless of entries found */
-	return found ? 0 : -1;
-}
-
-
-int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id)
-{
-	unsigned int id_val;
-
-	if (os_strcmp(id, "*") == 0) {
-		id_val = 0;
-	} else {
-		id_val = atoi(id);
-		if (id_val == 0)
-			return -1;
-	}
-
-	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;
@@ -1905,7 +1480,8 @@
 
 	curve = get_param(cmd, " curve=");
 	hostapd_dpp_set_testing_options(hapd, auth);
-	if (hostapd_dpp_set_configurator(hapd, auth, cmd) == 0 &&
+	if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+				 auth, cmd) == 0 &&
 	    dpp_configurator_own_config(auth, curve, 1) == 0) {
 		hostapd_dpp_handle_config_obj(hapd, auth);
 		ret = 0;
@@ -1918,19 +1494,6 @@
 }
 
 
-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);
-}
-
-
 int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
 {
 	struct dpp_bootstrap_info *own_bi;
@@ -1940,7 +1503,7 @@
 	if (!pos)
 		return -1;
 	pos += 5;
-	own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
+	own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
 	if (!own_bi) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Identified bootstrap info not found");
@@ -2070,6 +1633,10 @@
 	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);
+#ifdef CONFIG_DPP2
+	eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
+			     NULL);
+#endif /* CONFIG_DPP2 */
 	dpp_auth_deinit(hapd->dpp_auth);
 	hapd->dpp_auth = NULL;
 	hostapd_dpp_pkex_remove(hapd, "*");
@@ -2077,20 +1644,3 @@
 	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 3ef7c14..449ca16 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -10,12 +10,6 @@
 #define DPP_HOSTAPD_H
 
 int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
-int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd);
-int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id);
-const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
-					   unsigned int id);
-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);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 54be3b5..8ddf754 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -15,6 +15,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "common/dpp.h"
 #include "crypto/random.h"
 #include "p2p/p2p.h"
 #include "wps/wps.h"
@@ -305,6 +306,7 @@
 			return -1;
 		}
 		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  hapd->iface->freq,
 					  ie, ielen,
 					  elems.mdie, elems.mdie_len,
 					  elems.owe_dh, elems.owe_dh_len);
@@ -564,6 +566,38 @@
 	}
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+		dpp_pfs_free(sta->dpp_pfs);
+		sta->dpp_pfs = NULL;
+
+		if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+		    hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
+		    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
+		    elems.owe_dh) {
+			sta->dpp_pfs = dpp_pfs_init(
+				wpabuf_head(hapd->conf->dpp_netaccesskey),
+				wpabuf_len(hapd->conf->dpp_netaccesskey));
+			if (!sta->dpp_pfs) {
+				wpa_printf(MSG_DEBUG,
+					   "DPP: Could not initialize PFS");
+				/* Try to continue without PFS */
+				goto pfs_fail;
+			}
+
+			if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
+					    elems.owe_dh_len) < 0) {
+				dpp_pfs_free(sta->dpp_pfs);
+				sta->dpp_pfs = NULL;
+				reason = WLAN_REASON_UNSPECIFIED;
+				goto fail;
+			}
+		}
+
+		wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
+				   sta->dpp_pfs->secret : NULL);
+	pfs_fail:
+#endif /* CONFIG_DPP2 */
+
 #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
 	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
 
@@ -1072,6 +1106,7 @@
 }
 
 
+#ifndef NEED_AP_MLME
 static void hostapd_action_rx(struct hostapd_data *hapd,
 			      struct rx_mgmt *drv_mgmt)
 {
@@ -1084,7 +1119,7 @@
 	if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
 		return;
 
-	plen = drv_mgmt->frame_len - IEEE80211_HDRLEN - 1;
+	plen = drv_mgmt->frame_len - IEEE80211_HDRLEN;
 
 	mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
 	fc = le_to_host16(mgmt->frame_control);
@@ -1104,19 +1139,20 @@
 	}
 #ifdef CONFIG_IEEE80211R_AP
 	if (mgmt->u.action.category == WLAN_ACTION_FT) {
-		const u8 *payload = drv_mgmt->frame + 24 + 1;
-
-		wpa_ft_action_rx(sta->wpa_sm, payload, plen);
+		wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen);
+		return;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_IEEE80211W
-	if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
+	if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
 		ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
+		return;
 	}
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WNM_AP
 	if (mgmt->u.action.category == WLAN_ACTION_WNM) {
 		ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
+		return;
 	}
 #endif /* CONFIG_WNM_AP */
 #ifdef CONFIG_FST
@@ -1126,7 +1162,7 @@
 	}
 #endif /* CONFIG_FST */
 #ifdef CONFIG_DPP
-	if (plen >= 1 + 4 &&
+	if (plen >= 2 + 4 &&
 	    mgmt->u.action.u.vs_public_action.action ==
 	    WLAN_PA_VENDOR_SPECIFIC &&
 	    WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
@@ -1143,6 +1179,7 @@
 	}
 #endif /* CONFIG_DPP */
 }
+#endif /* NEED_AP_MLME */
 
 
 #ifdef NEED_AP_MLME
@@ -1604,10 +1641,10 @@
 		if (!data->rx_mgmt.frame)
 			break;
 #ifdef NEED_AP_MLME
-		if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
-			break;
-#endif /* NEED_AP_MLME */
+		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
+#else /* NEED_AP_MLME */
 		hostapd_action_rx(hapd, &data->rx_mgmt);
+#endif /* NEED_AP_MLME */
 		break;
 	case EVENT_RX_PROBE_REQ:
 		if (data->rx_probe_req.sa == NULL ||
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 342585f..77742f4 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -348,7 +348,7 @@
 
 	if (!hapd->started) {
 		wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
-			   __func__, hapd->conf->iface);
+			   __func__, hapd->conf ? hapd->conf->iface : "N/A");
 		return;
 	}
 	hapd->started = 0;
@@ -417,6 +417,20 @@
 
 	hostapd_clean_rrm(hapd);
 	fils_hlp_deinit(hapd);
+
+#ifdef CONFIG_SAE
+	{
+		struct hostapd_sae_commit_queue *q;
+
+		while ((q = dl_list_first(&hapd->sae_commit_queue,
+					  struct hostapd_sae_commit_queue,
+					  list))) {
+			dl_list_del(&q->list);
+			os_free(q);
+		}
+	}
+	eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
+#endif /* CONFIG_SAE */
 }
 
 
@@ -431,7 +445,7 @@
 static void hostapd_cleanup(struct hostapd_data *hapd)
 {
 	wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
-		   hapd->conf->iface);
+		   hapd->conf ? hapd->conf->iface : "N/A");
 	if (hapd->iface->interfaces &&
 	    hapd->iface->interfaces->ctrl_iface_deinit) {
 		wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
@@ -506,7 +520,7 @@
 
 static void hostapd_clear_wep(struct hostapd_data *hapd)
 {
-	if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
+	if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
 		hostapd_set_privacy(hapd, 0);
 		hostapd_broadcast_wep_clear(hapd);
 	}
@@ -658,8 +672,10 @@
 	for (i = 5; i > 5 - j; i--)
 		mask[i] = 0;
 	j = bits % 8;
-	while (j--)
+	while (j) {
+		j--;
 		mask[i] <<= 1;
+	}
 
 skip_mask_ext:
 	wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
@@ -1867,15 +1883,17 @@
 		}
 	}
 
-	if (hapd->iconf->rts_threshold > -1 &&
-	    hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+	if (hapd->iconf->rts_threshold >= -1 &&
+	    hostapd_set_rts(hapd, hapd->iconf->rts_threshold) &&
+	    hapd->iconf->rts_threshold >= -1) {
 		wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
 			   "kernel driver");
 		goto fail;
 	}
 
-	if (hapd->iconf->fragm_threshold > -1 &&
-	    hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+	if (hapd->iconf->fragm_threshold >= -1 &&
+	    hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) &&
+	    hapd->iconf->fragm_threshold != -1) {
 		wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
 			   "for kernel driver");
 		goto fail;
@@ -1888,11 +1906,14 @@
 		if (j)
 			os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
 		if (hostapd_setup_bss(hapd, j == 0)) {
-			do {
+			for (;;) {
 				hapd = iface->bss[j];
 				hostapd_bss_deinit_no_free(hapd);
 				hostapd_free_hapd_data(hapd);
-			} while (j-- > 0);
+				if (j == 0)
+					break;
+				j--;
+			}
 			goto fail;
 		}
 		if (is_zero_ether_addr(hapd->conf->bssid))
@@ -2145,6 +2166,9 @@
 	dl_list_init(&hapd->l2_queue);
 	dl_list_init(&hapd->l2_oui_queue);
 #endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+	dl_list_init(&hapd->sae_commit_queue);
+#endif /* CONFIG_SAE */
 
 	return hapd;
 }
@@ -2155,7 +2179,7 @@
 	if (!hapd)
 		return;
 	wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
-		   hapd->conf->iface);
+		   hapd->conf ? hapd->conf->iface : "N/A");
 	hostapd_bss_deinit_no_free(hapd);
 	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
 	hostapd_cleanup(hapd);
@@ -2182,7 +2206,7 @@
 	}
 #endif /* CONFIG_FST */
 
-	for (j = iface->num_bss - 1; j >= 0; j--) {
+	for (j = (int) iface->num_bss - 1; j >= 0; j--) {
 		if (!iface->bss)
 			break;
 		hostapd_bss_deinit(iface->bss[j]);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 85e63d3..607bb95 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -66,9 +66,7 @@
 	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 */
+	struct dpp_global *dpp;
 #endif /* CONFIG_DPP */
 };
 
@@ -129,6 +127,13 @@
 	int stationary;
 };
 
+struct hostapd_sae_commit_queue {
+	struct dl_list list;
+	int rssi;
+	size_t len;
+	u8 msg[];
+};
+
 /**
  * struct hostapd_data - hostapd per-BSS data structure
  */
@@ -307,7 +312,10 @@
 	/** Key used for generating SAE anti-clogging tokens */
 	u8 sae_token_key[8];
 	struct os_reltime last_sae_token_key_update;
+	u16 sae_token_idx;
+	u16 sae_pending_token_idx[256];
 	int dot11RSNASAERetransPeriod; /* msec */
+	struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
 #endif /* CONFIG_SAE */
 
 #ifdef CONFIG_TESTING_OPTIONS
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 376bbd8..28aca46 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -21,6 +21,7 @@
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
 #include "common/sae.h"
+#include "common/dpp.h"
 #include "common/ocv.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
@@ -62,6 +63,9 @@
 		       const u8 *msk, size_t msk_len,
 		       int *is_pub);
 #endif /* CONFIG_FILS */
+static void handle_auth(struct hostapd_data *hapd,
+			const struct ieee80211_mgmt *mgmt, size_t len,
+			int rssi, int from_queue);
 
 
 u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
@@ -420,6 +424,15 @@
 		return NULL;
 	}
 
+	if (pw && pw->vlan_id) {
+		if (!sta->sae->tmp) {
+			wpa_printf(MSG_INFO,
+				   "SAE: No temporary data allocated - cannot store VLAN ID");
+			return NULL;
+		}
+		sta->sae->tmp->vlan_id = pw->vlan_id;
+	}
+
 	buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
 			   (rx_id ? 3 + os_strlen(rx_id) : 0));
 	if (buf == NULL)
@@ -509,21 +522,57 @@
 			return 1;
 	}
 
+	/* In addition to already existing open SAE sessions, check whether
+	 * there are enough pending commit messages in the processing queue to
+	 * potentially result in too many open sessions. */
+	if (open + dl_list_len(&hapd->sae_commit_queue) >=
+	    hapd->conf->sae_anti_clogging_threshold)
+		return 1;
+
 	return 0;
 }
 
 
+static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+{
+	u8 hash[SHA256_MAC_LEN];
+
+	hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+		    addr, ETH_ALEN, hash);
+	return hash[0];
+}
+
+
 static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
 			   const u8 *token, size_t token_len)
 {
 	u8 mac[SHA256_MAC_LEN];
+	const u8 *addrs[2];
+	size_t len[2];
+	u16 token_idx;
+	u8 idx;
 
 	if (token_len != SHA256_MAC_LEN)
 		return -1;
-	if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
-			addr, ETH_ALEN, mac) < 0 ||
-	    os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0)
+	idx = sae_token_hash(hapd, addr);
+	token_idx = hapd->sae_pending_token_idx[idx];
+	if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
+		wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
+			   MACSTR " - token_idx 0x%04x, expected 0x%04x",
+			   MAC2STR(addr), WPA_GET_BE16(token), token_idx);
 		return -1;
+	}
+
+	addrs[0] = addr;
+	len[0] = ETH_ALEN;
+	addrs[1] = token;
+	len[1] = 2;
+	if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+			       2, addrs, len, mac) < 0 ||
+	    os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
+		return -1;
+
+	hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
 
 	return 0;
 }
@@ -535,16 +584,25 @@
 	struct wpabuf *buf;
 	u8 *token;
 	struct os_reltime now;
+	u8 idx[2];
+	const u8 *addrs[2];
+	size_t len[2];
+	u8 p_idx;
+	u16 token_idx;
 
 	os_get_reltime(&now);
 	if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
-	    os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
+	    os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
+	    hapd->sae_token_idx == 0xffff) {
 		if (random_get_bytes(hapd->sae_token_key,
 				     sizeof(hapd->sae_token_key)) < 0)
 			return NULL;
 		wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
 			    hapd->sae_token_key, sizeof(hapd->sae_token_key));
 		hapd->last_sae_token_key_update = now;
+		hapd->sae_token_idx = 0;
+		os_memset(hapd->sae_pending_token_idx, 0,
+			  sizeof(hapd->sae_pending_token_idx));
 	}
 
 	buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
@@ -553,9 +611,25 @@
 
 	wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
 
+	p_idx = sae_token_hash(hapd, addr);
+	token_idx = hapd->sae_pending_token_idx[p_idx];
+	if (!token_idx) {
+		hapd->sae_token_idx++;
+		token_idx = hapd->sae_token_idx;
+		hapd->sae_pending_token_idx[p_idx] = token_idx;
+	}
+	WPA_PUT_BE16(idx, token_idx);
 	token = wpabuf_put(buf, SHA256_MAC_LEN);
-	hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
-		    addr, ETH_ALEN, token);
+	addrs[0] = addr;
+	len[0] = ETH_ALEN;
+	addrs[1] = idx;
+	len[1] = sizeof(idx);
+	if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+			       2, addrs, len, token) < 0) {
+		wpabuf_free(buf);
+		return NULL;
+	}
+	WPA_PUT_BE16(token, token_idx);
 
 	return buf;
 }
@@ -629,6 +703,35 @@
 
 void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
+#ifndef CONFIG_NO_VLAN
+	struct vlan_description vlan_desc;
+
+	if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
+		wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
+			   " to VLAN ID %d",
+			   MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
+
+		os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+		vlan_desc.notempty = 1;
+		vlan_desc.untagged = sta->sae->tmp->vlan_id;
+		if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+			wpa_printf(MSG_INFO,
+				   "Invalid VLAN ID %d in sae_password",
+				   sta->sae->tmp->vlan_id);
+			return;
+		}
+
+		if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
+		    ap_sta_bind_vlan(hapd, sta) < 0) {
+			wpa_printf(MSG_INFO,
+				   "Failed to assign VLAN ID %d from sae_password to "
+				   MACSTR, sta->sae->tmp->vlan_id,
+				   MAC2STR(sta->addr));
+			return;
+		}
+	}
+#endif /* CONFIG_NO_VLAN */
+
 	sta->flags |= WLAN_STA_AUTH;
 	sta->auth_alg = WLAN_AUTH_SAE;
 	mlme_authenticate_indication(hapd, sta);
@@ -640,7 +743,7 @@
 
 
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
-		       const u8 *bssid, u8 auth_transaction)
+		       const u8 *bssid, u8 auth_transaction, int allow_reuse)
 {
 	int ret;
 
@@ -653,7 +756,8 @@
 	switch (sta->sae->state) {
 	case SAE_NOTHING:
 		if (auth_transaction == 1) {
-			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+			ret = auth_sae_send_commit(hapd, sta, bssid,
+						   !allow_reuse);
 			if (ret)
 				return ret;
 			sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -742,7 +846,8 @@
 			 * step to get to Accepted without waiting for
 			 * additional events.
 			 */
-			return sae_sm_step(hapd, sta, bssid, auth_transaction);
+			return sae_sm_step(hapd, sta, bssid, auth_transaction,
+					   0);
 		}
 		break;
 	case SAE_CONFIRMED:
@@ -812,18 +917,21 @@
 {
 	struct sae_data *sae = sta->sae;
 	int i, *groups = hapd->conf->sae_groups;
+	int default_groups[] = { 19, 0 };
 
 	if (sae->state != SAE_COMMITTED)
 		return;
 
 	wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
 
-	for (i = 0; groups && groups[i] > 0; i++) {
+	if (!groups)
+		groups = default_groups;
+	for (i = 0; groups[i] > 0; i++) {
 		if (sae->group == groups[i])
 			break;
 	}
 
-	if (!groups || groups[i] <= 0) {
+	if (groups[i] <= 0) {
 		wpa_printf(MSG_DEBUG,
 			   "SAE: Previously selected group not found from the current configuration");
 		return;
@@ -852,11 +960,15 @@
 {
 	int resp = WLAN_STATUS_SUCCESS;
 	struct wpabuf *data = NULL;
+	int *groups = hapd->conf->sae_groups;
+	int default_groups[] = { 19, 0 };
+	const u8 *pos, *end;
+
+	if (!groups)
+		groups = default_groups;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
-		const u8 *pos, *end;
-
 		wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
 		pos = mgmt->u.auth.variable;
 		end = ((const u8 *) mgmt) + len;
@@ -899,8 +1011,10 @@
 	}
 
 	if (auth_transaction == 1) {
-		const u8 *token = NULL, *pos, *end;
+		const u8 *token = NULL;
 		size_t token_len = 0;
+		int allow_reuse = 0;
+
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "start SAE authentication (RX commit, status=%u)",
@@ -917,8 +1031,7 @@
 				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 				goto reply;
 			}
-			resp = sae_group_allowed(sta->sae,
-						 hapd->conf->sae_groups,
+			resp = sae_group_allowed(sta->sae, groups,
 						 WPA_GET_LE16(pos));
 			if (resp != WLAN_STATUS_SUCCESS) {
 				wpa_printf(MSG_ERROR,
@@ -979,15 +1092,28 @@
 			 * 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);
+			pos = mgmt->u.auth.variable;
+			end = ((const u8 *) mgmt) + len;
+			if (end - pos >= (int) sizeof(le16) &&
+			    sae_group_allowed(sta->sae, groups,
+					      WPA_GET_LE16(pos)) ==
+			    WLAN_STATUS_SUCCESS) {
+				/* Do not waste resources deriving the same PWE
+				 * again since the same group is reused. */
+				sae_set_state(sta, SAE_NOTHING,
+					      "Allow previous PWE to be reused");
+				allow_reuse = 1;
+			} else {
+				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,
-					&token_len, hapd->conf->sae_groups);
+					&token_len, groups);
 		if (resp == SAE_SILENTLY_DISCARD) {
 			wpa_printf(MSG_DEBUG,
 				   "SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1017,7 +1143,7 @@
 		if (resp != WLAN_STATUS_SUCCESS)
 			goto reply;
 
-		if (!token && use_sae_anti_clogging(hapd)) {
+		if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
 			wpa_printf(MSG_DEBUG,
 				   "SAE: Request anti-clogging token from "
 				   MACSTR, MAC2STR(sta->addr));
@@ -1030,7 +1156,8 @@
 			goto reply;
 		}
 
-		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+				   allow_reuse);
 	} else if (auth_transaction == 2) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -1071,7 +1198,7 @@
 			}
 			sta->sae->rc = peer_send_confirm;
 		}
-		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0);
 	} else {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
@@ -1084,6 +1211,15 @@
 
 reply:
 	if (resp != WLAN_STATUS_SUCCESS) {
+		pos = mgmt->u.auth.variable;
+		end = ((const u8 *) mgmt) + len;
+
+		/* Copy the Finite Cyclic Group field from the request if we
+		 * rejected it as unsupported group. */
+		if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+		    !data && end - pos >= 2)
+			data = wpabuf_alloc_copy(pos, 2);
+
 		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
 				auth_transaction, resp,
 				data ? wpabuf_head(data) : (u8 *) "",
@@ -1131,6 +1267,105 @@
 	return 0;
 }
 
+
+void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct hostapd_sae_commit_queue *q;
+	unsigned int queue_len;
+
+	q = dl_list_first(&hapd->sae_commit_queue,
+			  struct hostapd_sae_commit_queue, list);
+	if (!q)
+		return;
+	wpa_printf(MSG_DEBUG,
+		   "SAE: Process next available message from queue");
+	dl_list_del(&q->list);
+	handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
+		    q->rssi, 1);
+	os_free(q);
+
+	if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+		return;
+	queue_len = dl_list_len(&hapd->sae_commit_queue);
+	eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+			       hapd, NULL);
+}
+
+
+static void auth_sae_queue(struct hostapd_data *hapd,
+			   const struct ieee80211_mgmt *mgmt, size_t len,
+			   int rssi)
+{
+	struct hostapd_sae_commit_queue *q, *q2;
+	unsigned int queue_len;
+	const struct ieee80211_mgmt *mgmt2;
+
+	queue_len = dl_list_len(&hapd->sae_commit_queue);
+	if (queue_len >= 15) {
+		wpa_printf(MSG_DEBUG,
+			   "SAE: No more room in message queue - drop the new frame from "
+			   MACSTR, MAC2STR(mgmt->sa));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
+		   MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
+		   queue_len);
+	q = os_zalloc(sizeof(*q) + len);
+	if (!q)
+		return;
+	q->rssi = rssi;
+	q->len = len;
+	os_memcpy(q->msg, mgmt, len);
+
+	/* Check whether there is already a queued Authentication frame from the
+	 * same station with the same transaction number and if so, replace that
+	 * queue entry with the new one. This avoids issues with a peer that
+	 * sends multiple times (e.g., due to frequent SAE retries). There is no
+	 * point in us trying to process the old attempts after a new one has
+	 * obsoleted them. */
+	dl_list_for_each(q2, &hapd->sae_commit_queue,
+			 struct hostapd_sae_commit_queue, list) {
+		mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
+		if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
+		    mgmt->u.auth.auth_transaction ==
+		    mgmt2->u.auth.auth_transaction) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: Replace queued message from same STA with same transaction number");
+			dl_list_add(&q2->list, &q->list);
+			dl_list_del(&q2->list);
+			os_free(q2);
+			goto queued;
+		}
+	}
+
+	/* No pending identical entry, so add to the end of the queue */
+	dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
+
+queued:
+	if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+		return;
+	eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+			       hapd, NULL);
+}
+
+
+static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct hostapd_sae_commit_queue *q;
+	const struct ieee80211_mgmt *mgmt;
+
+	dl_list_for_each(q, &hapd->sae_commit_queue,
+			 struct hostapd_sae_commit_queue, list) {
+		mgmt = (const struct ieee80211_mgmt *) q->msg;
+		if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
 #endif /* CONFIG_SAE */
 
 
@@ -1290,6 +1525,7 @@
 	}
 
 	res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+				  hapd->iface->freq,
 				  elems.rsn_ie - 2, elems.rsn_ie_len + 2,
 				  elems.mdie, elems.mdie_len, NULL, 0);
 	resp = wpa_res_to_status_code(res);
@@ -1561,7 +1797,8 @@
 			}
 
 			sta->fils_erp_pmkid_set = 0;
-			if (wpa_auth_pmksa_add2(
+			if (!hapd->conf->disable_pmksa_caching &&
+			    wpa_auth_pmksa_add2(
 				    hapd->wpa_auth, sta->addr,
 				    pmk, pmk_len,
 				    sta->fils_erp_pmkid,
@@ -1761,7 +1998,7 @@
 
 static void handle_auth(struct hostapd_data *hapd,
 			const struct ieee80211_mgmt *mgmt, size_t len,
-			int rssi)
+			int rssi, int from_queue)
 {
 	u16 auth_alg, auth_transaction, status_code;
 	u16 resp = WLAN_STATUS_SUCCESS;
@@ -1808,11 +2045,12 @@
 
 	wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
 		   "auth_transaction=%d status_code=%d wep=%d%s "
-		   "seq_ctrl=0x%x%s",
+		   "seq_ctrl=0x%x%s%s",
 		   MAC2STR(mgmt->sa), auth_alg, auth_transaction,
 		   status_code, !!(fc & WLAN_FC_ISWEP),
 		   challenge ? " challenge" : "",
-		   seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
+		   seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
+		   from_queue ? " (from queue)" : "");
 
 #ifdef CONFIG_NO_RC4
 	if (auth_alg == WLAN_AUTH_SHARED_KEY) {
@@ -1940,6 +2178,22 @@
 	if (res == HOSTAPD_ACL_PENDING)
 		return;
 
+#ifdef CONFIG_SAE
+	if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
+	    (auth_transaction == 1 ||
+	     (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
+		/* Handle SAE Authentication commit message through a queue to
+		 * provide more control for postponing the needed heavy
+		 * processing under a possible DoS attack scenario. In addition,
+		 * queue SAE Authentication confirm message if there happens to
+		 * be a queued commit message from the same peer. This is needed
+		 * to avoid reordering Authentication frames within the same
+		 * SAE exchange. */
+		auth_sae_queue(hapd, mgmt, len, rssi);
+		return;
+	}
+#endif /* CONFIG_SAE */
+
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta) {
 		sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
@@ -2259,28 +2513,30 @@
 		}
 	}
 
-	if (multi_ap_value == MULTI_AP_BACKHAUL_STA)
-		sta->flags |= WLAN_STA_MULTI_AP;
+	if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "Multi-AP IE with unexpected value 0x%02x",
+			       multi_ap_value);
 
-	if ((hapd->conf->multi_ap & BACKHAUL_BSS) &&
-	    multi_ap_value == MULTI_AP_BACKHAUL_STA)
-		return WLAN_STATUS_SUCCESS;
+	if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
+		if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+			return WLAN_STATUS_SUCCESS;
 
-	if (hapd->conf->multi_ap & FRONTHAUL_BSS) {
-		if (multi_ap_value == MULTI_AP_BACKHAUL_STA) {
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE80211,
-				       HOSTAPD_LEVEL_INFO,
-				       "Backhaul STA tries to associate with fronthaul-only BSS");
-			return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
-		}
-		return WLAN_STATUS_SUCCESS;
+		hostapd_logger(hapd, sta->addr,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "Non-Multi-AP STA tries to associate with backhaul-only BSS");
+		return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
 	}
 
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO,
-		       "Non-Multi-AP STA tries to associate with backhaul-only BSS");
-	return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+	if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Backhaul STA tries to associate with fronthaul-only BSS");
+
+	sta->flags |= WLAN_STA_MULTI_AP;
+	return WLAN_STATUS_SUCCESS;
 }
 
 
@@ -2659,7 +2915,9 @@
 				   "state machine");
 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
 		}
+		wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
 		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  hapd->iface->freq,
 					  wpa_ie, wpa_ie_len,
 					  elems.mdie, elems.mdie_len,
 					  elems.owe_dh, elems.owe_dh_len);
@@ -2751,6 +3009,37 @@
 		}
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+		dpp_pfs_free(sta->dpp_pfs);
+		sta->dpp_pfs = NULL;
+
+		if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+		    hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
+		    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
+		    elems.owe_dh) {
+			sta->dpp_pfs = dpp_pfs_init(
+				wpabuf_head(hapd->conf->dpp_netaccesskey),
+				wpabuf_len(hapd->conf->dpp_netaccesskey));
+			if (!sta->dpp_pfs) {
+				wpa_printf(MSG_DEBUG,
+					   "DPP: Could not initialize PFS");
+				/* Try to continue without PFS */
+				goto pfs_fail;
+			}
+
+			if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
+					    elems.owe_dh_len) < 0) {
+				dpp_pfs_free(sta->dpp_pfs);
+				sta->dpp_pfs = NULL;
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+			}
+		}
+
+		wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
+				   sta->dpp_pfs->secret : NULL);
+	pfs_fail:
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_IEEE80211N
 		if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
 		    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
@@ -3021,6 +3310,10 @@
 	if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
 		buflen += 150;
 #endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+	if (sta && sta->dpp_pfs)
+		buflen += 5 + sta->dpp_pfs->curve->prime_len;
+#endif /* CONFIG_DPP2 */
 	buf = os_zalloc(buflen);
 	if (!buf) {
 		res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3128,6 +3421,39 @@
 	}
 #endif /* CONFIG_FST */
 
+#ifdef CONFIG_OWE
+	if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+	    sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
+	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
+		struct wpabuf *pub;
+
+		pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+		if (!pub) {
+			res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto done;
+		}
+		/* OWE Diffie-Hellman Parameter element */
+		*p++ = WLAN_EID_EXTENSION; /* Element ID */
+		*p++ = 1 + 2 + wpabuf_len(pub); /* Length */
+		*p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
+		WPA_PUT_LE16(p, sta->owe_group);
+		p += 2;
+		os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
+		p += wpabuf_len(pub);
+		wpabuf_free(pub);
+	}
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+	if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+	    sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
+	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
+		os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
+			  wpabuf_len(sta->dpp_pfs->ie));
+		p += wpabuf_len(sta->dpp_pfs->ie);
+	}
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_IEEE80211AC
 	if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
 		p = hostapd_eid_vendor_vht(hapd, p);
@@ -3224,30 +3550,6 @@
 	}
 #endif /* CONFIG_FILS */
 
-#ifdef CONFIG_OWE
-	if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
-	    sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
-	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
-		struct wpabuf *pub;
-
-		pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
-		if (!pub) {
-			res = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			goto done;
-		}
-		/* OWE Diffie-Hellman Parameter element */
-		*p++ = WLAN_EID_EXTENSION; /* Element ID */
-		*p++ = 1 + 2 + wpabuf_len(pub); /* Length */
-		*p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
-		WPA_PUT_LE16(p, sta->owe_group);
-		p += 2;
-		os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
-		p += wpabuf_len(pub);
-		send_len += 3 + 2 + wpabuf_len(pub);
-		wpabuf_free(pub);
-	}
-#endif /* CONFIG_OWE */
-
 	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
 		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
 			   strerror(errno));
@@ -3896,26 +4198,6 @@
 
 
 #ifdef CONFIG_IEEE80211W
-
-static int hostapd_sa_query_action(struct hostapd_data *hapd,
-				   const struct ieee80211_mgmt *mgmt,
-				   size_t len)
-{
-	const u8 *end;
-
-	end = mgmt->u.action.u.sa_query_resp.trans_id +
-		WLAN_SA_QUERY_TR_ID_LEN;
-	if (((u8 *) mgmt) + len < end) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
-			   "frame (len=%lu)", (unsigned long) len);
-		return 0;
-	}
-
-	ieee802_11_sa_query_action(hapd, mgmt, len);
-	return 1;
-}
-
-
 static int robust_action_frame(u8 category)
 {
 	return category != WLAN_ACTION_PUBLIC &&
@@ -4001,7 +4283,8 @@
 		return 1;
 #ifdef CONFIG_IEEE80211W
 	case WLAN_ACTION_SA_QUERY:
-		return hostapd_sa_query_action(hapd, mgmt, len);
+		ieee802_11_sa_query_action(hapd, mgmt, len);
+		return 1;
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WNM_AP
 	case WLAN_ACTION_WNM:
@@ -4196,7 +4479,7 @@
 	switch (stype) {
 	case WLAN_FC_STYPE_AUTH:
 		wpa_printf(MSG_DEBUG, "mgmt::auth");
-		handle_auth(hapd, mgmt, len, ssi_signal);
+		handle_auth(hapd, mgmt, len, ssi_signal, 0);
 		ret = 1;
 		break;
 	case WLAN_FC_STYPE_ASSOC_REQ:
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 5082226..db7badc 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -175,4 +175,6 @@
 int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
 		      int ap_seg1_idx, int *bandwidth, int *seg1_idx);
 
+void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
+
 #endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index d70d6c1..707381f 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -213,6 +213,14 @@
 	const u8 action_type = mgmt->u.action.u.sa_query_resp.action;
 	const u8 *trans_id = mgmt->u.action.u.sa_query_resp.trans_id;
 
+	if (((const u8 *) mgmt) + len <
+	    mgmt->u.action.u.sa_query_resp.variable) {
+		wpa_printf(MSG_DEBUG,
+			   "IEEE 802.11: Too short SA Query Action frame (len=%lu)",
+			   (unsigned long) len);
+		return;
+	}
+
 	sta = ap_get_sta(hapd, sa);
 
 #ifdef CONFIG_OCV
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index a56c82e..870329a 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2733,7 +2733,8 @@
 				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
 			  1 : 2,
 			  (unsigned int) diff.sec,
-			  sm->identity ? (char *) sm->identity : identity_buf);
+			  sm->identity ? (char *) sm->identity :
+					 (identity_buf ? identity_buf : "N/A"));
 	os_free(identity_buf);
 	if (os_snprintf_error(buflen - len, ret))
 		return len;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 4a7722c..71f9f21 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -13,6 +13,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
 #include "common/sae.h"
+#include "common/dpp.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "p2p/p2p.h"
@@ -362,6 +363,11 @@
 	crypto_ecdh_deinit(sta->owe_ecdh);
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+	dpp_pfs_free(sta->dpp_pfs);
+	sta->dpp_pfs = NULL;
+#endif /* CONFIG_DPP2 */
+
 	os_free(sta->ext_capability);
 
 #ifdef CONFIG_WNM_AP
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index ee3f628..ece0c60 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -265,6 +265,10 @@
 	u8 *ext_capability;
 	char *ifname_wds; /* WDS ifname, if in use */
 
+#ifdef CONFIG_DPP2
+	struct dpp_pfs *dpp_pfs;
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	enum wpa_alg last_tk_alg;
 	int last_tk_key_idx;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 3021a8c..616b205 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-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -114,12 +114,13 @@
 static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
 					  const u8 *addr,
 					  const u8 *p2p_dev_addr,
-					  const u8 *prev_psk, size_t *psk_len)
+					  const u8 *prev_psk, size_t *psk_len,
+					  int *vlan_id)
 {
 	if (wpa_auth->cb->get_psk == NULL)
 		return NULL;
 	return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
-				     prev_psk, psk_len);
+				     prev_psk, psk_len, vlan_id);
 }
 
 
@@ -251,6 +252,15 @@
 #endif /* CONFIG_OCV */
 
 
+static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
+				const u8 *addr, int vlan_id)
+{
+	if (!wpa_auth->cb->update_vlan)
+		return -1;
+	return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
+}
+
+
 static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_authenticator *wpa_auth = eloop_ctx;
@@ -686,6 +696,9 @@
 	os_free(sm->last_rx_eapol_key);
 	os_free(sm->wpa_ie);
 	wpa_group_put(sm->wpa_auth, sm->group);
+#ifdef CONFIG_DPP2
+	wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
 	os_free(sm);
 }
 
@@ -852,13 +865,15 @@
 	int ok = 0;
 	const u8 *pmk = NULL;
 	size_t pmk_len;
+	int vlan_id = 0;
 
 	os_memset(&PTK, 0, sizeof(PTK));
 	for (;;) {
 		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
 		    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
 			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
-					       sm->p2p_dev_addr, pmk, &pmk_len);
+					       sm->p2p_dev_addr, pmk, &pmk_len,
+					       &vlan_id);
 			if (pmk == NULL)
 				break;
 #ifdef CONFIG_IEEE80211R_AP
@@ -877,8 +892,10 @@
 
 		if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
 				       data, data_len) == 0) {
-			os_memcpy(sm->PMK, pmk, pmk_len);
-			sm->pmk_len = pmk_len;
+			if (sm->PMK != pmk) {
+				os_memcpy(sm->PMK, pmk, pmk_len);
+				sm->pmk_len = pmk_len;
+			}
 			ok = 1;
 			break;
 		}
@@ -897,6 +914,11 @@
 	wpa_printf(MSG_DEBUG,
 		   "WPA: Earlier SNonce resulted in matching MIC");
 	sm->alt_snonce_valid = 0;
+
+	if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+	    wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
+		return -1;
+
 	os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
 	os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
 	sm->PTK_valid = TRUE;
@@ -2024,7 +2046,7 @@
 
 	SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
 	psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
-			       &psk_len);
+			       &psk_len, NULL);
 	if (psk) {
 		os_memcpy(sm->PMK, psk, psk_len);
 		sm->pmk_len = psk_len;
@@ -2038,6 +2060,10 @@
 		wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache");
 		os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
 		sm->pmk_len = sm->pmksa->pmk_len;
+#ifdef CONFIG_IEEE80211R_AP
+		os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len);
+		sm->xxkey_len = sm->pmksa->pmk_len;
+#endif /* CONFIG_IEEE80211R_AP */
 	}
 #endif /* CONFIG_SAE */
 	sm->req_replay_counter_used = 0;
@@ -2136,14 +2162,24 @@
 			  const u8 *pmk, unsigned int pmk_len,
 			  struct wpa_ptk *ptk)
 {
+	const u8 *z = NULL;
+	size_t z_len = 0;
+
 #ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
 		return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
 #endif /* CONFIG_IEEE80211R_AP */
 
+#ifdef CONFIG_DPP2
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+		z = wpabuf_head(sm->dpp_z);
+		z_len = wpabuf_len(sm->dpp_z);
+	}
+#endif /* CONFIG_DPP2 */
+
 	return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
 			      sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
-			      ptk, sm->wpa_key_mgmt, sm->pairwise);
+			      ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
 }
 
 
@@ -2193,6 +2229,16 @@
 			    pmk_r0_name, WPA_PMK_NAME_LEN);
 		wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
 		os_memset(fils_ft, 0, sizeof(fils_ft));
+
+		res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
+					     sm->addr, sm->pmk_r1_name,
+					     use_sha384);
+		os_memset(pmk_r0, 0, PMK_LEN_MAX);
+		if (res < 0)
+			return -1;
+		wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
+			    WPA_PMK_NAME_LEN);
+		sm->pmk_r1_name_valid = 1;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
 
@@ -2712,6 +2758,7 @@
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
 	struct wpa_eapol_ie_parse kde;
+	int vlan_id = 0;
 
 	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
 	sm->EAPOLKeyReceived = FALSE;
@@ -2727,7 +2774,8 @@
 		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
 		    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
 			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
-					       sm->p2p_dev_addr, pmk, &pmk_len);
+					       sm->p2p_dev_addr, pmk, &pmk_len,
+					       &vlan_id);
 			if (pmk == NULL)
 				break;
 			psk_found = 1;
@@ -2749,8 +2797,10 @@
 		    wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
 				       sm->last_rx_eapol_key,
 				       sm->last_rx_eapol_key_len) == 0) {
-			os_memcpy(sm->PMK, pmk, pmk_len);
-			sm->pmk_len = pmk_len;
+			if (sm->PMK != pmk) {
+				os_memcpy(sm->PMK, pmk, pmk_len);
+				sm->pmk_len = pmk_len;
+			}
 			ok = 1;
 			break;
 		}
@@ -2896,6 +2946,13 @@
 	}
 #endif /* CONFIG_IEEE80211R_AP */
 
+	if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+	    wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
+		wpa_sta_disconnect(wpa_auth, sm->addr,
+				   WLAN_REASON_PREV_AUTH_NOT_VALID);
+		return;
+	}
+
 	sm->pending_1_of_4_timeout = 0;
 	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 
@@ -3335,7 +3392,7 @@
 		break;
 	case WPA_PTK_INITPSK:
 		if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
-				     NULL, NULL)) {
+				     NULL, NULL, NULL)) {
 			SM_ENTER(WPA_PTK, PTKSTART);
 #ifdef CONFIG_SAE
 		} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
@@ -4786,6 +4843,24 @@
 #endif /* CONFIG_FILS */
 
 
+void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
+{
+	if (sm)
+		sm->auth_alg = auth_alg;
+}
+
+
+#ifdef CONFIG_DPP2
+void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
+{
+	if (sm) {
+		wpabuf_clear_free(sm->dpp_z);
+		sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+	}
+}
+#endif /* CONFIG_DPP2 */
+
+
 #ifdef CONFIG_TESTING_OPTIONS
 
 int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index e61648d..484e1e5 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -254,7 +254,8 @@
 			  int value);
 	int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
 	const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
-			      const u8 *prev_psk, size_t *psk_len);
+			      const u8 *prev_psk, size_t *psk_len,
+			      int *vlan_id);
 	int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
 	int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
 		       const u8 *addr, int idx, u8 *key, size_t key_len);
@@ -270,6 +271,7 @@
 	int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data,
 			size_t data_len);
 	int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+	int (*update_vlan)(void *ctx, const u8 *addr, int vlan_id);
 	int (*get_sta_tx_params)(void *ctx, const u8 *addr,
 				 int ap_max_chanwidth, int ap_seg1_idx,
 				 int *bandwidth, int *seg1_idx);
@@ -316,7 +318,7 @@
 };
 
 int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
-			struct wpa_state_machine *sm,
+			struct wpa_state_machine *sm, int freq,
 			const u8 *wpa_ie, size_t wpa_ie_len,
 			const u8 *mdie, size_t mdie_len,
 			const u8 *owe_dh, size_t owe_dh_len);
@@ -471,6 +473,8 @@
 u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
 				   u8 *pos, size_t max_len,
 				   const u8 *req_ies, size_t req_ies_len);
+void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
+void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
 
 int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
 		       void (*cb)(void *ctx1, void *ctx2),
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index ac736f0..fdb7eba 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -66,7 +66,7 @@
  * Returns: 0 on success, -1 on error
  */
 static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
-			      const u8 *enc, const size_t enc_len,
+			      const u8 *enc, size_t enc_len,
 			      const u8 *auth, const size_t auth_len,
 			      const u8 *src_addr, u8 type,
 			      u8 **plain, size_t *plain_size)
@@ -74,7 +74,11 @@
 	const u8 *ad[3] = { src_addr, auth, &type };
 	size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
 
+	wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
+		   MAC2STR(src_addr), type);
 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypt using key", key, key_len);
+	wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs", enc, enc_len);
+	wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
 
 	if (!key) { /* skip decryption */
 		*plain = os_memdup(enc, enc_len);
@@ -97,8 +101,18 @@
 		goto err;
 
 	if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
-			    *plain) < 0)
-		goto err;
+			    *plain) < 0) {
+		if (enc_len < AES_BLOCK_SIZE + 2)
+			goto err;
+
+		/* Try to work around Ethernet devices that add extra
+		 * two octet padding even if the frame is longer than
+		 * the minimum Ethernet frame. */
+		enc_len -= 2;
+		if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
+				    *plain) < 0)
+			goto err;
+	}
 
 	*plain_size = enc_len - AES_BLOCK_SIZE;
 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypted TLVs",
@@ -463,9 +477,12 @@
 	const u8 *ad[3] = { src_addr, auth, &type };
 	size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
 
+	wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
+		   MAC2STR(src_addr), type);
 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): plaintext message",
 			plain, plain_len);
 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): encrypt using key", key, key_len);
+	wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
 
 	if (!key) {
 		/* encryption not needed, return plaintext as packet */
@@ -475,6 +492,8 @@
 		wpa_printf(MSG_ERROR, "FT: Failed to encrypt RRB-OUI message");
 		return -1;
 	}
+	wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs",
+		    enc, plain_len + AES_BLOCK_SIZE);
 
 	return 0;
 }
@@ -503,9 +522,10 @@
 			    const u8 *src_addr, u8 type,
 			    u8 **packet, size_t *packet_len)
 {
-	u8 *plain = NULL, *auth = NULL, *pos;
+	u8 *plain = NULL, *auth = NULL, *pos, *tmp;
 	size_t plain_len = 0, auth_len = 0;
 	int ret = -1;
+	size_t pad_len = 0;
 
 	*packet = NULL;
 	if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0)
@@ -517,6 +537,28 @@
 	*packet_len = sizeof(u16) + auth_len + plain_len;
 	if (key)
 		*packet_len += AES_BLOCK_SIZE;
+#define RRB_MIN_MSG_LEN 64
+	if (*packet_len < RRB_MIN_MSG_LEN) {
+		pad_len = RRB_MIN_MSG_LEN - *packet_len;
+		if (pad_len < sizeof(struct ft_rrb_tlv))
+			pad_len = sizeof(struct ft_rrb_tlv);
+		wpa_printf(MSG_DEBUG,
+			   "FT: Pad message to minimum Ethernet frame length (%d --> %d)",
+			   (int) *packet_len, (int) (*packet_len + pad_len));
+		*packet_len += pad_len;
+		tmp = os_realloc(auth, auth_len + pad_len);
+		if (!tmp)
+			goto out;
+		auth = tmp;
+		pos = auth + auth_len;
+		WPA_PUT_LE16(pos, FT_RRB_LAST_EMPTY);
+		pos += 2;
+		WPA_PUT_LE16(pos, pad_len - sizeof(struct ft_rrb_tlv));
+		pos += 2;
+		os_memset(pos, 0, pad_len - sizeof(struct ft_rrb_tlv));
+		auth_len += pad_len;
+
+	}
 	*packet = os_zalloc(*packet_len);
 	if (!*packet)
 		goto out;
@@ -529,6 +571,7 @@
 	if (wpa_ft_rrb_encrypt(key, key_len, plain, plain_len, auth,
 			       auth_len, src_addr, type, pos) < 0)
 		goto out;
+	wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", *packet, *packet_len);
 
 	ret = 0;
 
@@ -596,8 +639,8 @@
 {
 	if (!wpa_auth->cb->send_oui)
 		return -1;
-	wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR,
-		   oui_suffix, MAC2STR(dst));
+	wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR " (len=%u)",
+		   oui_suffix, MAC2STR(dst), (unsigned int) data_len);
 	return wpa_auth->cb->send_oui(wpa_auth->cb_ctx, dst, oui_suffix, data,
 				      data_len);
 }
@@ -620,7 +663,7 @@
 	if (wpa_auth->cb->get_psk == NULL)
 		return NULL;
 	return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
-				     prev_psk, NULL);
+				     prev_psk, NULL, NULL);
 }
 
 
@@ -907,6 +950,8 @@
 		goto err;
 	}
 
+	wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
+		   MAC2STR(src_addr));
 	item = os_zalloc(sizeof(*item));
 	if (!item)
 		goto err;
@@ -2386,10 +2431,24 @@
 
 	end = pos + max_len;
 
-	if (auth_alg == WLAN_AUTH_FT) {
+	if (auth_alg == WLAN_AUTH_FT ||
+	    ((auth_alg == WLAN_AUTH_FILS_SK ||
+	      auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+	      auth_alg == WLAN_AUTH_FILS_PK) &&
+	     (sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
+				  WPA_KEY_MGMT_FT_FILS_SHA384)))) {
+		if (!sm->pmk_r1_name_valid) {
+			wpa_printf(MSG_ERROR,
+				   "FT: PMKR1Name is not valid for Assoc Resp RSNE");
+			return NULL;
+		}
+		wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name for Assoc Resp RSNE",
+			    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
 		/*
 		 * RSN (only present if this is a Reassociation Response and
-		 * part of a fast BSS transition)
+		 * part of a fast BSS transition; or if this is a
+		 * (Re)Association Response frame during an FT initial mobility
+		 * domain association using FILS)
 		 */
 		res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
 		if (res < 0)
@@ -4373,6 +4432,7 @@
 	wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
 		   MACSTR, MAC2STR(src_addr));
 	wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+	wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
 
 	if (is_multicast_ether_addr(src_addr)) {
 		wpa_printf(MSG_DEBUG,
@@ -4401,8 +4461,10 @@
 	}
 
 	auth = data + sizeof(u16);
+	wpa_hexdump(MSG_MSGDUMP, "FT: Authenticated payload", auth, alen);
 	enc = data + sizeof(u16) + alen;
 	elen = data_len - sizeof(u16) - alen;
+	wpa_hexdump(MSG_MSGDUMP, "FT: Encrypted payload", enc, elen);
 
 	switch (oui_suffix) {
 	case FT_PACKET_R0KH_R1KH_PULL:
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 9091f43..45172c6 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -246,12 +246,15 @@
 
 static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
 					   const u8 *p2p_dev_addr,
-					   const u8 *prev_psk, size_t *psk_len)
+					   const u8 *prev_psk, size_t *psk_len,
+					   int *vlan_id)
 {
 	struct hostapd_data *hapd = ctx;
 	struct sta_info *sta = ap_get_sta(hapd, addr);
 	const u8 *psk;
 
+	if (vlan_id)
+		*vlan_id = 0;
 	if (psk_len)
 		*psk_len = PMK_LEN;
 
@@ -287,7 +290,8 @@
 	}
 #endif /* CONFIG_OWE */
 
-	psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
+	psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk,
+			      vlan_id);
 	/*
 	 * This is about to iterate over all psks, prev_psk gives the last
 	 * returned psk which should not be returned again.
@@ -295,6 +299,9 @@
 	 */
 	if (sta && sta->psk && !psk) {
 		struct hostapd_sta_wpa_psk_short *pos;
+
+		if (vlan_id)
+			*vlan_id = 0;
 		psk = sta->psk->psk;
 		for (pos = sta->psk; pos; pos = pos->next) {
 			if (pos->is_passphrase) {
@@ -788,6 +795,45 @@
 }
 
 
+static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
+{
+#ifndef CONFIG_NO_VLAN
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	struct vlan_description vlan_desc;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta)
+		return -1;
+
+	os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+	vlan_desc.notempty = 1;
+	vlan_desc.untagged = vlan_id;
+	if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+		wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
+			   vlan_id);
+		return -1;
+	}
+
+	if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
+		wpa_printf(MSG_INFO,
+			   "Failed to assign VLAN ID %d from wpa_psk_file to "
+			   MACSTR, vlan_id, MAC2STR(sta->addr));
+		return -1;
+	}
+
+	wpa_printf(MSG_INFO,
+		   "Assigned VLAN ID %d from wpa_psk_file to " MACSTR,
+		   vlan_id, MAC2STR(sta->addr));
+	if ((sta->flags & WLAN_STA_ASSOC) &&
+	    ap_sta_bind_vlan(hapd, sta) < 0)
+		return -1;
+#endif /* CONFIG_NO_VLAN */
+
+	return 0;
+}
+
+
 #ifdef CONFIG_OCV
 static int hostapd_get_sta_tx_params(void *ctx, const u8 *addr,
 				     int ap_max_chanwidth, int ap_seg1_idx,
@@ -1229,6 +1275,7 @@
 		.send_ether = hostapd_wpa_auth_send_ether,
 		.send_oui = hostapd_wpa_auth_send_oui,
 		.channel_info = hostapd_channel_info,
+		.update_vlan = hostapd_wpa_auth_update_vlan,
 #ifdef CONFIG_OCV
 		.get_sta_tx_params = hostapd_get_sta_tx_params,
 #endif /* CONFIG_OCV */
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index a349304..3dcf77a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -22,6 +22,7 @@
 
 	u8 addr[ETH_ALEN];
 	u8 p2p_dev_addr[ETH_ALEN];
+	u16 auth_alg;
 
 	enum {
 		WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
@@ -150,6 +151,10 @@
 	unsigned int fils_completed:1;
 #endif /* CONFIG_FILS */
 
+#ifdef CONFIG_DPP2
+	struct wpabuf *dpp_z;
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	void (*eapol_status_cb)(void *ctx1, void *ctx2);
 	void *eapol_status_cb_ctx1;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 3bcbef7..8580a5a 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -530,7 +530,7 @@
 
 
 int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
-			struct wpa_state_machine *sm,
+			struct wpa_state_machine *sm, int freq,
 			const u8 *wpa_ie, size_t wpa_ie_len,
 			const u8 *mdie, size_t mdie_len,
 			const u8 *owe_dh, size_t owe_dh_len)
@@ -560,6 +560,10 @@
 
 	if (version == WPA_PROTO_RSN) {
 		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
+		if (!data.has_pairwise)
+			data.pairwise_cipher = wpa_default_rsn_cipher(freq);
+		if (!data.has_group)
+			data.group_cipher = wpa_default_rsn_cipher(freq);
 
 		if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie &&
 		    !wpa_key_mgmt_only_ft(data.key_mgmt)) {
@@ -831,6 +835,12 @@
 			   "OWE: No Diffie-Hellman Parameter element");
 		return WPA_INVALID_AKMP;
 	}
+#ifdef CONFIG_DPP
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) {
+		/* Diffie-Hellman Parameter element can be used with DPP as
+		 * well, so allow this to proceed. */
+	} else
+#endif /* CONFIG_DPP */
 	if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
 		wpa_printf(MSG_DEBUG,
 			   "OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
@@ -848,6 +858,21 @@
 	else
 		sm->wpa = WPA_VERSION_WPA;
 
+#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
+	if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
+	     sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
+	    (sm->auth_alg == WLAN_AUTH_FILS_SK ||
+	     sm->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+	     sm->auth_alg == WLAN_AUTH_FILS_PK) &&
+	    (data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid ||
+	     os_memcmp_const(data.pmkid, sm->pmk_r1_name,
+			     WPA_PMK_NAME_LEN) != 0)) {
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				 "No PMKR1Name match for FILS+FT");
+		return WPA_INVALID_PMKID;
+	}
+#endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */
+
 	sm->pmksa = NULL;
 	for (i = 0; i < data.num_pmkid; i++) {
 		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 5ec0199..6161cdb 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -354,6 +354,18 @@
 							    bss->wpa_pairwise,
 							    bss->rsn_pairwise);
 
+		if (hapd->conf->wps_cred_add_sae &&
+		    (cred->auth_type & WPS_AUTH_WPA2PSK) &&
+		    cred->key_len != 2 * PMK_LEN) {
+			bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
+#ifdef CONFIG_IEEE80211W
+			if (bss->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+				bss->ieee80211w =
+					MGMT_FRAME_PROTECTION_OPTIONAL;
+			bss->sae_require_mfp = 1;
+#endif /* CONFIG_IEEE80211W */
+		}
+
 		if (cred->key_len >= 8 && cred->key_len < 64) {
 			os_free(bss->ssid.wpa_passphrase);
 			bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
@@ -401,6 +413,7 @@
 	char buf[1024];
 	int multi_bss;
 	int wpa;
+	int pmf_changed = 0;
 
 	if (hapd->wps == NULL)
 		return 0;
@@ -520,6 +533,10 @@
 
 	if (wpa) {
 		char *prefix;
+#ifdef CONFIG_IEEE80211W
+		int sae = 0;
+#endif /* CONFIG_IEEE80211W */
+
 		fprintf(nconf, "wpa=%d\n", wpa);
 
 		fprintf(nconf, "wpa_key_mgmt=");
@@ -528,10 +545,30 @@
 			fprintf(nconf, "WPA-EAP");
 			prefix = " ";
 		}
-		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
 			fprintf(nconf, "%sWPA-PSK", prefix);
+			prefix = " ";
+		}
+		if (hapd->conf->wps_cred_add_sae &&
+		    (cred->auth_type & WPS_AUTH_WPA2PSK) &&
+		    cred->key_len != 2 * PMK_LEN) {
+			fprintf(nconf, "%sSAE", prefix);
+#ifdef CONFIG_IEEE80211W
+			sae = 1;
+#endif /* CONFIG_IEEE80211W */
+		}
 		fprintf(nconf, "\n");
 
+#ifdef CONFIG_IEEE80211W
+		if (sae && hapd->conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+			fprintf(nconf, "ieee80211w=%d\n",
+				MGMT_FRAME_PROTECTION_OPTIONAL);
+			pmf_changed = 1;
+		}
+		if (sae)
+			fprintf(nconf, "sae_require_mfp=1\n");
+#endif /* CONFIG_IEEE80211W */
+
 		fprintf(nconf, "wpa_pairwise=");
 		prefix = "";
 		if (cred->encr_type & WPS_ENCR_AES) {
@@ -585,6 +622,7 @@
 		     str_starts(buf, "wep_default_key=") ||
 		     str_starts(buf, "wep_key") ||
 		     str_starts(buf, "wps_state=") ||
+		     (pmf_changed && str_starts(buf, "ieee80211w=")) ||
 		     str_starts(buf, "wpa=") ||
 		     str_starts(buf, "wpa_psk=") ||
 		     str_starts(buf, "wpa_pairwise=") ||
@@ -975,6 +1013,7 @@
 {
 	struct wps_context *wps;
 	struct wps_registrar_config cfg;
+	u8 *multi_ap_netw_key = NULL;
 
 	if (conf->wps_state == 0) {
 		hostapd_wps_clear_ies(hapd, 0);
@@ -1133,6 +1172,31 @@
 		wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
 	}
 
+	if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
+	    hapd->conf->multi_ap_backhaul_ssid.ssid_len) {
+		cfg.multi_ap_backhaul_ssid_len =
+			hapd->conf->multi_ap_backhaul_ssid.ssid_len;
+		cfg.multi_ap_backhaul_ssid =
+			hapd->conf->multi_ap_backhaul_ssid.ssid;
+
+		if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+			cfg.multi_ap_backhaul_network_key = (const u8 *)
+				conf->multi_ap_backhaul_ssid.wpa_passphrase;
+			cfg.multi_ap_backhaul_network_key_len =
+				os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+		} else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+			multi_ap_netw_key = os_malloc(2 * PMK_LEN + 1);
+			if (!multi_ap_netw_key)
+				goto fail;
+			wpa_snprintf_hex((char *) multi_ap_netw_key,
+					 2 * PMK_LEN + 1,
+					 conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+					 PMK_LEN);
+			cfg.multi_ap_backhaul_network_key = multi_ap_netw_key;
+			cfg.multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+		}
+	}
+
 	wps->ap_settings = conf->ap_settings;
 	wps->ap_settings_len = conf->ap_settings_len;
 
@@ -1174,10 +1238,12 @@
 	hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
 
 	hapd->wps = wps;
+	bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
 
 	return 0;
 
 fail:
+	bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
 	hostapd_free_wps(wps);
 	return -1;
 }