[wpa_supplicant] Cumulative patch from 9fde14607

Changes include required updates to DPP R2.

Bug: 143479699
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: Regression test Passed (Bug: 143485775)

9fde14607 Allow scans triggered by D-Bus to use MAC address randomization
10f8351d6 D-Bus: Add MAC address randomization endpoints
bb66d4675 Move ownership of MAC address randomization mask to scan params
6c2f70cc6 DPP: Mention ssid and pass parameters for DPP_AUTH_INIT in documentation
1030dec1f JSON: Fix escaping of characters that have MSB=1 with signed char
7800725af dbus: Export OWE capability and OWE BSS key_mgmt
b2ad4e6b2 D-Bus: Fix P2P NULL dereference after interface removal
937644aa2 nl80211: Indicate SUITE_B_192 capa only when CCMP-256/GCMP-256 supported
1b5865a53 SAE: Ignore commit message when waiting for confirm in STA mode
50a2c8c90 Do not indicate possible PSK failure when using SAE
df3b2e22a nl80211: Add STA node details in AP through QCA vendor subcommand
f273b2a5c Add QCA vendor cmd for setting BT coex chain mode
4dc860680 Extend QCA OEM data vendor subcmd to allow use as an event
93a1e275a SAE: Determine H2E vs. looping when restarting SAE auth in AP mode
de580bf6c crypto: Remove unused crypto_bignum_sqrtmod()
9b292a48f SAE: Drop sqrt() alternative from SSWU (H2E)
305369038 wpa_supplicant: Fix arithmetic on void pointer
00ddc1cc2 common: Fix same expression checked twice in fils_key_auth_sk()
327d09aa0 HE: Add 11ax info to ap mode ctrl iface STATUS command
d7678a084 Fix AP Extended Capability length determination
a592f2a9e P2P: Continue listening next request if no post-PD operations
a32acf391 Fix hostapd build with CONFIG_WPA_TRACE but no CONFIG_WPA_TRACE_BFD
b38c8c9cb dbus: Suppress to show NULL string
6807eee9c Interworking: Check NULL string to avoid compiler warning
ec1c0d154 Fix name of DBus interface in defconfig
f73dd0a69 FT-SAE: Add RSNXE into FT MIC
cb9925977 Add RSNXE into (Re)Association Response frames
865721c69 Merge wpa_supplicant and hostapd EAPOL-Key KDE parsers
898b6d58f SAE: Verify that STA negotiated H2E if it claims to support it
74866f537 RSN: Verify RSNXE match between (Re)AssocReq and EAPOL-Key msg 2/4
9981d5bf3 Add RSNXE into AP KDE parser
d3516cad7 Store a copy of Association Request RSNXE in AP mode for later use
6d6c88775 SAE: Add RSNXE in Association Request and EAPOL-Key msg 2/4
8401cdc8d Add RSNXE into IE parser
0b0ed907d WPS: Check SHA256 result success
8dda97c75 QCA vendor command for adding a STA node
b41dc61af Add a new QCA vendor attribute to carry device info for OEM data
bf185bfd5 QCA vendor attributes to indicate BW-based agile spectral capability
1317ea2c0 nl80211: Allow external auth based on SAE/FT-SAE key mgmt
cdb5774f4 FST: Update FST about MAC address change
49e95ee1e AP: Publish only HE capabilities and operation IEs on 6 GHz band
d7c2c5c98 AP: Add initial support for 6 GHz band
a5b2faa71 AP: Add op_class config item to specify 6 GHz channels uniquely
89450024a wpa_supplicant: Pass in operating class for channel validity checks
032c8264d SAE: Check that peer's rejected groups are not enabled in AP
a5dc2a5c1 SAE: H2E version of SAE commit message handling for AP
43b20b437 SAE: Derive H2E PT in AP when starting the AP
444d76f74 SAE: Check that peer's rejected groups are not enabled
cfe1ea5c9 SAE: H2E version of SAE commit message handling for STA
447cd5f2d SAE: Collect list of rejected groups for H2E in STA
05a2fb0d1 SAE: Derive H2E PT in STA before connection
146889e3c RSN: Verify RSNXE match between Beacon/ProbeResp and EAPOL-Key msg 3/4
3134bb13a SAE: Advertise Extended RSN Capabilities when H2E is enabled
293a01f3b SAE: Handle BSS membership selector indication for H2E-only in STA mode
cc0da0ff4 SAE: Advertise BSS membership selector for H2E-only case
85e64e634 SAE: Add sae_pwe configuration parameter for wpa_supplicant
a36e13a7c SAE: Add sae_pwe configuration parameter for hostapd
af4487148 tests: Module test for SAE hash-to-element crypto routines
cf84246eb SAE: Add Rejected Groups element into H2E Commit
efd428529 SAE: Hash algorithm selection for H2E KCK/CN()
aeb022f8e SAE: Implement hash-to-element PT/PWE crypto routines
ecd711407 SAE: Parse Rejected Groups element from H2E SAE commit
86f608486 SAE: Tell sae_parse_commit() whether H2E is used
316156739 SAE: H2E protocol defines
1766e608b wolfSSL: Fix crypto_bignum_sub()
2a1c84f4e crypto: Add more bignum/EC helper functions
9c08bfbd9 DPP: Fix confusing debug entry from Configurator
f7fe05522 SAE: Allow AP behavior for SAE Confirm to be configured
d6a7de60c wpa_cli: Clean up unnecessarily complex CONFIG_MESH use
8b426ab1e wpa_supplicant: Pass AP mode EDMG config to hostapd struct
a82aee1f4 wpa_supplicant: Add support for EDMG channels
35aed771f Indicate EDMG in scan results
f6f8c6ade AP: Show EDMG channel info in STATUS output
241dd76cf hostapd: Check EDMG configuration against capability
dc3457cc4 hostapd: Check usability of EDMG channel
bebd91e9c Add EDMG parameters to set_freq functions
fdd0fef2c EDMG: Helper functions for parameter encoding/checking
e8ff22f47 wpa_supplicant: Add EDMG channel configuration parameters
5c5ff22ef hostapd: Add EDMG channel configuration parameters
dda5d9e31 nl80211: Add support for EDMG channels
a19913c17 IEEE P802.11ay/D4.0 defines for EDMG
c34917403 MBO/OCE: Update disable_mbo_oce flag after association
b719a1568 DPP2: Parse AKM suite selector version of akm node
68fea9603 DPP2: Allow Configurator to use AKM suite selectors in Config Object
52d469de1 DPP2: Support multiple Config Objects in Enrollee
7eb06a336 DPP2: Allow multiple Config Objects to be build on Configurator
99918e069 DPP: Cleaned up netrole indication for config object building
e0d22c842 FILS+FT: Fix MFPR flag in RSNE during FILS exchange for FT
d0a4ed6a1 Allow SAE to be used in wpa_supplicant AP mode
7846e8d60 NetBSD: Fix compile
2e06cef80 MBO/OCE: Work around misbehaving MBO/OCE APs that use RSN without PMF
722c7d195 wlantest: Process VLAN tagged Data frames
83b83b461 nl80211: Migrate to current netlink key message format
7a4b01c87 AP: Provide correct keyid to wpa_send_eapol() for EAPOL-Key msg 3/4
a3ebf7175 BSD: Add support for route(4) message filtering
d9286d099 ACS: Stop before scan if no channels in chanlist are available
f32aa244e DPP: Debug print configRequest bandSupport on Configurator
8f8c423a5 DPP: Add bandSupport JSON array into config request
6d3dc9ba1 mka: Check OLPN for exhaustion on SAKuse decode
84851007d mka: Check OLPN for exhaustion on SAKuse encode
547ba732d mka: Clear out old/latest key values on CHANGE in CP state machine
536a7cfcf mka: Don't set newSAK to FALSE on ABANDON in CP state machine
0fedfba2e mka: Change RECEIVE and RETIRE states to match the standard
3f2641e7a Fix wpa_supplicant build with CONFIG_PCSC=y
5a5639b06 DPP: Allow name and mudurl to be configured for Config Request
3394def5a More consistent SA check for unexpected Data frames
16ef233bf DPP2: Connection status result (Enrollee)
b10e01a79 DPP2: Connection status result (Configurator)
e501a2eb5 DPP2: Connection status result defines
cc8399528 DPP2: Move dpp_build_conf_result() to be within ifdef block
3a6736fe8 DPP2: Fix a memory leak on error path for Config Result
21dc1627f wpa_supplicant: Don't return an error when successfully parsing WMM rules
8214b45ba P2P: Use latest BSS entry if multiple P2P Device Addr matches found
dc6c3be4e wpa_supplicant: Add support for 60 GHz band channels 5 and 6
018edec9b Remove IAPP functionality from hostapd
d86d66dc0 AP: Silently ignore management frame from unexpected source address
a84bf4438 HE: Send the AP's OBSS PD settings to the kernel
262b71eea Sync with mac80211-next.git include/uapi/linux/nl80211.h
8788a314d WPS: Update MAC address on address changes
39042d7f7 os_sleep: Use nanosleep for POSIX versions 2008 and higher
a69742c2f wpa_cli: Do not pick p2p-dev-* interfaces by default
d842e00bd SAE: Return result from confirm CN() operation to the caller
a8bfc6fff FILS: Update connect params after sending connection notification
0df82a3da Correct the type/usage of QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST
6bf6c6fec DPP: Fix hostapd build dependencies for DPP-only build
1eff2e7bf DPP2: Fix wpa_supplicant build dependencies for CONFIG_AP=y build
d2bae5763 DPP: Fix wpa_supplicant build dependencies for DPP-only build
7d2ed8bae Remove CONFIG_IEEE80211W build parameter
022926187 DFS offload: Fix hostapd state and CAC info in STATUS output
4d78ba990 EAP-TEAP peer: Clear Phase 2 EAP method on new Identity exchange
681618246 EAP-TEAP peer: Add support for machine credentials using certificates
ebee8232d Do not try to include net/ethernet.h in MinGW/Windows builds
bf15b1559 Fix Windows error code definition workaround
043de65f1 EAP peer config: Move ocsp param to phase1/phase2
8d76e0ad7 EAP server: Configurable maximum number of authentication message rounds
b99c4cadb EAP peer: Move certificate configuration params into shared struct
6e711e7ab mesh: Do not enable HE on 5 GHz without VHT
0497e4148 HE: Fix HE Capabilities element size
a2e0cc9e0 Add nl80211 vendor ACS trigger reasons related to interference
69e8e7817 HS 2.0: Do not add two copies of OSEN element into Beacon/Probe Resp
a762ba8b1 HS 2.0 AP: Do not mandate PMF for HS 2.0 Indication in open OSU network
e49ce2990 IEEE 802.1X authenticator: Coding style cleanup
31aaddc90 Clean up IEEE 802.1X authentication debug messages for EAP code
71419119f EAP-TEAP peer: Fix protected indication of inner EAP method failure
93cd29d2b EAP-TEAP server: Add support for requiring user and machine credentials
c38c62ff7 wlantest: Derive PMK-R1 and PTK for FT protocol cases
c41936566 EAP-TEAP peer: Add support for machine authentication
c724a0a16 EAP peer: Add a concept of a separate machine credential
9ce3bfaf4 RADIUS server: Abort startup on allocation failures
fa1f0751c RADIUS server: Use struct eap_config to avoid duplicated definitions
a00cb1b1f EAP-TEAP server: Fix eap_teap_pac_no_inner configuration
986033ff3 EAP-TEAP server: Fix Crypto-Binding check in PAC no-inner-auth case
e54cfbb56 EAP-TEAP server: Allow a specific Identity-Type to be requested/required
f186ec54c EAP-TEAP peer: Support Identity-Type TLV
cc661c160 EAP-TEAP: Add parsing and generation routines for Identity-Type TLV
100b2edb2 OpenSSL: Write peer certificate chain details in debug log
7eb157f1e EAP: Increase the maximum number of message exchanges
822e7c66a EAP server: Use struct eap_config to avoid duplicated definitions
62af2b18f EAP-TEAP peer: Support vendor EAP method in Phase 2
aba8dc82f EAP-PEAP server: Support vendor EAP types in Phase 2
357c1062d EAP-FAST peer: Support vendor EAP method in Phase 2
f32f76231 EAP-FAST server: Support vendor EAP types in Phase 2
887d8703b EAP-PEAP peer: Support vendor EAP method in Phase 2
f2ef4f255 EAP peer: Allow VENDOR-TEST method in Phase 2
5ddbd9e96 EAP-TTLS peer: Support vendor EAP method in Phase 2
5e94e7f23 EAP-TTLS server: Support vendor EAP types in Phase 2
5f2301a6d Replace EapType typedef with enum eap_type
76ddfae6e EAP-TEAP server: Testing mechanism for Result TLV in a separate message
4c327146f EAP-TEAP peer: Allow Result TLV without Crypto-Binding TLV
128d46be9 EAP-TEAP: Add parsing of Error TLV
234489efd EAP-TEAP server: Require Intermediate-Result TLV even with Result TLV
0f7c91f2b EAP-TEAP peer: Add Intermediate-Result TLV with Crypto-Binding TLV
a66e53c41 EAP-TEAP: Fix TLS-PRF for TLS ciphersuites that use SHA384
52069c7ef Add TLS-PRF using HMAC with P_SHA384 for TEAP
a647a0ad7 Extend server certificate TOD policy reporting to include TOD-TOFU
346d10cf8 SAE: Conditionally set PMKID while notifying the external auth status
b7cd64876 SAE: Use BSSID stored in ext_auth_bssid for set_pmk
e0b331d89 OWE: Update connect params with new DH attributes to the driver
c574a3ff1 nl80211: Request update connection params only for drivers with SME
528f263c4 FT: Reject over-the-DS response with MFPC=0 if PMF is required
ae05b6a21 RSN: Do not allow connection to proceed without MFPC=1 if PMF required
ded56f2fa FT: Fix MFPR flag in RSNE during FT protocol
0028d627c OCE: Mandate PMF for WPA2 association with OCE AP
84ebc759a HS 2.0: Match credentials based on required_roaming_consortium
d2b208384 SAE: Allow PMKID to be added into Association Request frame following SAE
2ca23faf1 Make wpa_insert_pmkid() more generic
05822609d HE: MCS size is always a minimum of 4 bytes
df4f95998 nl80211: Don't force VHT channel definition with HE
dd0153fce Check for LEAP before doing FT
6126e5f97 Fix a typo in hostapd config documentation
698a0067c Fix check_crl_strict documentation
485dd425b Add QCA vendor command for avoid frequency feature
6ae1247bf Update QCA vendor attributes for 6 GHz band support
aa23ece3d Add QCA vendor channel attribute to restart AP
85508ecf6 Add QCA vendor command to configure ACS policy
2395fdb67 Add QCA vendor attributes to enhance roaming configuration
1425caac2 Rename qca_wlan_vendor_attr_roam_subcmd to represent subcmds
f13119631 Document the attributes used by QCA_NL80211_VENDOR_SUBCMD_ROAM
b0b25c5bb Clear external eapSuccess setting in driver-authorized cases
fa1d5ec18 The master branch is now used for v2.10 development
ca8c2bd28 Preparations for v2.8 release
3263fca28 Set the default scan IEs on interface restart
d776bf8c6 EAP-TEAP peer: Fix fragmentation of final message
1c7e61a35 wolfssl: Avoid void pointer arithmetic
7122a02fa SAE: Fix order_len for FFC groups
422e73d62 DPP: Indicate authentication success on ConfReqRX if needed
d001fe31a OpenSSL: Handle EVP_PKEY_derive() secret_len changes for ECDH
29ef1c5ee DPP: Use a common helper function for ECDH operations
ac734a342 SAE: Fix KCK, PMK, and PMKID derivation for groups 22, 23, 24
c65168ccd OpenSSL: Fix crypto_bignum_to_bin() with padlen == 0
cb28bd52e nl80211: Use separate flag for 4-way handshake offload
6bb11c7a4 EAP-SIM/AKA server: Allow pseudonym/fast reauth to be disabled
c1b236521 EAP-SIM/AKA: Do not allow anonymous@realm "pseudonym" to be cleared
cc2fd9425 D-Bus: Demote timeout/flush messages to MSG_MSGDUMP
3b726df82 nl80211: Missing sysctl flags aren't fatal
f4111ff3d Extra RADIUS request attributes from SQLite
74707def8 Move hostapd_parse_radius_attr() into ap_config.c
1e5ea68d1 mka: Accept last two used MNs in Peers List of a received MKPDU
013686403 P2P: Pass HE flag to GO negotiation result
876c5eaa6 dragonfly: Disable use of groups using Brainpool curves
968520da8 nl80211: Add WMM parameters while updating TDLS peer entry
5a511924b wpa_cli: Add support to process DPP action events in action script
64e37be94 Avoid nested enum wpas_mode declaration to allow C++ compilation
fe2e1edf4 EAP-SIM server: Avoid void pointer arithmetic
cfc9ebea0 EAP-AKA server: Avoid void pointer arithmetic
bd0414043 trace: Avoid void pointer arithmetic
fc03ea2c1 DPP: Avoid void pointer arithmetic
d1b1f9fa9 Report WPA/RSN protocol and AKM suite selector in STA MIB
43aafef8d Add missed wpa_akm_to_suite() selectors
bfb6a482f dragonfly: SAE/EAP-pwd min PWE derivation iteration count to shared code
226da33d7 EAP-pwd peer: Configurable set of groups with reduced default
6a4406c01 Add QCA vendor attributes for ELNA bypass
176c133e9 Add a vendor attribute to configure disconnect IEs
123895228 Add QCA vendor command to support OEM data

Change-Id: Iaa497edcda7c5dcdad19db9d09ab09ef74e508bd
diff --git a/src/common/Makefile b/src/common/Makefile
index e703630..ccb280e 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -9,7 +9,6 @@
 include ../lib.rules
 
 CFLAGS += -DCONFIG_IEEE80211R
-CFLAGS += -DCONFIG_IEEE80211W
 CFLAGS += -DCONFIG_HS20
 CFLAGS += -DCONFIG_SAE
 CFLAGS += -DCONFIG_SUITE
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 30c5247..fb0cf43 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/module_tests.h"
 #include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
 #include "ieee802_11_common.h"
 #include "ieee802_11_defs.h"
 #include "gas.h"
@@ -258,6 +259,7 @@
 	/* IEEE P802.11-REVmd/D2.1, Annex J.10 */
 	const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 };
 	const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 };
+	const char *ssid = "byteme";
 	const char *pw = "mekmitasdigoat";
 	const char *pwid = "psk4internet";
 	const u8 local_rand[] = {
@@ -338,6 +340,72 @@
 	};
 	struct wpabuf *buf = NULL;
 	struct crypto_bignum *mask = NULL;
+	const u8 pwe_19_x[32] = {
+		0x19, 0xd3, 0x37, 0xc9, 0x30, 0x79, 0x2b, 0x47,
+		0x2b, 0x14, 0x5f, 0xc1, 0x5b, 0x98, 0x64, 0x0a,
+		0x0e, 0x7d, 0x3b, 0xb0, 0x7d, 0xc0, 0xad, 0xee,
+		0x6f, 0xc9, 0xdf, 0x75, 0xde, 0xc2, 0xd6, 0x94
+	};
+	const u8 pwe_19_y[32] = {
+		0xb7, 0x8a, 0x02, 0x39, 0x20, 0x29, 0xe7, 0xf4,
+		0x52, 0x41, 0x3d, 0x35, 0x8c, 0x88, 0xd9, 0x16,
+		0xc8, 0x90, 0xba, 0x40, 0xd9, 0x93, 0xe3, 0x2d,
+		0xd0, 0x0f, 0xfb, 0x58, 0xee, 0x62, 0x74, 0x98
+	};
+	const u8 pwe_15[384] = {
+		0x59, 0x00, 0x9a, 0x32, 0xbb, 0x37, 0x84, 0x60,
+		0x27, 0xeb, 0x70, 0x20, 0x57, 0x34, 0xf1, 0xb4,
+		0xde, 0x1b, 0x48, 0xfc, 0x0e, 0xa5, 0xb8, 0x65,
+		0xb1, 0xa0, 0xd4, 0xb9, 0x42, 0x1d, 0x6d, 0xdf,
+		0x8b, 0x86, 0xeb, 0x4a, 0x2c, 0x2e, 0x38, 0x06,
+		0x52, 0xae, 0x67, 0x39, 0xed, 0x7d, 0x0c, 0xd0,
+		0xea, 0x30, 0x6e, 0x50, 0xe7, 0xb1, 0x8d, 0x91,
+		0xf0, 0x05, 0x1f, 0x16, 0xf5, 0x45, 0xa7, 0x37,
+		0x21, 0x0d, 0x8a, 0x69, 0x9a, 0xd1, 0xf1, 0x8c,
+		0x2b, 0xbb, 0xd8, 0x21, 0xa2, 0x8f, 0xcc, 0xd1,
+		0x35, 0x98, 0x66, 0xf3, 0x3c, 0x03, 0xba, 0x70,
+		0x72, 0x4e, 0xe4, 0x23, 0xb5, 0x2e, 0x96, 0x5f,
+		0xdd, 0xd1, 0xae, 0x71, 0xb1, 0xc1, 0x4b, 0x69,
+		0x4e, 0x60, 0x0a, 0x08, 0x02, 0xa1, 0x6e, 0x80,
+		0x68, 0x0a, 0xe7, 0x97, 0x9f, 0x5b, 0xbf, 0xa8,
+		0x77, 0xda, 0x5b, 0x26, 0x13, 0x0a, 0xab, 0x92,
+		0x79, 0x87, 0xa3, 0x85, 0x78, 0x74, 0xae, 0xae,
+		0x01, 0xf0, 0x31, 0x8a, 0xc3, 0x96, 0xce, 0xaa,
+		0x57, 0xbf, 0xb3, 0x57, 0xce, 0x2d, 0x2d, 0x36,
+		0xda, 0x02, 0x5b, 0x12, 0xeb, 0xff, 0x13, 0x00,
+		0x9e, 0xf7, 0xae, 0xe0, 0x47, 0xa4, 0x5d, 0x0a,
+		0x88, 0x65, 0xbc, 0x66, 0x23, 0x3e, 0xf2, 0xf1,
+		0xa0, 0x64, 0x5c, 0x6b, 0xdc, 0x81, 0xe9, 0x3c,
+		0x46, 0x4f, 0x83, 0xcf, 0x9f, 0x55, 0x33, 0x8f,
+		0xaa, 0x60, 0x4b, 0xd7, 0x21, 0x73, 0x6b, 0xdb,
+		0x26, 0xad, 0x2f, 0xb7, 0xe2, 0x42, 0x56, 0x33,
+		0xdb, 0xd6, 0xb2, 0x3a, 0x7d, 0x75, 0x87, 0xda,
+		0x86, 0xc4, 0xe9, 0x41, 0x8d, 0x63, 0x19, 0x8e,
+		0x8b, 0x17, 0x95, 0xfe, 0x2b, 0x96, 0xa0, 0x38,
+		0xf1, 0xe2, 0x1d, 0x42, 0xa9, 0xe3, 0x8a, 0xa1,
+		0x61, 0x62, 0x10, 0xf8, 0xb3, 0xb2, 0x2c, 0x7b,
+		0xdf, 0xba, 0x74, 0xb2, 0x5b, 0xf6, 0xa9, 0xae,
+		0x1d, 0x21, 0x0d, 0xc0, 0x48, 0x20, 0xfc, 0x28,
+		0xf6, 0x22, 0xd2, 0xf6, 0x9c, 0x71, 0x3f, 0x9f,
+		0x32, 0xd6, 0xbb, 0x9b, 0xd3, 0x87, 0x25, 0xcf,
+		0x62, 0xd1, 0x68, 0xba, 0x55, 0x3b, 0x74, 0x2b,
+		0x1d, 0x5a, 0xe4, 0x94, 0x59, 0x3b, 0x13, 0x21,
+		0x15, 0x87, 0x3b, 0x09, 0x0e, 0xcf, 0x35, 0x60,
+		0x04, 0xa8, 0xde, 0xa1, 0x09, 0xca, 0xb8, 0x35,
+		0x1e, 0x16, 0x61, 0xed, 0xa1, 0x1f, 0x8c, 0x92,
+		0x83, 0xa5, 0x27, 0x92, 0xf2, 0x80, 0xc3, 0xcb,
+		0xdd, 0x3c, 0x0c, 0xf5, 0x8d, 0x69, 0xb3, 0xe4,
+		0xd5, 0x49, 0x4d, 0x62, 0xcb, 0xb8, 0xe3, 0x9f,
+		0x89, 0xb5, 0x57, 0xff, 0xef, 0x12, 0x37, 0x05,
+		0xb6, 0x35, 0xe5, 0xc6, 0xd9, 0x23, 0xe2, 0xeb,
+		0xe4, 0x0d, 0x1a, 0x30, 0x8f, 0x73, 0x70, 0x3a,
+		0xef, 0x5a, 0xd1, 0x8c, 0x18, 0x34, 0x1e, 0xf0,
+		0xb9, 0x08, 0x57, 0xab, 0xcb, 0x5c, 0x87, 0x10
+	};
+	int pt_groups[] = { 19, 20, 21, 25, 26, 28, 29, 30, 15, 0 };
+	struct sae_pt *pt_info, *pt;
+	u8 addr1b[ETH_ALEN] = { 0x3b, 0x36, 0xc2, 0x8b, 0x83, 0x03 };
+	u8 addr2b[ETH_ALEN] = { 0x58, 0x36, 0xc0, 0x64, 0x2d, 0x31 };
 
 	os_memset(&sae, 0, sizeof(sae));
 	buf = wpabuf_alloc(1000);
@@ -377,7 +445,7 @@
 	}
 
 	if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
-		    NULL) != 0 ||
+			     NULL, 0) != 0 ||
 	    sae_process_commit(&sae) < 0)
 		goto fail;
 
@@ -411,6 +479,62 @@
 	if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
 		goto fail;
 
+	pt_info = sae_derive_pt(pt_groups,
+				(const u8 *) ssid, os_strlen(ssid),
+				(const u8 *) pw, os_strlen(pw), pwid);
+	if (!pt_info)
+		goto fail;
+
+	for (pt = pt_info; pt; pt = pt->next) {
+		if (pt->group == 19) {
+			struct crypto_ec_point *pwe;
+			u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+			size_t prime_len = sizeof(pwe_19_x);
+
+			pwe = sae_derive_pwe_from_pt_ecc(pt, addr1b, addr2b);
+			if (!pwe) {
+				sae_deinit_pt(pt);
+				goto fail;
+			}
+			if (crypto_ec_point_to_bin(pt->ec, pwe, bin,
+						   bin + prime_len) < 0 ||
+			    os_memcmp(pwe_19_x, bin, prime_len) != 0 ||
+			    os_memcmp(pwe_19_y, bin + prime_len,
+				      prime_len) != 0) {
+				wpa_printf(MSG_ERROR,
+					   "SAE: PT/PWE test vector mismatch");
+				crypto_ec_point_deinit(pwe, 1);
+				sae_deinit_pt(pt);
+				goto fail;
+			}
+			crypto_ec_point_deinit(pwe, 1);
+		}
+
+		if (pt->group == 15) {
+			struct crypto_bignum *pwe;
+			u8 bin[SAE_MAX_PRIME_LEN];
+			size_t prime_len = sizeof(pwe_15);
+
+			pwe = sae_derive_pwe_from_pt_ffc(pt, addr1b, addr2b);
+			if (!pwe) {
+				sae_deinit_pt(pt);
+				goto fail;
+			}
+			if (crypto_bignum_to_bin(pwe, bin, sizeof(bin),
+						 prime_len) < 0 ||
+			    os_memcmp(pwe_15, bin, prime_len) != 0) {
+				wpa_printf(MSG_ERROR,
+					   "SAE: PT/PWE test vector mismatch");
+				crypto_bignum_deinit(pwe, 1);
+				sae_deinit_pt(pt);
+				goto fail;
+			}
+			crypto_bignum_deinit(pwe, 1);
+		}
+	}
+
+	sae_deinit_pt(pt_info);
+
 	ret = 0;
 fail:
 	sae_clear_data(&sae);
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 3eb86c5..ab7072c 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -610,6 +610,91 @@
 }
 
 
+static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
+		    u8 *secret, size_t *secret_len)
+{
+	EVP_PKEY_CTX *ctx;
+	int ret = -1;
+
+	ERR_clear_error();
+	*secret_len = 0;
+
+	ctx = EVP_PKEY_CTX_new(own, NULL);
+	if (!ctx) {
+		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	if (EVP_PKEY_derive_init(ctx) != 1) {
+		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto fail;
+	}
+
+	if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
+		wpa_printf(MSG_ERROR,
+			   "DPP: EVP_PKEY_derive_set_peet failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto fail;
+	}
+
+	if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
+		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto fail;
+	}
+
+	if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+		u8 buf[200];
+		int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
+
+		/* It looks like OpenSSL can return unexpectedly large buffer
+		 * need for shared secret from EVP_PKEY_derive(NULL) in some
+		 * cases. For example, group 19 has shown cases where secret_len
+		 * is set to 72 even though the actual length ends up being
+		 * updated to 32 when EVP_PKEY_derive() is called with a buffer
+		 * for the value. Work around this by trying to fetch the value
+		 * and continue if it is within supported range even when the
+		 * initial buffer need is claimed to be larger. */
+		wpa_printf(level,
+			   "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+			   (int) *secret_len);
+		if (*secret_len > 200)
+			goto fail;
+		if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
+			wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+				   ERR_error_string(ERR_get_error(), NULL));
+			goto fail;
+		}
+		if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+			wpa_printf(MSG_ERROR,
+				   "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+				   (int) *secret_len);
+			goto fail;
+		}
+		wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
+				buf, *secret_len);
+		os_memcpy(secret, buf, *secret_len);
+		forced_memzero(buf, sizeof(buf));
+		goto done;
+	}
+
+	if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
+		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto fail;
+	}
+
+done:
+	ret = 0;
+
+fail:
+	EVP_PKEY_CTX_free(ctx);
+	return ret;
+}
+
+
 static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
 {
 	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
@@ -657,6 +742,34 @@
 }
 
 
+static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
+				    u16 req_id, u16 *ret_len)
+{
+	u16 id, alen;
+	const u8 *pos, *end = buf + len;
+
+	if (!prev)
+		pos = buf;
+	else
+		pos = prev + WPA_GET_LE16(prev - 2);
+	while (end - pos >= 4) {
+		id = WPA_GET_LE16(pos);
+		pos += 2;
+		alen = WPA_GET_LE16(pos);
+		pos += 2;
+		if (alen > end - pos)
+			return NULL;
+		if (id == req_id) {
+			*ret_len = alen;
+			return pos;
+		}
+		pos += alen;
+	}
+
+	return NULL;
+}
+
+
 int dpp_check_attrs(const u8 *buf, size_t len)
 {
 	const u8 *pos, *end;
@@ -2142,7 +2255,6 @@
 {
 	struct dpp_authentication *auth;
 	size_t nonce_len;
-	EVP_PKEY_CTX *ctx = NULL;
 	size_t secret_len;
 	struct wpabuf *pi = NULL;
 	const u8 *r_pubkey_hash, *i_pubkey_hash;
@@ -2211,21 +2323,10 @@
 		goto fail;
 
 	/* ECDH: M = pI * BR */
-	ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
-	    secret_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
+		     auth->Mx, &secret_len) < 0)
 		goto fail;
-	}
 	auth->secret_len = secret_len;
-	EVP_PKEY_CTX_free(ctx);
-	ctx = NULL;
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
 			auth->Mx, auth->secret_len);
@@ -2277,7 +2378,6 @@
 
 out:
 	wpabuf_free(pi);
-	EVP_PKEY_CTX_free(ctx);
 	return auth;
 fail:
 	dpp_auth_deinit(auth);
@@ -2304,7 +2404,7 @@
 	}
 	wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
 	json_len = os_strlen(json);
-	wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
 
 	/* { E-nonce, configAttrib }ke */
 	clear_len = 4 + nonce_len + 4 + json_len;
@@ -2440,6 +2540,67 @@
 }
 
 
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+					  const char *name, int netrole_ap,
+					  const char *mud_url, int *opclasses)
+{
+	size_t len, nlen;
+	const char *tech = "infra";
+	const char *dpp_name;
+	char *nbuf;
+	struct wpabuf *buf, *json;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+		static const char *bogus_tech = "knfra";
+
+		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+		tech = bogus_tech;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	dpp_name = name ? name : "Test";
+	len = os_strlen(dpp_name);
+	nlen = len * 6 + 1;
+	nbuf = os_malloc(nlen);
+	if (!nbuf)
+		return NULL;
+	json_escape_string(nbuf, nlen, dpp_name, len);
+
+	len = 100 + os_strlen(nbuf) + int_array_len(opclasses) * 4;
+	if (mud_url && mud_url[0])
+		len += 10 + os_strlen(mud_url);
+	json = wpabuf_alloc(len);
+	if (!json) {
+		os_free(nbuf);
+		return NULL;
+	}
+
+	wpabuf_printf(json,
+		      "{\"name\":\"%s\","
+		      "\"wi-fi_tech\":\"%s\","
+		      "\"netRole\":\"%s\"",
+		      nbuf, tech, netrole_ap ? "ap" : "sta");
+	if (mud_url && mud_url[0])
+		wpabuf_printf(json, ",\"mudurl\":\"%s\"", mud_url);
+	if (opclasses) {
+		int i;
+
+		wpabuf_put_str(json, ",\"bandSupport\":[");
+		for (i = 0; opclasses[i]; i++)
+			wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
+		wpabuf_put_str(json, "]");
+	}
+	wpabuf_put_str(json, "}");
+	os_free(nbuf);
+
+	buf = dpp_build_conf_req(auth, wpabuf_head(json));
+	wpabuf_free(json);
+
+	return buf;
+}
+
+
 static void dpp_auth_success(struct dpp_authentication *auth)
 {
 	wpa_printf(MSG_DEBUG,
@@ -2750,7 +2911,6 @@
 static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
 {
 	size_t nonce_len;
-	EVP_PKEY_CTX *ctx = NULL;
 	size_t secret_len;
 	struct wpabuf *msg, *pr = NULL;
 	u8 r_auth[4 + DPP_MAX_HASH_LEN];
@@ -2813,20 +2973,9 @@
 		goto fail;
 
 	/* ECDH: N = pR * PI */
-	ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
-	    secret_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
+		     auth->Nx, &secret_len) < 0)
 		goto fail;
-	}
-	EVP_PKEY_CTX_free(ctx);
-	ctx = NULL;
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
 			auth->Nx, auth->secret_len);
@@ -3122,22 +3271,9 @@
 	}
 	dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
 
-	ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
-	    secret_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
-		dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
+	if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
 		goto fail;
-	}
 	auth->secret_len = secret_len;
-	EVP_PKEY_CTX_free(ctx);
-	ctx = NULL;
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
 			auth->Mx, auth->secret_len);
@@ -3591,7 +3727,6 @@
 		 const u8 *attr_start, size_t attr_len)
 {
 	EVP_PKEY *pr;
-	EVP_PKEY_CTX *ctx = NULL;
 	size_t secret_len;
 	const u8 *addr[2];
 	size_t len[2];
@@ -3741,21 +3876,10 @@
 	}
 	dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
 
-	ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
-	    secret_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
 		dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
 		goto fail;
 	}
-	EVP_PKEY_CTX_free(ctx);
-	ctx = NULL;
 	EVP_PKEY_free(auth->peer_protocol_key);
 	auth->peer_protocol_key = pr;
 	pr = NULL;
@@ -3927,7 +4051,6 @@
 	bin_clear_free(unwrapped, unwrapped_len);
 	bin_clear_free(unwrapped2, unwrapped2_len);
 	EVP_PKEY_free(pr);
-	EVP_PKEY_CTX_free(ctx);
 	return NULL;
 }
 
@@ -4265,8 +4388,8 @@
 }
 
 
-static int dpp_configuration_parse(struct dpp_authentication *auth,
-				   const char *cmd)
+static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
+					  const char *cmd, int idx)
 {
 	const char *pos, *end;
 	struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
@@ -4277,6 +4400,7 @@
 		conf_sta = dpp_configuration_alloc(pos + 10);
 		if (!conf_sta)
 			goto fail;
+		conf_sta->netrole = DPP_NETROLE_STA;
 		conf = conf_sta;
 	}
 
@@ -4285,6 +4409,7 @@
 		conf_ap = dpp_configuration_alloc(pos + 9);
 		if (!conf_ap)
 			goto fail;
+		conf_ap->netrole = DPP_NETROLE_AP;
 		conf = conf_ap;
 	}
 
@@ -4362,8 +4487,15 @@
 	if (!dpp_configuration_valid(conf))
 		goto fail;
 
-	auth->conf_sta = conf_sta;
-	auth->conf_ap = conf_ap;
+	if (idx == 0) {
+		auth->conf_sta = conf_sta;
+		auth->conf_ap = conf_ap;
+	} else if (idx == 1) {
+		auth->conf2_sta = conf_sta;
+		auth->conf2_ap = conf_ap;
+	} else {
+		goto fail;
+	}
 	return 0;
 
 fail:
@@ -4373,6 +4505,41 @@
 }
 
 
+static int dpp_configuration_parse(struct dpp_authentication *auth,
+				   const char *cmd)
+{
+	const char *pos;
+	char *tmp;
+	size_t len;
+	int res;
+
+	pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
+	if (!pos)
+		return dpp_configuration_parse_helper(auth, cmd, 0);
+
+	len = pos - cmd;
+	tmp = os_malloc(len + 1);
+	if (!tmp)
+		goto fail;
+	os_memcpy(tmp, cmd, len);
+	tmp[len] = '\0';
+	res = dpp_configuration_parse_helper(auth, cmd, 0);
+	str_clear_free(tmp);
+	if (res)
+		goto fail;
+	res = dpp_configuration_parse_helper(auth, cmd + len, 1);
+	if (res)
+		goto fail;
+	return 0;
+fail:
+	dpp_configuration_free(auth->conf_sta);
+	dpp_configuration_free(auth->conf2_sta);
+	dpp_configuration_free(auth->conf_ap);
+	dpp_configuration_free(auth->conf2_ap);
+	return -1;
+}
+
+
 static struct dpp_configurator *
 dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
 {
@@ -4412,6 +4579,18 @@
 		}
 	}
 
+	pos = os_strstr(cmd, " conn_status=");
+	if (pos) {
+		pos += 13;
+		auth->send_conn_status = atoi(pos);
+	}
+
+	pos = os_strstr(cmd, " akm_use_selector=");
+	if (pos) {
+		pos += 18;
+		auth->akm_use_selector = atoi(pos);
+	}
+
 	if (dpp_configuration_parse(auth, cmd) < 0) {
 		wpa_msg(msg_ctx, MSG_INFO,
 			"DPP: Failed to set configurator parameters");
@@ -4423,18 +4602,26 @@
 
 void dpp_auth_deinit(struct dpp_authentication *auth)
 {
+	unsigned int i;
+
 	if (!auth)
 		return;
 	dpp_configuration_free(auth->conf_ap);
+	dpp_configuration_free(auth->conf2_ap);
 	dpp_configuration_free(auth->conf_sta);
+	dpp_configuration_free(auth->conf2_sta);
 	EVP_PKEY_free(auth->own_protocol_key);
 	EVP_PKEY_free(auth->peer_protocol_key);
 	wpabuf_free(auth->req_msg);
 	wpabuf_free(auth->resp_msg);
 	wpabuf_free(auth->conf_req);
-	os_free(auth->connector);
+	for (i = 0; i < auth->num_conf_obj; i++) {
+		struct dpp_config_obj *conf = &auth->conf_obj[i];
+
+		os_free(conf->connector);
+		wpabuf_free(conf->c_sign_key);
+	}
 	wpabuf_free(auth->net_access_key);
-	wpabuf_free(auth->c_sign_key);
 	dpp_bootstrap_info_free(auth->tmp_own_bi);
 #ifdef CONFIG_TESTING_OPTIONS
 	os_free(auth->config_obj_override);
@@ -4545,8 +4732,21 @@
 }
 
 
+static const char * dpp_netrole_str(enum dpp_netrole netrole)
+{
+	switch (netrole) {
+	case DPP_NETROLE_STA:
+		return "sta";
+	case DPP_NETROLE_AP:
+		return "ap";
+	default:
+		return "??";
+	}
+}
+
+
 static struct wpabuf *
-dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
 		       struct dpp_configuration *conf)
 {
 	struct wpabuf *buf = NULL;
@@ -4567,6 +4767,7 @@
 	size_t extra_len = 1000;
 	int incl_legacy;
 	enum dpp_akm akm;
+	const char *akm_str;
 
 	if (!auth->conf) {
 		wpa_printf(MSG_INFO,
@@ -4620,7 +4821,8 @@
 #endif /* CONFIG_TESTING_OPTIONS */
 	wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
 		      conf->group_id ? conf->group_id : "*");
-	wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
+	wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],",
+		      dpp_netrole_str(conf->netrole));
 #ifdef CONFIG_TESTING_OPTIONS
 skip_groups:
 #endif /* CONFIG_TESTING_OPTIONS */
@@ -4719,7 +4921,11 @@
 	if (!buf)
 		goto fail;
 
-	wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
+	if (auth->akm_use_selector && dpp_akm_ver2(akm))
+		akm_str = dpp_akm_selector_str(akm);
+	else
+		akm_str = dpp_akm_str(akm);
+	wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
 	if (incl_legacy) {
 		dpp_build_legacy_cred_params(buf, conf);
 		wpabuf_put_str(buf, ",");
@@ -4760,16 +4966,21 @@
 
 
 static struct wpabuf *
-dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
 			  struct dpp_configuration *conf)
 {
 	struct wpabuf *buf;
+	const char *akm_str;
 
 	buf = dpp_build_conf_start(auth, conf, 1000);
 	if (!buf)
 		return NULL;
 
-	wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
+	if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
+		akm_str = dpp_akm_selector_str(conf->akm);
+	else
+		akm_str = dpp_akm_str(conf->akm);
+	wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
 	dpp_build_legacy_cred_params(buf, conf);
 	wpabuf_put_str(buf, "}}");
 
@@ -4781,29 +4992,37 @@
 
 
 static struct wpabuf *
-dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
+dpp_build_conf_obj(struct dpp_authentication *auth, int ap, int idx)
 {
 	struct dpp_configuration *conf;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	if (auth->config_obj_override) {
+		if (idx != 0)
+			return NULL;
 		wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
 		return wpabuf_alloc_copy(auth->config_obj_override,
 					 os_strlen(auth->config_obj_override));
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
-	conf = ap ? auth->conf_ap : auth->conf_sta;
+	if (idx == 0)
+		conf = ap ? auth->conf_ap : auth->conf_sta;
+	else if (idx == 1)
+		conf = ap ? auth->conf2_ap : auth->conf2_sta;
+	else
+		conf = NULL;
 	if (!conf) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: No configuration available for Enrollee(%s) - reject configuration request",
-			   ap ? "ap" : "sta");
+		if (idx == 0)
+			wpa_printf(MSG_DEBUG,
+				   "DPP: No configuration available for Enrollee(%s) - reject configuration request",
+				   ap ? "ap" : "sta");
 		return NULL;
 	}
 
 	if (dpp_akm_dpp(conf->akm))
-		return dpp_build_conf_obj_dpp(auth, ap, conf);
-	return dpp_build_conf_obj_legacy(auth, ap, conf);
+		return dpp_build_conf_obj_dpp(auth, conf);
+	return dpp_build_conf_obj_legacy(auth, conf);
 }
 
 
@@ -4811,7 +5030,7 @@
 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
 		    u16 e_nonce_len, int ap)
 {
-	struct wpabuf *conf;
+	struct wpabuf *conf, *conf2 = NULL;
 	size_t clear_len, attr_len;
 	struct wpabuf *clear = NULL, *msg = NULL;
 	u8 *wrapped;
@@ -4819,18 +5038,23 @@
 	size_t len[1];
 	enum dpp_status_error status;
 
-	conf = dpp_build_conf_obj(auth, ap);
+	conf = dpp_build_conf_obj(auth, ap, 0);
 	if (conf) {
 		wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
 				  wpabuf_head(conf), wpabuf_len(conf));
+		conf2 = dpp_build_conf_obj(auth, ap, 1);
 	}
 	status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
 	auth->conf_resp_status = status;
 
-	/* { E-nonce, configurationObject}ke */
+	/* { E-nonce, configurationObject[, sendConnStatus]}ke */
 	clear_len = 4 + e_nonce_len;
 	if (conf)
 		clear_len += 4 + wpabuf_len(conf);
+	if (conf2)
+		clear_len += 4 + wpabuf_len(conf2);
+	if (auth->peer_version >= 2 && auth->send_conn_status && !ap)
+		clear_len += 4;
 	clear = wpabuf_alloc(clear_len);
 	attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
 #ifdef CONFIG_TESTING_OPTIONS
@@ -4878,6 +5102,20 @@
 		wpabuf_put_le16(clear, wpabuf_len(conf));
 		wpabuf_put_buf(clear, conf);
 	}
+	if (auth->peer_version >= 2 && conf2) {
+		wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
+		wpabuf_put_le16(clear, wpabuf_len(conf2));
+		wpabuf_put_buf(clear, conf2);
+	} else if (conf2) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Second Config Object available, but peer does not support more than one");
+	}
+
+	if (auth->peer_version >= 2 && auth->send_conn_status && !ap) {
+		wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
+		wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
+		wpabuf_put_le16(clear, 0);
+	}
 
 #ifdef CONFIG_TESTING_OPTIONS
 skip_config_obj:
@@ -4926,6 +5164,7 @@
 			"DPP: Configuration Response attributes", msg);
 out:
 	wpabuf_free(conf);
+	wpabuf_free(conf2);
 	wpabuf_free(clear);
 
 	return msg;
@@ -5054,6 +5293,26 @@
 		goto fail;
 	}
 
+	token = json_get_member(root, "mudurl");
+	if (token && token->type == JSON_STRING)
+		wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
+
+	token = json_get_member(root, "bandSupport");
+	if (token && token->type == JSON_ARRAY) {
+		wpa_printf(MSG_DEBUG, "DPP: bandSupport");
+		token = token->child;
+		while (token) {
+			if (token->type != JSON_NUMBER)
+				wpa_printf(MSG_DEBUG,
+					   "DPP: Invalid bandSupport array member type");
+			else
+				wpa_printf(MSG_DEBUG,
+					   "DPP: Supported global operating class: %d",
+					   token->number);
+			token = token->sibling;
+		}
+	}
+
 	resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
 
 fail:
@@ -5143,7 +5402,7 @@
 }
 
 
-static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
+static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
 				 struct json_token *cred)
 {
 	struct json_token *pass, *psk_hex;
@@ -5160,28 +5419,28 @@
 				      pass->string, len);
 		if (len < 8 || len > 63)
 			return -1;
-		os_strlcpy(auth->passphrase, pass->string,
-			   sizeof(auth->passphrase));
+		os_strlcpy(conf->passphrase, pass->string,
+			   sizeof(conf->passphrase));
 	} else if (psk_hex && psk_hex->type == JSON_STRING) {
-		if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
+		if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
 			wpa_printf(MSG_DEBUG,
 				   "DPP: Unexpected psk_hex with akm=sae");
 			return -1;
 		}
 		if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
-		    hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
+		    hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
 			wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
 			return -1;
 		}
 		wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
-				auth->psk, PMK_LEN);
-		auth->psk_set = 1;
+				conf->psk, PMK_LEN);
+		conf->psk_set = 1;
 	} else {
 		wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
 		return -1;
 	}
 
-	if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
+	if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
 		wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
 		return -1;
 	}
@@ -5349,6 +5608,7 @@
 
 
 static int dpp_parse_connector(struct dpp_authentication *auth,
+			       struct dpp_config_obj *conf,
 			       const unsigned char *payload,
 			       u16 payload_len)
 {
@@ -5476,7 +5736,7 @@
 }
 
 
-static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
+static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
 {
 	unsigned char *der = NULL;
 	int der_len;
@@ -5484,13 +5744,14 @@
 	der_len = i2d_PUBKEY(csign, &der);
 	if (der_len <= 0)
 		return;
-	wpabuf_free(auth->c_sign_key);
-	auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
+	wpabuf_free(conf->c_sign_key);
+	conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
 	OPENSSL_free(der);
 }
 
 
-static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
+static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
+				  struct dpp_config_obj *conf)
 {
 	unsigned char *der = NULL;
 	int der_len;
@@ -5684,6 +5945,7 @@
 
 
 static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
+			      struct dpp_config_obj *conf,
 			      struct json_token *cred)
 {
 	struct dpp_signed_connector_info info;
@@ -5695,10 +5957,10 @@
 
 	os_memset(&info, 0, sizeof(info));
 
-	if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
+	if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Legacy credential included in Connector credential");
-		if (dpp_parse_cred_legacy(auth, cred) < 0)
+		if (dpp_parse_cred_legacy(conf, cred) < 0)
 			return -1;
 	}
 
@@ -5737,16 +5999,17 @@
 					 signed_connector) != DPP_STATUS_OK)
 		goto fail;
 
-	if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
+	if (dpp_parse_connector(auth, conf,
+				info.payload, info.payload_len) < 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
 		goto fail;
 	}
 
-	os_free(auth->connector);
-	auth->connector = os_strdup(signed_connector);
+	os_free(conf->connector);
+	conf->connector = os_strdup(signed_connector);
 
-	dpp_copy_csign(auth, csign_pub);
-	dpp_copy_netaccesskey(auth);
+	dpp_copy_csign(conf, csign_pub);
+	dpp_copy_netaccesskey(auth, conf);
 
 	ret = 0;
 fail:
@@ -5777,8 +6040,32 @@
 }
 
 
+const char * dpp_akm_selector_str(enum dpp_akm akm)
+{
+	switch (akm) {
+	case DPP_AKM_DPP:
+		return "506F9A02";
+	case DPP_AKM_PSK:
+		return "000FAC02+000FAC06";
+	case DPP_AKM_SAE:
+		return "000FAC08";
+	case DPP_AKM_PSK_SAE:
+		return "000FAC02+000FAC06+000FAC08";
+	case DPP_AKM_SAE_DPP:
+		return "506F9A02+000FAC08";
+	case DPP_AKM_PSK_SAE_DPP:
+		return "506F9A02+000FAC08+000FAC02+000FAC06";
+	default:
+		return "??";
+	}
+}
+
+
 static enum dpp_akm dpp_akm_from_str(const char *akm)
 {
+	const char *pos;
+	int dpp = 0, psk = 0, sae = 0;
+
 	if (os_strcmp(akm, "psk") == 0)
 		return DPP_AKM_PSK;
 	if (os_strcmp(akm, "sae") == 0)
@@ -5791,6 +6078,38 @@
 		return DPP_AKM_SAE_DPP;
 	if (os_strcmp(akm, "dpp+psk+sae") == 0)
 		return DPP_AKM_PSK_SAE_DPP;
+
+	pos = akm;
+	while (*pos) {
+		if (os_strlen(pos) < 8)
+			break;
+		if (os_strncasecmp(pos, "506F9A02", 8) == 0)
+			dpp = 1;
+		else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
+			psk = 1;
+		else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
+			psk = 1;
+		else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
+			sae = 1;
+		pos += 8;
+		if (*pos != '+')
+			break;
+		pos++;
+	}
+
+	if (dpp && psk && sae)
+		return DPP_AKM_PSK_SAE_DPP;
+	if (dpp && sae)
+		return DPP_AKM_SAE_DPP;
+	if (dpp)
+		return DPP_AKM_DPP;
+	if (psk && sae)
+		return DPP_AKM_PSK_SAE;
+	if (sae)
+		return DPP_AKM_SAE;
+	if (psk)
+		return DPP_AKM_PSK;
+
 	return DPP_AKM_UNKNOWN;
 }
 
@@ -5800,6 +6119,7 @@
 {
 	int ret = -1;
 	struct json_token *root, *token, *discovery, *cred;
+	struct dpp_config_obj *conf;
 
 	root = json_parse((const char *) conf_obj, conf_obj_len);
 	if (!root)
@@ -5838,8 +6158,17 @@
 		dpp_auth_fail(auth, "Too long discovery::ssid string value");
 		goto fail;
 	}
-	auth->ssid_len = os_strlen(token->string);
-	os_memcpy(auth->ssid, token->string, auth->ssid_len);
+
+	if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No room for this many Config Objects - ignore this one");
+		json_free(root);
+		return 0;
+	}
+	conf = &auth->conf_obj[auth->num_conf_obj++];
+
+	conf->ssid_len = os_strlen(token->string);
+	os_memcpy(conf->ssid, token->string, conf->ssid_len);
 
 	cred = json_get_member(root, "cred");
 	if (!cred || cred->type != JSON_OBJECT) {
@@ -5852,13 +6181,13 @@
 		dpp_auth_fail(auth, "No cred::akm string value found");
 		goto fail;
 	}
-	auth->akm = dpp_akm_from_str(token->string);
+	conf->akm = dpp_akm_from_str(token->string);
 
-	if (dpp_akm_legacy(auth->akm)) {
-		if (dpp_parse_cred_legacy(auth, cred) < 0)
+	if (dpp_akm_legacy(conf->akm)) {
+		if (dpp_parse_cred_legacy(conf, cred) < 0)
 			goto fail;
-	} else if (dpp_akm_dpp(auth->akm)) {
-		if (dpp_parse_cred_dpp(auth, cred) < 0)
+	} else if (dpp_akm_dpp(conf->akm)) {
+		if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
 			goto fail;
 	} else {
 		wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
@@ -5955,17 +6284,32 @@
 		goto fail;
 	}
 
-	conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
-				DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
+	conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
+				&conf_obj_len);
 	if (!conf_obj) {
 		dpp_auth_fail(auth,
 			      "Missing required Configuration Object attribute");
 		goto fail;
 	}
-	wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
-			  conf_obj, conf_obj_len);
-	if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
-		goto fail;
+	while (conf_obj) {
+		wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
+				  conf_obj, conf_obj_len);
+		if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
+			goto fail;
+		conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
+					     DPP_ATTR_CONFIG_OBJ,
+					     &conf_obj_len);
+	}
+
+#ifdef CONFIG_DPP2
+	status = dpp_get_attr(unwrapped, unwrapped_len,
+			      DPP_ATTR_SEND_CONN_STATUS, &status_len);
+	if (status) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Configurator requested connection status result");
+		auth->conn_status_requested = 1;
+	}
+#endif /* CONFIG_DPP2 */
 
 	ret = 0;
 
@@ -5976,6 +6320,7 @@
 
 
 #ifdef CONFIG_DPP2
+
 enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
 					 const u8 *hdr,
 					 const u8 *attr_start, size_t attr_len)
@@ -6056,7 +6401,6 @@
 	bin_clear_free(unwrapped, unwrapped_len);
 	return ret;
 }
-#endif /* CONFIG_DPP2 */
 
 
 struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
@@ -6074,7 +6418,7 @@
 	clear = wpabuf_alloc(clear_len);
 	msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
 	if (!clear || !msg)
-		return NULL;
+		goto fail;
 
 	/* DPP Status */
 	dpp_build_attr_status(clear, status);
@@ -6115,6 +6459,219 @@
 }
 
 
+static int valid_channel_list(const char *val)
+{
+	while (*val) {
+		if (!((*val >= '0' && *val <= '9') ||
+		      *val == '/' || *val == ','))
+			return 0;
+		val++;
+	}
+
+	return 1;
+}
+
+
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+						const u8 *hdr,
+						const u8 *attr_start,
+						size_t attr_len,
+						u8 *ssid, size_t *ssid_len,
+						char **channel_list)
+{
+	const u8 *wrapped_data, *status, *e_nonce;
+	u16 wrapped_data_len, status_len, e_nonce_len;
+	const u8 *addr[2];
+	size_t len[2];
+	u8 *unwrapped = NULL;
+	size_t unwrapped_len = 0;
+	enum dpp_status_error ret = 256;
+	struct json_token *root = NULL, *token;
+
+	*ssid_len = 0;
+	*channel_list = NULL;
+
+	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+				    &wrapped_data_len);
+	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+		dpp_auth_fail(auth,
+			      "Missing or invalid required Wrapped Data attribute");
+		goto fail;
+	}
+	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+		    wrapped_data, wrapped_data_len);
+
+	attr_len = wrapped_data - 4 - attr_start;
+
+	addr[0] = hdr;
+	len[0] = DPP_HDR_LEN;
+	addr[1] = attr_start;
+	len[1] = attr_len;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+		    wrapped_data, wrapped_data_len);
+	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+	unwrapped = os_malloc(unwrapped_len);
+	if (!unwrapped)
+		goto fail;
+	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+			    wrapped_data, wrapped_data_len,
+			    2, addr, len, unwrapped) < 0) {
+		dpp_auth_fail(auth, "AES-SIV decryption failed");
+		goto fail;
+	}
+	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+		    unwrapped, unwrapped_len);
+
+	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+		goto fail;
+	}
+
+	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+			       DPP_ATTR_ENROLLEE_NONCE,
+			       &e_nonce_len);
+	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+		dpp_auth_fail(auth,
+			      "Missing or invalid Enrollee Nonce attribute");
+		goto fail;
+	}
+	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+	if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+		dpp_auth_fail(auth, "Enrollee Nonce mismatch");
+		wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
+			    auth->e_nonce, e_nonce_len);
+		goto fail;
+	}
+
+	status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
+			      &status_len);
+	if (!status) {
+		dpp_auth_fail(auth,
+			      "Missing required DPP Connection Status attribute");
+		goto fail;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+			  status, status_len);
+
+	root = json_parse((const char *) status, status_len);
+	if (!root) {
+		dpp_auth_fail(auth, "Could not parse connStatus");
+		goto fail;
+	}
+
+	token = json_get_member(root, "ssid");
+	if (token && token->type == JSON_STRING &&
+	    os_strlen(token->string) <= SSID_MAX_LEN) {
+		*ssid_len = os_strlen(token->string);
+		os_memcpy(ssid, token->string, *ssid_len);
+	}
+
+	token = json_get_member(root, "channelList");
+	if (token && token->type == JSON_STRING &&
+	    valid_channel_list(token->string))
+		*channel_list = os_strdup(token->string);
+
+	token = json_get_member(root, "result");
+	if (!token || token->type != JSON_NUMBER) {
+		dpp_auth_fail(auth, "No connStatus - result");
+		goto fail;
+	}
+	wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
+	ret = token->number;
+
+fail:
+	json_free(root);
+	bin_clear_free(unwrapped, unwrapped_len);
+	return ret;
+}
+
+
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+					     enum dpp_status_error result,
+					     const u8 *ssid, size_t ssid_len,
+					     const char *channel_list)
+{
+	struct wpabuf *msg, *clear, *json;
+	size_t nonce_len, clear_len, attr_len;
+	const u8 *addr[2];
+	size_t len[2];
+	u8 *wrapped;
+
+	json = wpabuf_alloc(1000);
+	if (!json)
+		return NULL;
+	wpabuf_printf(json, "{\"result\":%d", result);
+	if (ssid) {
+		char ssid_str[6 * SSID_MAX_LEN + 1];
+
+		wpabuf_put_str(json, ",\"ssid\":\"");
+		json_escape_string(ssid_str, sizeof(ssid_str),
+				   (const char *) ssid, ssid_len);
+		wpabuf_put_str(json, ssid_str);
+		wpabuf_put_str(json, "\"");
+	}
+	if (channel_list)
+		wpabuf_printf(json, ",\"channelList\":\"%s\"", channel_list);
+	wpabuf_put_str(json, "}");
+	wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+			  wpabuf_head(json), wpabuf_len(json));
+
+	nonce_len = auth->curve->nonce_len;
+	clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
+	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+	clear = wpabuf_alloc(clear_len);
+	msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
+	if (!clear || !msg)
+		goto fail;
+
+	/* E-nonce */
+	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+	wpabuf_put_le16(clear, nonce_len);
+	wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+	/* DPP Connection Status */
+	wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
+	wpabuf_put_le16(clear, wpabuf_len(json));
+	wpabuf_put_buf(clear, json);
+
+	/* OUI, OUI type, Crypto Suite, DPP frame type */
+	addr[0] = wpabuf_head_u8(msg) + 2;
+	len[0] = 3 + 1 + 1 + 1;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+	/* Attributes before Wrapped Data (none) */
+	addr[1] = wpabuf_put(msg, 0);
+	len[1] = 0;
+	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+	/* Wrapped Data */
+	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+			    wpabuf_head(clear), wpabuf_len(clear),
+			    2, addr, len, wrapped) < 0)
+		goto fail;
+
+	wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
+			msg);
+	wpabuf_free(json);
+	wpabuf_free(clear);
+	return msg;
+fail:
+	wpabuf_free(json);
+	wpabuf_free(clear);
+	wpabuf_free(msg);
+	return NULL;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
 void dpp_configurator_free(struct dpp_configurator *conf)
 {
 	if (!conf)
@@ -6240,11 +6797,11 @@
 	auth->own_protocol_key = dpp_gen_keypair(auth->curve);
 	if (!auth->own_protocol_key)
 		return -1;
-	dpp_copy_netaccesskey(auth);
+	dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
 	auth->peer_protocol_key = auth->own_protocol_key;
-	dpp_copy_csign(auth, auth->conf->csign);
+	dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
 
-	conf_obj = dpp_build_conf_obj(auth, ap);
+	conf_obj = dpp_build_conf_obj(auth, ap, 0);
 	if (!conf_obj)
 		goto fail;
 	ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
@@ -6427,7 +6984,6 @@
 	const char *pos, *end;
 	unsigned char *own_conn = NULL;
 	size_t own_conn_len;
-	EVP_PKEY_CTX *ctx = NULL;
 	size_t Nx_len;
 	u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
 
@@ -6541,18 +7097,8 @@
 	}
 
 	/* ECDH: N = nk * PK */
-	ctx = EVP_PKEY_CTX_new(own_key, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
-	    Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
 		goto fail;
-	}
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
 			Nx, Nx_len);
@@ -6575,7 +7121,6 @@
 	if (ret != DPP_STATUS_OK)
 		os_memset(intro, 0, sizeof(*intro));
 	os_memset(Nx, 0, sizeof(Nx));
-	EVP_PKEY_CTX_free(ctx);
 	os_free(own_conn);
 	os_free(signed_connector);
 	os_free(info.payload);
@@ -7250,7 +7795,6 @@
 	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
 	size_t Kx_len;
 	int res;
-	EVP_PKEY_CTX *ctx = NULL;
 
 	if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
@@ -7417,18 +7961,8 @@
 		goto fail;
 
 	/* K = y * X' */
-	ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
-	    Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
 		goto fail;
-	}
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
 			Kx, Kx_len);
@@ -7446,7 +7980,6 @@
 	pkex->exchange_done = 1;
 
 out:
-	EVP_PKEY_CTX_free(ctx);
 	BN_CTX_free(bnctx);
 	EC_POINT_free(Qi);
 	EC_POINT_free(Qr);
@@ -7594,7 +8127,6 @@
 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
 	EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
 	BIGNUM *Nx = NULL, *Ny = NULL;
-	EVP_PKEY_CTX *ctx = NULL;
 	EC_KEY *Y_ec = NULL;
 	size_t Jx_len, Kx_len;
 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
@@ -7706,18 +8238,8 @@
 	if (!pkex->y ||
 	    EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
 		goto fail;
-	ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
-	    Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
 		goto fail;
-	}
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
 			Jx, Jx_len);
@@ -7741,19 +8263,8 @@
 	wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
 
 	/* K = x * Y’ */
-	EVP_PKEY_CTX_free(ctx);
-	ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
-	    Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
 		goto fail;
-	}
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
 			Kx, Kx_len);
@@ -7783,7 +8294,6 @@
 	BN_free(Nx);
 	BN_free(Ny);
 	EC_KEY_free(Y_ec);
-	EVP_PKEY_CTX_free(ctx);
 	BN_CTX_free(bnctx);
 	EC_GROUP_free(group);
 	return msg;
@@ -7911,7 +8421,6 @@
 					      const u8 *buf, size_t buflen)
 {
 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
-	EVP_PKEY_CTX *ctx = NULL;
 	size_t Jx_len, Lx_len;
 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
@@ -7995,18 +8504,8 @@
 			    pkex->peer_bootstrap_key);
 
 	/* ECDH: J' = y * A' */
-	ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
-	    Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
 		goto fail;
-	}
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
 			Jx, Jx_len);
@@ -8042,19 +8541,8 @@
 	wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
 
 	/* ECDH: L = b * X' */
-	EVP_PKEY_CTX_free(ctx);
-	ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
-	    Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
 		goto fail;
-	}
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
 			Lx, Lx_len);
@@ -8080,7 +8568,6 @@
 		goto fail;
 
 out:
-	EVP_PKEY_CTX_free(ctx);
 	os_free(unwrapped);
 	wpabuf_free(A_pub);
 	wpabuf_free(B_pub);
@@ -8109,7 +8596,6 @@
 	u8 v[DPP_MAX_HASH_LEN];
 	size_t Lx_len;
 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
-	EVP_PKEY_CTX *ctx = NULL;
 	struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
 
 #ifdef CONFIG_TESTING_OPTIONS
@@ -8180,18 +8666,8 @@
 			    pkex->peer_bootstrap_key);
 
 	/* ECDH: L' = x * B' */
-	ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
-	if (!ctx ||
-	    EVP_PKEY_derive_init(ctx) != 1 ||
-	    EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
-	    EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
-	    Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
-	    EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
-		wpa_printf(MSG_ERROR,
-			   "DPP: Failed to derive ECDH shared secret: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
+	if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
 		goto fail;
-	}
 
 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
 			Lx, Lx_len);
@@ -8231,7 +8707,6 @@
 	wpabuf_free(B_pub);
 	wpabuf_free(X_pub);
 	wpabuf_free(Y_pub);
-	EVP_PKEY_CTX_free(ctx);
 	os_free(unwrapped);
 	return ret;
 fail:
@@ -8767,6 +9242,10 @@
 
 #ifdef CONFIG_DPP2
 
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+							   void *timeout_ctx);
+
+
 static void dpp_connection_free(struct dpp_connection *conn)
 {
 	if (conn->sock >= 0) {
@@ -8776,6 +9255,8 @@
 		eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
 		close(conn->sock);
 	}
+	eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
+			     conn, NULL);
 	wpabuf_free(conn->msg);
 	wpabuf_free(conn->msg_out);
 	dpp_auth_deinit(conn->auth);
@@ -8999,23 +9480,9 @@
 {
 	struct dpp_authentication *auth = conn->auth;
 	struct wpabuf *buf;
-	char json[100];
 	int netrole_ap = 0; /* TODO: make this configurable */
 
-	os_snprintf(json, sizeof(json),
-		    "{\"name\":\"Test\","
-		    "\"wi-fi_tech\":\"infra\","
-		    "\"netRole\":\"%s\"}",
-		    netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
-	if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
-		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
-		json[29] = 'k'; /* replace "infra" with "knfra" */
-	}
-#endif /* CONFIG_TESTING_OPTIONS */
-	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
-	buf = dpp_build_conf_req(auth, json);
+	buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
 	if (!buf) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: No configuration request data available");
@@ -9030,7 +9497,7 @@
 		return;
 	}
 	wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
-	wpabuf_put_data(conn->msg_out, wpabuf_head(buf) + 1,
+	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
 			wpabuf_len(buf) - 1);
 	wpabuf_free(buf);
 
@@ -9410,7 +9877,7 @@
 	if (!conn->msg_out)
 		return -1;
 	wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
-	wpabuf_put_data(conn->msg_out, wpabuf_head(conn->auth->resp_msg) + 1,
+	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
 			wpabuf_len(conn->auth->resp_msg) - 1);
 
 	if (dpp_tcp_send(conn) == 1) {
@@ -9458,7 +9925,7 @@
 		return -1;
 	}
 	wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
-	wpabuf_put_data(conn->msg_out, wpabuf_head(msg) + 1,
+	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
 			wpabuf_len(msg) - 1);
 	wpabuf_free(msg);
 
@@ -9500,6 +9967,22 @@
 }
 
 
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+							   void *timeout_ctx)
+{
+	struct dpp_connection *conn = eloop_ctx;
+
+	if (!conn->auth->waiting_conf_result)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Timeout while waiting for Connection Status Result");
+	wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+		DPP_EVENT_CONN_STATUS_RESULT "timeout");
+	dpp_connection_remove(conn);
+}
+
+
 static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
 					 const u8 *hdr, const u8 *buf,
 					 size_t len)
@@ -9519,6 +10002,18 @@
 	}
 
 	status = dpp_conf_result_rx(auth, hdr, buf, len);
+	if (status == DPP_STATUS_OK && auth->send_conn_status) {
+		wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+			DPP_EVENT_CONF_SENT "wait_conn_status=1");
+		wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+		eloop_cancel_timeout(
+			dpp_controller_conn_status_result_wait_timeout,
+			conn, NULL);
+		eloop_register_timeout(
+			16, 0, dpp_controller_conn_status_result_wait_timeout,
+			conn, NULL);
+		return 0;
+	}
 	if (status == DPP_STATUS_OK)
 		wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
 			DPP_EVENT_CONF_SENT);
@@ -9529,6 +10024,39 @@
 }
 
 
+static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
+						const u8 *hdr, const u8 *buf,
+						size_t len)
+{
+	struct dpp_authentication *auth = conn->auth;
+	enum dpp_status_error status;
+	u8 ssid[SSID_MAX_LEN];
+	size_t ssid_len = 0;
+	char *channel_list = NULL;
+
+	if (!conn->ctrl)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+	if (!auth || !auth->waiting_conn_status_result) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No DPP Configuration waiting for connection status result - drop");
+		return -1;
+	}
+
+	status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+					   ssid, &ssid_len, &channel_list);
+	wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+		DPP_EVENT_CONN_STATUS_RESULT
+		"result=%d ssid=%s channel_list=%s",
+		status, wpa_ssid_txt(ssid, ssid_len),
+		channel_list ? channel_list : "N/A");
+	os_free(channel_list);
+	return -1; /* to remove the completed connection */
+}
+
+
 static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
 				    size_t len)
 {
@@ -9576,6 +10104,9 @@
 		return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
 	case DPP_PA_CONFIGURATION_RESULT:
 		return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
+	case DPP_PA_CONNECTION_STATUS_RESULT:
+		return dpp_controller_rx_conn_status_result(conn, msg, pos,
+							    end - pos);
 	default:
 		/* TODO: missing messages types */
 		wpa_printf(MSG_DEBUG,
@@ -9692,6 +10223,7 @@
 	if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
 		return -1;
 
+#ifdef CONFIG_DPP2
 	wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
 	status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
 	msg = dpp_build_conf_result(auth, status);
@@ -9704,7 +10236,7 @@
 		return -1;
 	}
 	wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
-	wpabuf_put_data(encaps, wpabuf_head(msg) + 1, wpabuf_len(msg) - 1);
+	wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
 	wpabuf_free(msg);
 	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
 
@@ -9717,6 +10249,9 @@
 	/* This exchange will be terminated in the TX status handler */
 
 	return 0;
+#else /* CONFIG_DPP2 */
+	return -1;
+#endif /* CONFIG_DPP2 */
 }
 
 
diff --git a/src/common/dpp.h b/src/common/dpp.h
index db640ef..0be26d7 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -35,6 +35,7 @@
 	DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
 	DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
 	DPP_PA_CONFIGURATION_RESULT = 11,
+	DPP_PA_CONNECTION_STATUS_RESULT = 12,
 };
 
 enum dpp_attribute_id {
@@ -64,6 +65,8 @@
 	DPP_ATTR_CHANNEL = 0x1018,
 	DPP_ATTR_PROTOCOL_VERSION = 0x1019,
 	DPP_ATTR_ENVELOPED_DATA = 0x101A,
+	DPP_ATTR_SEND_CONN_STATUS = 0x101B,
+	DPP_ATTR_CONN_STATUS = 0x101C,
 };
 
 enum dpp_status_error {
@@ -77,6 +80,7 @@
 	DPP_STATUS_INVALID_CONNECTOR = 7,
 	DPP_STATUS_NO_MATCH = 8,
 	DPP_STATUS_CONFIG_REJECTED = 9,
+	DPP_STATUS_NO_AP = 10,
 };
 
 #define DPP_CAPAB_ENROLLEE BIT(0)
@@ -157,10 +161,16 @@
 	DPP_AKM_PSK_SAE_DPP,
 };
 
+enum dpp_netrole {
+	DPP_NETROLE_STA,
+	DPP_NETROLE_AP,
+};
+
 struct dpp_configuration {
 	u8 ssid[32];
 	size_t ssid_len;
 	enum dpp_akm akm;
+	enum dpp_netrole netrole;
 
 	/* For DPP configuration (connector) */
 	os_time_t netaccesskey_expiry;
@@ -174,6 +184,8 @@
 	int psk_set;
 };
 
+#define DPP_MAX_CONF_OBJ 10
+
 struct dpp_authentication {
 	void *msg_ctx;
 	u8 peer_version;
@@ -222,22 +234,31 @@
 	int remove_on_tx_status;
 	int connect_on_tx_status;
 	int waiting_conf_result;
+	int waiting_conn_status_result;
 	int auth_success;
 	struct wpabuf *conf_req;
 	const struct wpabuf *conf_resp; /* owned by GAS server */
 	struct dpp_configuration *conf_ap;
+	struct dpp_configuration *conf2_ap;
 	struct dpp_configuration *conf_sta;
+	struct dpp_configuration *conf2_sta;
 	struct dpp_configurator *conf;
-	char *connector; /* received signedConnector */
-	u8 ssid[SSID_MAX_LEN];
-	u8 ssid_len;
-	char passphrase[64];
-	u8 psk[PMK_LEN];
-	int psk_set;
-	enum dpp_akm akm;
+	struct dpp_config_obj {
+		char *connector; /* received signedConnector */
+		u8 ssid[SSID_MAX_LEN];
+		u8 ssid_len;
+		char passphrase[64];
+		u8 psk[PMK_LEN];
+		int psk_set;
+		enum dpp_akm akm;
+		struct wpabuf *c_sign_key;
+	} conf_obj[DPP_MAX_CONF_OBJ];
+	unsigned int num_conf_obj;
 	struct wpabuf *net_access_key;
 	os_time_t net_access_key_expiry;
-	struct wpabuf *c_sign_key;
+	int send_conn_status;
+	int conn_status_requested;
+	int akm_use_selector;
 #ifdef CONFIG_TESTING_OPTIONS
 	char *config_obj_override;
 	char *discovery_override;
@@ -413,6 +434,9 @@
 		 const u8 *attr_start, size_t attr_len);
 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
 				   const char *json);
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+					  const char *name, int netrole_ap,
+					  const char *mud_url, int *opclasses);
 int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
 		     const u8 *attr_start, size_t attr_len);
 int dpp_notify_new_qr_code(struct dpp_authentication *auth,
@@ -439,12 +463,23 @@
 					 const u8 *attr_start, size_t attr_len);
 struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
 				      enum dpp_status_error status);
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+						const u8 *hdr,
+						const u8 *attr_start,
+						size_t attr_len,
+						u8 *ssid, size_t *ssid_len,
+						char **channel_list);
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+					     enum dpp_status_error result,
+					     const u8 *ssid, size_t ssid_len,
+					     const char *channel_list);
 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
 			      size_t len);
 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
 int dpp_check_attrs(const u8 *buf, size_t len);
 int dpp_key_expired(const char *timestamp, os_time_t *expiry);
 const char * dpp_akm_str(enum dpp_akm akm);
+const char * dpp_akm_selector_str(enum dpp_akm akm);
 int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
 			     size_t buflen);
 void dpp_configurator_free(struct dpp_configurator *conf);
diff --git a/src/common/dragonfly.c b/src/common/dragonfly.c
index e98bce6..547be66 100644
--- a/src/common/dragonfly.c
+++ b/src/common/dragonfly.c
@@ -21,14 +21,35 @@
 	 * purposes: FFC groups whose prime is >= 3072 bits and ECC groups
 	 * defined over a prime field whose prime is >= 256 bits. Furthermore,
 	 * ECC groups defined over a characteristic 2 finite field and ECC
-	 * groups with a co-factor greater than 1 are not suitable. */
+	 * groups with a co-factor greater than 1 are not suitable. Disable
+	 * groups that use Brainpool curves as well for now since they leak more
+	 * timing information due to the prime not being close to a power of
+	 * two. */
 	return group == 19 || group == 20 || group == 21 ||
-		group == 28 || group == 29 || group == 30 ||
 		(!ecc_only &&
 		 (group == 15 || group == 16 || group == 17 || group == 18));
 }
 
 
+unsigned int dragonfly_min_pwe_loop_iter(int group)
+{
+	if (group == 22 || group == 23 || group == 24) {
+		/* FFC groups for which pwd-value is likely to be >= p
+		 * frequently */
+		return 40;
+	}
+
+	if (group == 1 || group == 2 || group == 5 || group == 14 ||
+	    group == 15 || group == 16 || group == 17 || group == 18) {
+		/* FFC groups that have prime that is close to a power of two */
+		return 1;
+	}
+
+	/* Default to 40 (this covers most ECC groups) */
+	return 40;
+}
+
+
 int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
 				struct crypto_bignum **qr,
 				struct crypto_bignum **qnr)
diff --git a/src/common/dragonfly.h b/src/common/dragonfly.h
index e7627ef..ec3dd59 100644
--- a/src/common/dragonfly.h
+++ b/src/common/dragonfly.h
@@ -16,6 +16,7 @@
 struct crypto_ec;
 
 int dragonfly_suitable_group(int group, int ecc_only);
+unsigned int dragonfly_min_pwe_loop_iter(int group);
 int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
 				struct crypto_bignum **qr,
 				struct crypto_bignum **qnr);
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 3fdbf89..1ad8d7c 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -360,7 +360,8 @@
 
 int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int ht_enabled,
+			    int freq, int channel, int enable_edmg,
+			    u8 edmg_channel, int ht_enabled,
 			    int vht_enabled, int he_enabled,
 			    int sec_channel_offset,
 			    int oper_chwidth, int center_segment0,
@@ -381,6 +382,74 @@
 	data->center_freq2 = 0;
 	data->bandwidth = sec_channel_offset ? 40 : 20;
 
+	hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel,
+				 &data->edmg);
+
+	if (is_6ghz_freq(freq)) {
+		if (!data->he_enabled) {
+			wpa_printf(MSG_ERROR,
+				   "Can't set 6 GHz mode - HE isn't enabled");
+			return -1;
+		}
+
+		if (center_idx_to_bw_6ghz(channel) != 0) {
+			wpa_printf(MSG_ERROR,
+				   "Invalid control channel for 6 GHz band");
+			return -1;
+		}
+
+		if (!center_segment0) {
+			if (center_segment1) {
+				wpa_printf(MSG_ERROR,
+					   "Segment 0 center frequency isn't set");
+				return -1;
+			}
+
+			data->center_freq1 = data->freq;
+			data->bandwidth = 20;
+		} else {
+			int freq1, freq2 = 0;
+			int bw = center_idx_to_bw_6ghz(center_segment0);
+
+			if (bw < 0) {
+				wpa_printf(MSG_ERROR,
+					   "Invalid center frequency index for 6 GHz");
+				return -1;
+			}
+
+			freq1 = ieee80211_chan_to_freq(NULL, 131,
+						       center_segment0);
+			if (freq1 < 0) {
+				wpa_printf(MSG_ERROR,
+					   "Invalid segment 0 center frequency for 6 GHz");
+				return -1;
+			}
+
+			if (center_segment1) {
+				if (center_idx_to_bw_6ghz(center_segment1) != 2 ||
+				    bw != 2) {
+					wpa_printf(MSG_ERROR,
+						   "6 GHz 80+80 MHz configuration doesn't use valid 80 MHz channels");
+					return -1;
+				}
+
+				freq2 = ieee80211_chan_to_freq(NULL, 131,
+							       center_segment1);
+				if (freq2 < 0) {
+					wpa_printf(MSG_ERROR,
+						   "Invalid segment 1 center frequency for UHB");
+					return -1;
+				}
+			}
+
+			data->bandwidth = (1 << (u8) bw) * 20;
+			data->center_freq1 = freq1;
+			data->center_freq2 = freq2;
+		}
+
+		return 0;
+	}
+
 	if (data->vht_enabled) switch (oper_chwidth) {
 	case CHANWIDTH_USE_HT:
 		if (center_segment1 ||
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 2d2a539..c86e195 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -31,7 +31,8 @@
 		    int sec_chan);
 int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int ht_enabled,
+			    int freq, int channel, int edmg, u8 edmg_channel,
+			    int ht_enabled,
 			    int vht_enabled, int he_enabled,
 			    int sec_channel_offset,
 			    int oper_chwidth, int center_segment0,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 9f57828..c6e6440 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -365,6 +365,10 @@
 			elems->rsn_ie = pos;
 			elems->rsn_ie_len = elen;
 			break;
+		case WLAN_EID_RSNX:
+			elems->rsnxe = pos;
+			elems->rsnxe_len = elen;
+			break;
 		case WLAN_EID_PWR_CAPABILITY:
 			if (elen < 2)
 				break;
@@ -873,8 +877,8 @@
 		return HOSTAPD_MODE_IEEE80211A;
 	}
 
-	/* 56.16 GHz, channel 1..4 */
-	if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+	/* 56.16 GHz, channel 1..6 */
+	if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
 		if (sec_channel || vht)
 			return NUM_HOSTAPD_MODES;
 
@@ -884,6 +888,19 @@
 		return HOSTAPD_MODE_IEEE80211AD;
 	}
 
+	if (freq > 5940 && freq <= 7105) {
+		int bw;
+		u8 idx = (freq - 5940) / 5;
+
+		bw = center_idx_to_bw_6ghz(idx);
+		if (bw < 0)
+			return NUM_HOSTAPD_MODES;
+
+		*channel = idx;
+		*op_class = 131 + bw;
+		return HOSTAPD_MODE_IEEE80211A;
+	}
+
 	return NUM_HOSTAPD_MODES;
 }
 
@@ -993,8 +1010,8 @@
 		if (chan < 149 || chan > 165)
 			return -1;
 		return 5000 + 5 * chan;
-	case 34: /* 60 GHz band, channels 1..3 */
-		if (chan < 1 || chan > 3)
+	case 34: /* 60 GHz band, channels 1..6 */
+		if (chan < 1 || chan > 6)
 			return -1;
 		return 56160 + 2160 * chan;
 	}
@@ -1031,8 +1048,8 @@
 		if (chan < 149 || chan > 169)
 			return -1;
 		return 5000 + 5 * chan;
-	case 18: /* 60 GHz band, channels 1..4 */
-		if (chan < 1 || chan > 4)
+	case 18: /* 60 GHz band, channels 1..6 */
+		if (chan < 1 || chan > 6)
 			return -1;
 		return 56160 + 2160 * chan;
 	}
@@ -1075,8 +1092,8 @@
 		if (chan < 100 || chan > 140)
 			return -1;
 		return 5000 + 5 * chan;
-	case 59: /* 60 GHz band, channels 1..4 */
-		if (chan < 1 || chan > 3)
+	case 59: /* 60 GHz band, channels 1..6 */
+		if (chan < 1 || chan > 6)
 			return -1;
 		return 56160 + 2160 * chan;
 	}
@@ -1163,8 +1180,16 @@
 		if (chan < 36 || chan > 128)
 			return -1;
 		return 5000 + 5 * chan;
-	case 180: /* 60 GHz band, channels 1..4 */
-		if (chan < 1 || chan > 4)
+	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+		if (chan < 1 || chan > 233)
+			return -1;
+		return 5940 + chan * 5;
+	case 180: /* 60 GHz band, channels 1..6 */
+		if (chan < 1 || chan > 6)
 			return -1;
 		return 56160 + 2160 * chan;
 	}
@@ -1494,6 +1519,7 @@
 	S2S(FILS_AUTHENTICATION_FAILURE)
 	S2S(UNKNOWN_AUTHENTICATION_SERVER)
 	S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+	S2S(SAE_HASH_TO_ELEMENT)
 	}
 	return "UNKNOWN";
 #undef S2S
@@ -1592,6 +1618,7 @@
 	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
+	{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
 	{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
 };
@@ -1906,6 +1933,43 @@
 }
 
 
+int center_idx_to_bw_6ghz(u8 idx)
+{
+	/* channels: 1, 5, 9, 13... */
+	if ((idx & 0x3) == 0x1)
+		return 0; /* 20 MHz */
+	/* channels 3, 11, 19... */
+	if ((idx & 0x7) == 0x3)
+		return 1; /* 40 MHz */
+	/* channels 7, 23, 39.. */
+	if ((idx & 0xf) == 0x7)
+		return 2; /* 80 MHz */
+	/* channels 15, 47, 79...*/
+	if ((idx & 0x1f) == 0xf)
+		return 3; /* 160 MHz */
+
+	return -1;
+}
+
+
+int is_6ghz_freq(int freq)
+{
+	if (freq < 5940 || freq > 7105)
+		return 0;
+
+	if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0)
+		return 0;
+
+	return 1;
+}
+
+
+int is_6ghz_op_class(u8 op_class)
+{
+	return op_class >= 131 && op_class <= 135;
+}
+
+
 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
 				    size_t nei_rep_len)
 {
@@ -2014,3 +2078,75 @@
 		return 0;
 	return !!(ie[2 + capab / 8] & BIT(capab % 8));
 }
+
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+			      int primary_channel,
+			      struct ieee80211_edmg_config *edmg)
+{
+	if (!edmg_enable) {
+		edmg->channels = 0;
+		edmg->bw_config = 0;
+		return;
+	}
+
+	/* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
+	switch (edmg_channel) {
+	case EDMG_CHANNEL_9:
+		edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
+		edmg->bw_config = EDMG_BW_CONFIG_5;
+		return;
+	case EDMG_CHANNEL_10:
+		edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
+		edmg->bw_config = EDMG_BW_CONFIG_5;
+		return;
+	case EDMG_CHANNEL_11:
+		edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
+		edmg->bw_config = EDMG_BW_CONFIG_5;
+		return;
+	case EDMG_CHANNEL_12:
+		edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
+		edmg->bw_config = EDMG_BW_CONFIG_5;
+		return;
+	case EDMG_CHANNEL_13:
+		edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
+		edmg->bw_config = EDMG_BW_CONFIG_5;
+		return;
+	default:
+		if (primary_channel > 0 && primary_channel < 7) {
+			edmg->channels = BIT(primary_channel - 1);
+			edmg->bw_config = EDMG_BW_CONFIG_4;
+		} else {
+			edmg->channels = 0;
+			edmg->bw_config = 0;
+		}
+		break;
+	}
+}
+
+
+/* Check if the requested EDMG configuration is a subset of the allowed
+ * EDMG configuration. */
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+			    struct ieee80211_edmg_config requested)
+{
+	/*
+	 * The validation check if the requested EDMG configuration
+	 * is a subset of the allowed EDMG configuration:
+	 * 1. Check that the requested channels are part (set) of the allowed
+	 * channels.
+	 * 2. P802.11ay defines the values of bw_config between 4 and 15.
+	 * (bw config % 4) will give us 4 groups inside bw_config definition,
+	 * inside each group we can check the subset just by comparing the
+	 * bw_config value.
+	 * Between this 4 groups, there is no subset relation - as a result of
+	 * the P802.11ay definition.
+	 * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
+	 */
+	if (((requested.channels & allowed.channels) != requested.channels) ||
+	    ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
+	    requested.bw_config > allowed.bw_config)
+		return 0;
+
+	return 1;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9b045b4..052f333 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -40,6 +40,7 @@
 	const u8 *ext_supp_rates;
 	const u8 *wpa_ie;
 	const u8 *rsn_ie;
+	const u8 *rsnxe;
 	const u8 *wmm; /* WMM Information or Parameter Element */
 	const u8 *wmm_tspec;
 	const u8 *wps_ie;
@@ -102,6 +103,7 @@
 	u8 ext_supp_rates_len;
 	u8 wpa_ie_len;
 	u8 rsn_ie_len;
+	u8 rsnxe_len;
 	u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
 	u8 wmm_tspec_len;
 	u8 wps_ie_len;
@@ -220,6 +222,9 @@
 
 const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
 int oper_class_bw_to_int(const struct oper_class_map *map);
+int center_idx_to_bw_6ghz(u8 idx);
+int is_6ghz_freq(int freq);
+int is_6ghz_op_class(u8 op_class);
 
 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
 				    size_t nei_rep_len);
@@ -273,4 +278,13 @@
 	return (const u8 *) element == (const u8 *) data + datalen;
 }
 
+struct ieee80211_edmg_config;
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+			      int primary_channel,
+			      struct ieee80211_edmg_config *edmg);
+
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+			    struct ieee80211_edmg_config requested);
+
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b0aa913..fbed051 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -204,6 +204,7 @@
 #define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
 #define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
 #define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
 
 /* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
 #define WLAN_REASON_UNSPECIFIED 1
@@ -446,6 +447,7 @@
 #define WLAN_EID_FILS_INDICATION 240
 #define WLAN_EID_DILS 241
 #define WLAN_EID_FRAGMENT 242
+#define WLAN_EID_RSNX 244
 #define WLAN_EID_EXTENSION 255
 
 /* Element ID Extension (EID 255) values */
@@ -470,6 +472,9 @@
 #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
 #define WLAN_EID_EXT_SPATIAL_REUSE 39
 #define WLAN_EID_EXT_OCV_OCI 54
+#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
+#define WLAN_EID_EXT_EDMG_OPERATION 62
+#define WLAN_EID_EXT_REJECTED_GROUPS 92
 
 /* Extended Capabilities field */
 #define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -552,6 +557,11 @@
 #define WLAN_EXT_CAPAB_SAE_PW_ID 81
 #define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
 
+/* Extended RSN Capabilities */
+/* bits 0-3: Field length (n-1) */
+#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
+#define WLAN_RSNX_CAPAB_SAE_H2E 5
+
 /* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
 #define WLAN_ACTION_SPECTRUM_MGMT 0
 #define WLAN_ACTION_QOS 1
@@ -1217,6 +1227,7 @@
 
 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123
 
 /* VHT Defines */
 #define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
@@ -2109,7 +2120,7 @@
 	u8 he_phy_capab_info[11];
 	/* Followed by 4, 8, or 12 octets of Supported HE-MCS And NSS Set field
 	* and optional variable length PPE Thresholds field. */
-	u8 optional[];
+	u8 optional[37];
 } STRUCT_PACKED;
 
 struct ieee80211_he_operation {
@@ -2174,6 +2185,10 @@
 						BIT(10) | BIT(11) | \
 						BIT(12) | BIT(13)))
 #define HE_OPERATION_RTS_THRESHOLD_OFFSET	4
+#define HE_OPERATION_VHT_OPER_INFO		((u32) BIT(14))
+#define HE_OPERATION_COHOSTED_BSS		((u32) BIT(15))
+#define HE_OPERATION_ER_SU_DISABLE		((u32) BIT(16))
+#define HE_OPERATION_6GHZ_OPER_INFO		((u32) BIT(17))
 #define HE_OPERATION_BSS_COLOR_MASK		((u32) (BIT(24) | BIT(25) | \
 							BIT(26) | BIT(27) | \
 							BIT(28) | BIT(29)))
@@ -2221,6 +2236,39 @@
 /* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
 #define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
 
+/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
+#define EDMG_BSS_OPERATING_CHANNELS_OFFSET	6
+#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET	7
+
+/* IEEE P802.11ay/D4.0, 29.3.4 - Channelization */
+enum edmg_channel {
+	EDMG_CHANNEL_9	= 9,
+	EDMG_CHANNEL_10	= 10,
+	EDMG_CHANNEL_11	= 11,
+	EDMG_CHANNEL_12	= 12,
+	EDMG_CHANNEL_13	= 13,
+};
+
+/* Represent CB2 contiguous channels */
+#define EDMG_CHANNEL_9_SUBCHANNELS	(BIT(0) | BIT(1)) /* channels 1 and 2 */
+#define EDMG_CHANNEL_10_SUBCHANNELS	(BIT(1) | BIT(2)) /* channels 2 and 3 */
+#define EDMG_CHANNEL_11_SUBCHANNELS	(BIT(2) | BIT(3)) /* channels 3 and 4 */
+#define EDMG_CHANNEL_12_SUBCHANNELS	(BIT(3) | BIT(4)) /* channels 4 and 5 */
+#define EDMG_CHANNEL_13_SUBCHANNELS	(BIT(4) | BIT(5)) /* channels 5 and 6 */
+
+/**
+ * enum edmg_bw_config - Allowed channel bandwidth configurations
+ * @EDMG_BW_CONFIG_4: 2.16 GHz
+ * @EDMG_BW_CONFIG_5: 2.16 GHz and 4.32 GHz
+ *
+ * IEEE P802.11ay/D4.0, 9.4.2.251 (EDMG Operation element),
+ * Table 13 (Channel BW Configuration subfield definition)
+ */
+enum edmg_bw_config {
+	EDMG_BW_CONFIG_4	= 4,
+	EDMG_BW_CONFIG_5	= 5,
+};
+
 /* DPP Public Action frame identifiers - OUI_WFA */
 #define DPP_OUI_TYPE 0x1A
 
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 0c607b8..a0a0fb5 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -72,7 +72,7 @@
  *
  * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
  *	invoke the ACS function in device and pass selected channels to
- *	hostapd.
+ *	hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
  *
  * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
  *	supported by the driver. enum qca_wlan_vendor_features defines
@@ -170,6 +170,11 @@
  *	to notify the connected station's status. The attributes for this
  *	command are defined in enum qca_wlan_vendor_attr_link_properties.
  *
+ * @QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY: This command is used to configure
+ *	DFS policy and channel hint for ACS operation. This command uses the
+ *	attributes defined in enum qca_wlan_vendor_attr_acs_config and
+ *	enum qca_acs_dfs_mode.
+ *
  * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to
  *	start the P2P Listen offload function in device and pass the listen
  *	channel, period, interval, count, device types, and vendor specific
@@ -584,6 +589,26 @@
  *	by the firmware to user space for persistent storage. The attributes
  *	defined in enum qca_vendor_attr_interop_issues_ap are used to deliver
  *	the parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command/event is used to
+ *	send/receive OEM data binary blobs to/from application/service to/from
+ *	firmware. The attributes defined in enum
+ *	qca_wlan_vendor_attr_oem_data_params are used to deliver the
+ *	parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT: This command/event is used
+ *	to send/receive avoid frequency data using
+ *	enum qca_wlan_vendor_attr_avoid_frequency_ext.
+ *	This new command is alternative to existing command
+ *	QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY since existing command/event
+ *	is using stream of bytes instead of structured data using vendor
+ *	attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: This vendor subcommand is used to
+ *	add the STA node details in driver/firmware. Attributes for this event
+ *	are specified in enum qca_wlan_vendor_attr_add_sta_node_params.
+ * @QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE: This command is used to set BT
+ *	coex chain mode from application/service.
+ *	The attributes defined in enum qca_vendor_attr_btc_chain_mode are used
+ *	to deliver the parameters.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -683,7 +708,8 @@
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
 	/* 110..114 - reserved for QCA */
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
-	/* 116..117 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY = 116,
+	/* 117 - reserved for QCA */
 	QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
 	QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
 	QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
@@ -754,6 +780,10 @@
 	QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG = 179,
 	QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING = 180,
 	QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP = 181,
+	QCA_NL80211_VENDOR_SUBCMD_OEM_DATA = 182,
+	QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT = 183,
+	QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184,
+	QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185,
 };
 
 enum qca_wlan_vendor_attr {
@@ -1090,31 +1120,162 @@
 	QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
 };
 
+/**
+ * enum qca_wlan_vendor_attr_acs_offload - Defines attributes to be used with
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: Required (u8).
+ * Used with event to notify the primary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY instead.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: Required (u8).
+ * Used with event to notify the secondary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is still used if either of
+ * the driver or user space application doesn't support 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: Required (u8).
+ * (a) Used with command to configure hw_mode from
+ * enum qca_wlan_vendor_acs_hw_mode for ACS operation.
+ * (b) Also used with event to notify the hw_mode of selected primary channel
+ * in ACS operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT mode.
+ * Disable (flag attribute not present) - HT disabled and
+ * Enable (flag attribute present) - HT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT40 mode.
+ * Disable (flag attribute not present) - HT40 disabled and
+ * Enable (flag attribute present) - HT40 enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for VHT mode.
+ * Disable (flag attribute not present) - VHT disabled and
+ * Enable (flag attribute present) - VHT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH: Optional (u16) with command and
+ * mandatory with event.
+ * If specified in command path, ACS operation is configured with the given
+ * channel width (in MHz).
+ * In event path, specifies the channel width of the primary channel selected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure channel list using an array of
+ * channel numbers (u8).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver mandates use of QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST whereas
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 0 center channel number selected in
+ * ACS operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 1 center channel number selected in
+ * ACS operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure the channel list using an array of channel
+ * center frequencies in MHz (u32).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver first parses the frequency list and if it fails to get a frequency
+ * list, parses the channel list specified using
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST (considers only 2 GHz and 5 GHz channels in
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY: Required (u32).
+ * Used with event to notify the primary channel center frequency (MHz) selected
+ * in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY: Required (u32).
+ * Used with event to notify the secondary channel center frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 0 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 1 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL.
+ */
 enum qca_wlan_vendor_attr_acs_offload {
 	QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
-	QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
-	QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
-	QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
-	QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
-	QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
-	QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
-	QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
-	QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
-	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
-	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
-	QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
+	QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL = 1,
+	QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL = 2,
+	QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE = 3,
+	QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED = 4,
+	QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED = 5,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED = 6,
+	QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH = 7,
+	QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST = 8,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL = 9,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL = 10,
+	QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST = 11,
+	QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY = 12,
+	QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY = 13,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY = 14,
+	QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_ACS_MAX =
 	QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
 };
 
+/**
+ * enum qca_wlan_vendor_acs_hw_mode - Defines HW mode to be used with the
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_ACS_MODE_IEEE80211B: 802.11b mode
+ * @QCA_ACS_MODE_IEEE80211G: 802.11g mode
+ * @QCA_ACS_MODE_IEEE80211A: 802.11a mode
+ * @QCA_ACS_MODE_IEEE80211AD: 802.11ad mode
+ * @QCA_ACS_MODE_IEEE80211ANY: all modes
+ * @QCA_ACS_MODE_IEEE80211AX: 802.11ax mode
+ */
 enum qca_wlan_vendor_acs_hw_mode {
 	QCA_ACS_MODE_IEEE80211B,
 	QCA_ACS_MODE_IEEE80211G,
 	QCA_ACS_MODE_IEEE80211A,
 	QCA_ACS_MODE_IEEE80211AD,
 	QCA_ACS_MODE_IEEE80211ANY,
+	QCA_ACS_MODE_IEEE80211AX,
 };
 
 /**
@@ -1146,6 +1307,8 @@
  * @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
  *	managed regulatory.
  * @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
+ * @QCA_WLAN_VENDOR_FEATURE_11AX: Device supports 802.11ax (HE)
+ * @QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT: Device supports 6 GHz band operation
  * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
  */
 enum qca_wlan_vendor_features {
@@ -1158,6 +1321,8 @@
 	QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON            = 6,
 	QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
 	QCA_WLAN_VENDOR_FEATURE_TWT 			= 8,
+	QCA_WLAN_VENDOR_FEATURE_11AX			= 9,
+	QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT		= 10,
 	NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
 };
 
@@ -1850,6 +2015,30 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
 
+	/* Attribute to configure disconnect IEs to the driver.
+	 * This carries an array of unsigned 8-bit characters.
+	 *
+	 * If this is configured, driver shall fill the IEs in disassoc/deauth
+	 * frame.
+	 * These IEs are expected to be considered only for the next
+	 * immediate disconnection (disassoc/deauth frame) originated by
+	 * the DUT, irrespective of the entity (user space/driver/firmware)
+	 * triggering the disconnection.
+	 * The host drivers are not expected to use the IEs set through
+	 * this interface for further disconnections after the first immediate
+	 * disconnection initiated post the configuration.
+	 * If the IEs are also updated through cfg80211 interface (after the
+	 * enhancement to cfg80211_disconnect), host driver is expected to
+	 * take the union of IEs from both of these interfaces and send in
+	 * further disassoc/deauth frames.
+	 */
+	QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
+
+	/* 8-bit unsigned value for ELNA bypass.
+	 * 1-Enable, 0-Disable
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -1858,10 +2047,23 @@
 
 /**
  * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Optional (u8)
+ * Channel number on which Access Point should restart.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY: Optional (u32)
+ * Channel center frequency (MHz) on which the access point should restart.
  */
 enum qca_wlan_vendor_attr_sap_config {
 	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
-	/* 1 - reserved for QCA */
+	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL = 1,
+
 	/* List of frequencies on which AP is expected to operate.
 	 * This is irrespective of ACS configuration. This list is a priority
 	 * based one and is looked for before the AP is created to ensure the
@@ -1869,6 +2071,7 @@
 	 * the system.
 	 */
 	QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY = 3,
 
 	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
@@ -1948,6 +2151,54 @@
 };
 
 /**
+ * enum qca_acs_dfs_mode - Defines different types of DFS channel
+ * configurations for ACS operation.
+ *
+ * @QCA_ACS_DFS_MODE_NONE: Refer to invalid DFS mode
+ * @QCA_ACS_DFS_MODE_ENABLE: Consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DISABLE: Do not consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in ACS operation
+ */
+enum qca_acs_dfs_mode {
+	QCA_ACS_DFS_MODE_NONE = 0,
+	QCA_ACS_DFS_MODE_ENABLE = 1,
+	QCA_ACS_DFS_MODE_DISABLE = 2,
+	QCA_ACS_DFS_MODE_DEPRIORITIZE = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_acs_config - Defines Configuration attributes
+ * used by the vendor command QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE: Required (u8)
+ * DFS mode for ACS operation from enum qca_acs_dfs_mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT: Required (u8)
+ * channel number hint for ACS operation, if valid channel is specified then
+ * ACS operation gives priority to this channel.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT: Required (u32).
+ * Channel center frequency (MHz) hint for ACS operation, if a valid center
+ * frequency is specified, ACS operation gives priority to this channel.
+ */
+enum qca_wlan_vendor_attr_acs_config {
+	QCA_WLAN_VENDOR_ATTR_ACS_MODE_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE = 1,
+	QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT = 2,
+	QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT = 3,
+
+	QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX =
+		QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST - 1,
+};
+
+/**
  * enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
  */
 enum qca_wlan_vendor_attr_get_hw_capability {
@@ -3330,6 +3581,345 @@
 	QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_scan_freq_list_type: Frequency list types
+ *
+ * @QCA_PREFERRED_SCAN_FREQ_LIST: The driver shall use the scan frequency list
+ *	specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ *	a preferred frequency list for roaming.
+ *
+ * @QCA_SPECIFIC_SCAN_FREQ_LIST: The driver shall use the frequency list
+ *	specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ *	a specific frequency list for roaming.
+ */
+enum qca_scan_freq_list_type {
+	QCA_PREFERRED_SCAN_FREQ_LIST = 1,
+	QCA_SPECIFIC_SCAN_FREQ_LIST = 2,
+};
+
+/**
+ * enum qca_vendor_attr_scan_freq_list_scheme: Frequency list scheme
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST: Nested attribute of u32 values
+ *	List of frequencies in MHz to be considered for a roam scan.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE: Unsigned 32-bit value.
+ *	Type of frequency list scheme being configured/gotten as defined by the
+ *	enum qca_scan_freq_list_type.
+ */
+enum qca_vendor_attr_scan_freq_list_scheme {
+	QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST = 1,
+	QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE = 2,
+
+	/* keep last */
+	QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST,
+	QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_MAX =
+	QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_vendor_roam_triggers: Bitmap of roaming triggers
+ *
+ * @QCA_ROAM_TRIGGER_REASON_PER: Set if the roam has to be triggered based on
+ *	a bad packet error rates (PER).
+ * @QCA_ROAM_TRIGGER_REASON_BEACON_MISS: Set if the roam has to be triggered
+ *	based on beacon misses from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_POOR_RSSI: Set if the roam has to be triggered
+ *	due to poor RSSI of the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BETTER_RSSI: Set if the roam has to be triggered
+ *	upon finding a BSSID with a better RSSI than the connected BSSID.
+ *	Here the RSSI of the current BSSID need not be poor.
+ * @QCA_ROAM_TRIGGER_REASON_PERIODIC: Set if the roam has to be triggered
+ *	by triggering a periodic scan to find a better AP to roam.
+ * @QCA_ROAM_TRIGGER_REASON_DENSE: Set if the roam has to be triggered
+ *	when the connected channel environment is too noisy/congested.
+ * @QCA_ROAM_TRIGGER_REASON_BTM: Set if the roam has to be triggered
+ *	when BTM Request frame is received from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BSS_LOAD: Set if the roam has to be triggered
+ *	when the channel utilization is goes above the configured threshold.
+ *
+ * Set the corresponding roam trigger reason bit to consider it for roam
+ * trigger.
+ * Userspace can set multiple bits and send to the driver. The driver shall
+ * consider all of them to trigger/initiate a roam scan.
+ */
+enum qca_vendor_roam_triggers {
+	QCA_ROAM_TRIGGER_REASON_PER		= 1 << 0,
+	QCA_ROAM_TRIGGER_REASON_BEACON_MISS	= 1 << 1,
+	QCA_ROAM_TRIGGER_REASON_POOR_RSSI	= 1 << 2,
+	QCA_ROAM_TRIGGER_REASON_BETTER_RSSI	= 1 << 3,
+	QCA_ROAM_TRIGGER_REASON_PERIODIC	= 1 << 4,
+	QCA_ROAM_TRIGGER_REASON_DENSE		= 1 << 5,
+	QCA_ROAM_TRIGGER_REASON_BTM		= 1 << 6,
+	QCA_ROAM_TRIGGER_REASON_BSS_LOAD	= 1 << 7,
+};
+
+/**
+ * enum qca_vendor_attr_roam_candidate_selection_criteria:
+ *
+ * Each attribute carries a weightage in percentage (%).
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the RSSI selection
+ *	criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the rate selection
+ *	criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the band width selection
+ *	criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the band selection
+ *	criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the NSS selection
+ *	criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the channel congestion
+ *	selection criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the beamforming selection
+ *	criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN: Unsigned 8-bit value.
+ *	Represents the weightage to be given for the OCE selection
+ *	criteria among other parameters.
+ */
+enum qca_vendor_attr_roam_candidate_selection_criteria {
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI = 1,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE = 2,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW = 3,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND = 4,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS = 5,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION = 6,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING = 7,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN = 8,
+
+	/* keep last */
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST,
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_MAX =
+	QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_roam_control - Attributes to carry roam configuration
+ * 	The following attributes are used to set/get/clear the respective
+ *	configurations to/from the driver.
+ *	For the get, the attribute for the configuration to be queried shall
+ *	carry any of its acceptable values to the driver. In return, the driver
+ *	shall send the configured values within the same attribute to the user
+ *	space.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_ENABLE: Unsigned 8-bit value.
+ *	Signifies to enable/disable roam control in driver.
+ *	1-enable, 0-disable
+ *	Enable: Mandates the driver to do the further roams using the
+ *	configuration parameters set through
+ *	QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET.
+ *	Disable: Disables the driver/firmware roaming triggered through
+ *	QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET. Further roaming is
+ *	expected to continue with the default configurations.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_STATUS: Unsigned 8-bit value.
+ *	This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET.
+ *	Roam control status is obtained through this attribute.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CLEAR_ALL: Flag attribute to indicate the
+ *	complete config set through QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET
+ *	is to be cleared in the driver.
+ *	This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR
+ *	and shall be ignored if used with other sub commands.
+ *	If this attribute is specified along with subcmd
+ *	QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR, the driver shall ignore
+ *	all other attributes, if there are any.
+ *	If this attribute is not specified when the subcmd
+ *	QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR is sent, the driver shall
+ *	clear the data corresponding to the attributes specified.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME: Nested attribute to carry the
+ *	list of frequencies and its type, represented by
+ *	enum qca_vendor_attr_scan_freq_list_scheme.
+ *	Frequency list and its type are mandatory for this attribute to set
+ *	the frequencies.
+ *	Frequency type is mandatory for this attribute to get the frequencies
+ *	and the frequency list is obtained through
+ *	QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST.
+ *	Frequency list type is mandatory for this attribute to clear the
+ *	frequencies.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD: Unsigned 32-bit value.
+ *	Carries the value of scan period in seconds to set.
+ *	The value of scan period is obtained with the same attribute for get.
+ *	Clears the scan period in the driver when specified with clear command.
+ *	Scan period is the idle time in seconds between each subsequent
+ *	channel scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD: Unsigned 32-bit value.
+ *	Carries the value of full scan period in seconds to set.
+ *	The value of full scan period is obtained with the same attribute for
+ *	get.
+ *	Clears the full scan period in the driver when specified with clear
+ *	command. Full scan period is the idle period in seconds between two
+ *	successive full channel roam scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_TRIGGERS: Unsigned 32-bit value.
+ *	Carries a bitmap of the roam triggers specified in
+ *	enum qca_vendor_roam_triggers.
+ *	The driver shall enable roaming by enabling corresponding roam triggers
+ *	based on the trigger bits sent with this attribute.
+ *	If this attribute is not configured, the driver shall proceed with
+ *	default behavior.
+ *	The bitmap configured is obtained with the same attribute for get.
+ *	Clears the bitmap configured in driver when specified with clear
+ *	command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA: Nested attribute signifying the
+ *	weightage in percentage (%) to be given for each selection criteria.
+ *	Different roam candidate selection criteria are represented by
+ *	enum qca_vendor_attr_roam_candidate_selection_criteria.
+ *	The driver shall select the roam candidate based on corresponding
+ *	candidate selection scores sent.
+ *
+ *	An empty nested attribute is used to indicate that no specific
+ *	preference score/criteria is configured (i.e., to disable this mechanism
+ *	in the set case and to show that the mechanism is disabled in the get
+ *	case).
+ *
+ *	Userspace can send multiple attributes out of this enum to the driver.
+ *	Since this attribute represents the weight/percentage of preference for
+ *	the respective selection criteria, it is preferred to configure 100%
+ *	total weightage. The value in each attribute or cumulative weight of the
+ *	values in all the nested attributes should not exceed 100%. The driver
+ *	shall reject such configuration.
+ *
+ *	If the weights configured through this attribute are less than 100%,
+ *	the driver shall honor the weights (x%) passed for the corresponding
+ *	selection criteria and choose/distribute rest of the weight (100-x)%
+ *	for the other selection criteria, based on its internal logic.
+ *
+ *	The selection criteria configured is obtained with the same
+ *	attribute for get.
+ *
+ *	Clears the selection criteria configured in the driver when specified
+ *	with clear command.
+ */
+enum qca_vendor_attr_roam_control {
+	QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
+	QCA_ATTR_ROAM_CONTROL_STATUS = 2,
+	QCA_ATTR_ROAM_CONTROL_CLEAR_ALL = 3,
+	QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME= 4,
+	QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD = 5,
+	QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6,
+	QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7,
+	QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA = 8,
+
+	/* keep last */
+	QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
+	QCA_ATTR_ROAM_CONTROL_MAX =
+	QCA_ATTR_ROAM_CONTROL_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roaming_config_params: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD: Unsigned 32-bit value.
+ *	Represents the different roam sub commands referred by
+ *	enum qca_wlan_vendor_roaming_subcmd.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID: Unsigned 32-bit value.
+ *	Represents the Request ID for the specific set of commands.
+ *	This also helps to map specific set of commands to the respective
+ *	ID / client. e.g., helps to identify the user entity configuring the
+ *	Blacklist BSSID and accordingly clear the respective ones with the
+ *	matching ID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned
+ *	32-bit value.Represents the number of whitelist SSIDs configured.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: Nested attribute
+ *	to carry the list of Whitelist SSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: SSID (binary attribute,
+ *	0..32 octets). Represents the white list SSID. Whitelist SSIDs
+ *	represent the list of SSIDs to which the firmware/driver can consider
+ *	to roam to.
+ *
+ * The following PARAM_A_BAND_XX attributes are applied to 5GHz BSSIDs when
+ * comparing with a 2.4GHz BSSID. They are not applied when comparing two
+ * 5GHz BSSIDs.The following attributes are set through the Roaming SUBCMD -
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD: Signed 32-bit
+ *	value, RSSI threshold above which 5GHz RSSI is favored.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD: Signed 32-bit
+ *	value, RSSI threshold below which 5GHz RSSI is penalized.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR: Unsigned 32-bit
+ *	value, factor by which 5GHz RSSI is boosted.
+ *	boost=(RSSI_measured-5GHz_boost_threshold)*5GHz_boost_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR: Unsigned 32-bit
+ *	value, factor by which 5GHz RSSI is penalized.
+ *	penalty=(5GHz_penalty_threshold-RSSI_measured)*5GHz_penalty_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST: Unsigned 32-bit
+ *	value, maximum boost that can be applied to a 5GHz RSSI.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS: Unsigned 32-bit
+ *	value, boost applied to current BSSID to ensure the currently
+ *	associated BSSID is favored so as to prevent ping-pong situations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER: Signed 32-bit
+ *	value, RSSI below which "Alert" roam is enabled.
+ *	"Alert" mode roaming - firmware is "urgently" hunting for another BSSID
+ *	because the RSSI is low, or because many successive beacons have been
+ *	lost or other bad link conditions.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: Unsigned 32-bit
+ *	value. 1-Enable, 0-Disable. Represents "Lazy" mode, where
+ *	firmware is hunting for a better BSSID or white listed SSID even though
+ *	the RSSI of the link is good. The parameters enabling the roaming are
+ *	configured through the PARAM_A_BAND_XX attrbutes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS: Nested attribute,
+ *	represents the BSSIDs preferred over others while evaluating them
+ *	for the roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID: Unsigned
+ *	32-bit value. Represents the number of preferred BSSIDs set.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID: 6-byte MAC
+ *	address representing the BSSID to be preferred.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER: Signed
+ *	32-bit value, representing the modifier to be applied to the RSSI of
+ *	the BSSID for the purpose of comparing it with other roam candidate.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: Nested attribute,
+ *	represents the BSSIDs to get blacklisted for roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: Unsigned
+ *	32-bit value, represents the number of blacklisted BSSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: 6-byte MAC
+ *	address representing the Blacklisted BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT: Flag attribute,
+ *	indicates this BSSID blacklist as a hint to the driver. The driver can
+ *	select this BSSID in the worst case (when no other BSSIDs are better).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL: Nested attribute to
+ *	set/get/clear the roam control config as
+ *	defined @enum qca_vendor_attr_roam_control.
+ */
 enum qca_wlan_vendor_attr_roaming_config_params {
 	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
 
@@ -3366,6 +3956,8 @@
 	/* Flag attribute indicates this BSSID blacklist as a hint */
 	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
 
+	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL = 22,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
@@ -3373,22 +3965,63 @@
 };
 
 /*
- * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
- * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ * enum qca_wlan_vendor_roaming_subcmd: Referred by
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST: Sub command to
+ *	configure the white list SSIDs. These are configured through
+ *	the following attributes.
+ *	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS,
+ *	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST,
+ *	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS: Sub command to
+ *	configure the Roam params. These parameters are evaluated on the GScan
+ *	results. Refers the attributes PARAM_A_BAND_XX above to configure the
+ *	params.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM: Sets the Lazy roam. Uses
+ *	the attribute QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE
+ *	to enable/disable Lazy roam.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS: Sets the BSSID
+ *	preference. Contains the attribute
+ *	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS to set the BSSID
+ *	preference.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the Blacklist
+ *	BSSIDs. Refers QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to
+ *	set the same.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: Command to set the
+ *	roam control config to the driver with the attribute
+ *	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET: Command to obtain the
+ *	roam control config from driver with the attribute
+ *	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ *	For the get, the attribute for the configuration to be queried shall
+ *	carry any of its acceptable value to the driver. In return, the driver
+ *	shall send the configured values within the same attribute to the user
+ *	space.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR: Command to clear the
+ *	roam control config in the driver with the attribute
+ *	QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ *	The driver shall continue with its default roaming behavior when data
+ *	corresponding to an attribute is cleared.
  */
-enum qca_wlan_vendor_attr_roam_subcmd {
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
-
-	/* keep last */
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
-	QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+enum qca_wlan_vendor_roaming_subcmd {
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_INVALID = 0,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST = 1,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM = 3,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS = 4,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PARAMS = 5,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID = 6,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET = 7,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET = 8,
+	QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR = 9,
 };
 
 enum qca_wlan_vendor_attr_gscan_config_params {
@@ -3756,8 +4389,8 @@
 
 	/* Unsigned 32-bit value; a GSCAN Capabilities attribute.
 	 * This is used to limit the maximum number of BSSIDs while sending
-	 * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with attributes
-	 * QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID and
+	 * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with subcmd
+	 * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID and attribute
 	 * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
 	 */
 	QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
@@ -3859,6 +4492,44 @@
 	QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS,
 	/* Represents the reason that LTE co-exist in the current band. */
 	QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX,
+	/* Represents the reason that generic, uncategorized interference has
+	 * been found in the current channel.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_GENERIC_INTERFERENCE,
+	/* Represents the reason that excessive 802.11 interference has been
+	 * found in the current channel.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_80211_INTERFERENCE,
+	/* Represents the reason that generic Continuous Wave (CW) interference
+	 * has been found in the current channel.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_CW_INTERFERENCE,
+	/* Represents the reason that Microwave Oven (MWO) interference has been
+	 * found in the current channel.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_MWO_INTERFERENCE,
+	/* Represents the reason that generic Frequency-Hopping Spread Spectrum
+	 * (FHSS) interference has been found in the current channel. This may
+	 * include 802.11 waveforms.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_FHSS_INTERFERENCE,
+	/* Represents the reason that non-802.11 generic Frequency-Hopping
+	 * Spread Spectrum (FHSS) interference has been found in the current
+	 * channel.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_FHSS_INTERFERENCE,
+	/* Represents the reason that generic Wideband (WB) interference has
+	 * been found in the current channel. This may include 802.11 waveforms.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_WB_INTERFERENCE,
+	/* Represents the reason that non-802.11 generic Wideband (WB)
+	 * interference has been found in the current channel.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_WB_INTERFERENCE,
+	/* Represents the reason that Jammer interference has been found in the
+	 * current channel.
+	 */
+	QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE,
 };
 
 /**
@@ -4026,6 +4697,46 @@
 	 */
 	QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2 = 11,
 
+	/*
+	 * VHT segment 0 in MHz (u32) and the attribute is mandatory.
+	 * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+	 * along with
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0.
+	 *
+	 * If both the driver and user-space application supports the 6 GHz
+	 * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0
+	 * is deprecated and
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+	 * should be used.
+	 *
+	 * To maintain backward compatibility,
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+	 * is still used if either of the driver or user space application
+	 * doesn't support the 6 GHz band.
+	 */
+	QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 = 12,
+
+	/*
+	 * VHT segment 1 in MHz (u32) and the attribute is mandatory.
+	 * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+	 * along with
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1.
+	 *
+	 * If both the driver and user-space application supports the 6 GHz
+	 * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1
+	 * is deprecated and
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+	 * should be considered.
+	 *
+	 * To maintain backward compatibility,
+	 * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+	 * is still used if either of the driver or user space application
+	 * doesn't support the 6 GHz band.
+	 */
+	QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
 	QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
@@ -4126,9 +4837,100 @@
 };
 
 /**
- * qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
+ * enum qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
  * QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This carries a list of channels
  * in priority order as decided after ACS operation in userspace.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON: Required (u8).
+ * One of reason code from enum qca_wlan_vendor_acs_select_reason.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ *     QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY,
+ *     QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY,
+ *     QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0,
+ *     QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1,
+ *     QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY: Required (u8).
+ * Primary channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY: Required (u8).
+ * Secondary channel number, required only for 160 and 80+80 MHz bandwidths.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0: Required (u8).
+ * VHT seg0 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1: Required (u8).
+ * VHT seg1 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH: Required (u8).
+ * Takes one of enum nl80211_chan_width values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ *	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY in MHz (u32),
+ *	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY in MHz (u32),
+ *	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 in MHz (u32),
+ *	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 in MHz (u32),
+ *	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY: Required (u32)
+ * Primary channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY: Required (u32)
+ * Secondary channel frequency in MHz used for HT 40 MHz channels.
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0: Required (u32)
+ * VHT seg0 channel frequency in MHz
+ * Note: If user-space application has no support of the 6GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1: Required (u32)
+ * VHT seg1 channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
  */
 enum qca_wlan_vendor_attr_external_acs_channels {
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0,
@@ -4159,6 +4961,12 @@
 	/* Channel width (u8). Takes one of enum nl80211_chan_width values. */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH = 8,
 
+	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST = 9,
+	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY = 10,
+	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY = 11,
+	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 = 12,
+	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 = 13,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST,
 	QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX =
@@ -4676,8 +5484,18 @@
 	 * u8 attribute.
 	 */
 	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
-	/* Flag attribute to indicate agile spectral scan capability */
+	/* Flag attribute to indicate agile spectral scan capability
+	 * for 20/40/80 MHz modes.
+	 */
 	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL = 11,
+	/* Flag attribute to indicate agile spectral scan capability
+	 * for 160 MHz mode.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_160 = 12,
+	/* Flag attribute to indicate agile spectral scan capability
+	 * for 80+80 MHz mode.
+	 */
+	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_80_80 = 13,
 
 	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@@ -7102,4 +7920,130 @@
 		QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
 };
 
+/**
+ * enum qca_vendor_oem_device_type - Represents the target device in firmware.
+ * It is used by QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_VIRTUAL: The command is intended for
+ * a virtual device.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_PHYSICAL: The command is intended for
+ * a physical device.
+ */
+enum qca_vendor_oem_device_type {
+	QCA_VENDOR_OEM_DEVICE_VIRTUAL = 0,
+	QCA_VENDOR_OEM_DEVICE_PHYSICAL = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command/event
+ * QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
+ * command/event QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this
+ * attribute.
+ * NLA_BINARY attribute, the max size is 1024 bytes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO: The binary blob will be routed
+ * based on this field. This optional attribute is included to specify whether
+ * the device type is a virtual device or a physical device for the
+ * command/event. This attribute can be omitted for a virtual device (default)
+ * command/event.
+ * This u8 attribute is used to carry information for the device type using
+ * values defined by enum qca_vendor_oem_device_type.
+ */
+enum qca_wlan_vendor_attr_oem_data_params {
+	QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
+	QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX =
+		QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext - Defines attributes to be
+ * used with vendor command/event QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE: Required
+ * Nested attribute containing multiple ranges with following attributes:
+ *	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START and
+ *	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START: Required (u32)
+ * Starting center frequency in MHz.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END: Required (u32)
+ * Ending center frequency in MHz.
+ */
+enum qca_wlan_vendor_attr_avoid_frequency_ext {
+	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE = 1,
+	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START = 2,
+	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END = 3,
+
+	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX =
+		QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST - 1
+};
+
+/*
+ * enum qca_wlan_vendor_attr_add_sta_node_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE.
+ */
+enum qca_wlan_vendor_attr_add_sta_node_params {
+	QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_INVALID = 0,
+	/* 6 byte MAC address of STA */
+	QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR = 1,
+	/* Authentication algorithm used by the station of size u16;
+	 * defined in enum nl80211_auth_type.
+	 */
+	QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX =
+		QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_btc_chain_mode - Specifies BT coex chain mode.
+ * This enum defines the valid set of values of BT coex chain mode.
+ * These values are used by attribute %QCA_VENDOR_ATTR_BTC_CHAIN_MODE of
+ * %QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4G are shared.
+ * @QCA_BTC_CHAIN_SEPARATED: chains of BT and WLAN 2.4G are separated.
+ */
+enum qca_btc_chain_mode {
+	QCA_BTC_CHAIN_SHARED = 0,
+	QCA_BTC_CHAIN_SEPARATED = 1,
+};
+
+/**
+ * enum qca_vendor_attr_btc_chain_mode - Specifies attributes for BT coex
+ * chain mode.
+ * Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE: u32 attribute.
+ * Indicates the BT coex chain mode, are 32-bit values from
+ * enum qca_btc_chain_mode. This attribute is mandatory.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE_RESTART: flag attribute.
+ * If set, vdev should be restarted when BT coex chain mode is updated.
+ * This attribute is optional.
+ */
+enum qca_vendor_attr_btc_chain_mode {
+	QCA_VENDOR_ATTR_BTC_CHAIN_MODE_INVALID = 0,
+	QCA_VENDOR_ATTR_BTC_CHAIN_MODE = 1,
+	QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART = 2,
+
+	/* Keep last */
+	QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST,
+	QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX =
+	QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 0da7145..2ab168b 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -12,6 +12,8 @@
 #include "utils/const_time.h"
 #include "crypto/crypto.h"
 #include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
 #include "crypto/random.h"
 #include "crypto/dh_groups.h"
 #include "ieee802_11_defs.h"
@@ -45,6 +47,7 @@
 		sae->group = group;
 		tmp->prime_len = crypto_ec_prime_len(tmp->ec);
 		tmp->prime = crypto_ec_get_prime(tmp->ec);
+		tmp->order_len = crypto_ec_order_len(tmp->ec);
 		tmp->order = crypto_ec_get_order(tmp->ec);
 		return 0;
 	}
@@ -69,6 +72,7 @@
 		}
 		tmp->prime = tmp->prime_buf;
 
+		tmp->order_len = tmp->dh->order_len;
 		tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
 							tmp->dh->order_len);
 		if (tmp->order_buf == NULL) {
@@ -105,6 +109,8 @@
 	crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
 	crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
 	wpabuf_free(tmp->anti_clogging_token);
+	wpabuf_free(tmp->own_rejected_groups);
+	wpabuf_free(tmp->peer_rejected_groups);
 	os_free(tmp->pw_id);
 	bin_clear_free(tmp, sizeof(*tmp));
 	sae->tmp = NULL;
@@ -275,7 +281,7 @@
 			      const u8 *addr2, const u8 *password,
 			      size_t password_len, const char *identifier)
 {
-	u8 counter, k = 40;
+	u8 counter, k;
 	u8 addrs[2 * ETH_ALEN];
 	const u8 *addr[3];
 	size_t len[3];
@@ -346,6 +352,8 @@
 	 * attacks that attempt to determine the number of iterations required
 	 * in the loop.
 	 */
+	k = dragonfly_min_pwe_loop_iter(sae->group);
+
 	for (counter = 1; counter <= k || !found; counter++) {
 		u8 pwd_seed[SHA256_MAC_LEN];
 
@@ -427,13 +435,6 @@
 }
 
 
-static int sae_modp_group_require_masking(int group)
-{
-	/* Groups for which pwd-value is likely to be >= p frequently */
-	return group == 22 || group == 23 || group == 24;
-}
-
-
 static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
 			      const u8 *addr2, const u8 *password,
 			      size_t password_len, const char *identifier)
@@ -482,7 +483,7 @@
 	len[num_elem] = sizeof(counter);
 	num_elem++;
 
-	k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
+	k = dragonfly_min_pwe_loop_iter(sae->group);
 
 	for (counter = 1; counter <= k || !found; counter++) {
 		u8 pwd_seed[SHA256_MAC_LEN];
@@ -528,6 +529,742 @@
 }
 
 
+static int hkdf_extract(size_t hash_len, const u8 *salt, size_t salt_len,
+			size_t num_elem, const u8 *addr[], const size_t len[],
+			u8 *prk)
+{
+	if (hash_len == 32)
+		return hmac_sha256_vector(salt, salt_len, num_elem, addr, len,
+					  prk);
+#ifdef CONFIG_SHA384
+	if (hash_len == 48)
+		return hmac_sha384_vector(salt, salt_len, num_elem, addr, len,
+					  prk);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+	if (hash_len == 64)
+		return hmac_sha512_vector(salt, salt_len, num_elem, addr, len,
+					  prk);
+#endif /* CONFIG_SHA512 */
+	return -1;
+}
+
+
+static int hkdf_expand(size_t hash_len, const u8 *prk, size_t prk_len,
+		       const char *info, u8 *okm, size_t okm_len)
+{
+	size_t info_len = os_strlen(info);
+
+	if (hash_len == 32)
+		return hmac_sha256_kdf(prk, prk_len, NULL,
+				       (const u8 *) info, info_len,
+				       okm, okm_len);
+#ifdef CONFIG_SHA384
+	if (hash_len == 48)
+		return hmac_sha384_kdf(prk, prk_len, NULL,
+				       (const u8 *) info, info_len,
+				       okm, okm_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+	if (hash_len == 64)
+		return hmac_sha512_kdf(prk, prk_len, NULL,
+				       (const u8 *) info, info_len,
+				       okm, okm_len);
+#endif /* CONFIG_SHA512 */
+	return -1;
+}
+
+
+static int sswu_curve_param(int group, int *z)
+{
+	switch (group) {
+	case 19:
+	case 20:
+	case 21:
+	case 28:
+		*z = -2;
+		return 0;
+	case 25:
+	case 29:
+		*z = -5;
+		return 0;
+	case 26:
+		*z = -11;
+		return 0;
+	case 30:
+		*z = 2;
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static void debug_print_bignum(const char *title, const struct crypto_bignum *a,
+			       size_t prime_len)
+{
+	u8 *bin;
+
+	bin = os_malloc(prime_len);
+	if (bin && crypto_bignum_to_bin(a, bin, prime_len, prime_len) >= 0)
+		wpa_hexdump_key(MSG_DEBUG, title, bin, prime_len);
+	else
+		wpa_printf(MSG_DEBUG, "Could not print bignum (%s)", title);
+	bin_clear_free(bin, prime_len);
+}
+
+
+static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
+				     const struct crypto_bignum *u)
+{
+	int z_int;
+	const struct crypto_bignum *a, *b, *prime;
+	struct crypto_bignum *u2, *t1, *t2, *z, *t, *zero, *one, *two, *three,
+		*x1a, *x1b, *y = NULL;
+	struct crypto_bignum *x1 = NULL, *x2, *gx1, *gx2, *v = NULL;
+	unsigned int m_is_zero, is_qr, is_eq;
+	size_t prime_len;
+	u8 bin[SAE_MAX_ECC_PRIME_LEN];
+	u8 bin1[SAE_MAX_ECC_PRIME_LEN];
+	u8 bin2[SAE_MAX_ECC_PRIME_LEN];
+	u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
+	struct crypto_ec_point *p = NULL;
+
+	if (sswu_curve_param(group, &z_int) < 0)
+		return NULL;
+
+	prime = crypto_ec_get_prime(ec);
+	prime_len = crypto_ec_prime_len(ec);
+	a = crypto_ec_get_a(ec);
+	b = crypto_ec_get_b(ec);
+
+	u2 = crypto_bignum_init();
+	t1 = crypto_bignum_init();
+	t2 = crypto_bignum_init();
+	z = crypto_bignum_init_uint(abs(z_int));
+	t = crypto_bignum_init();
+	zero = crypto_bignum_init_uint(0);
+	one = crypto_bignum_init_uint(1);
+	two = crypto_bignum_init_uint(2);
+	three = crypto_bignum_init_uint(3);
+	x1a = crypto_bignum_init();
+	x1b = crypto_bignum_init();
+	x2 = crypto_bignum_init();
+	gx1 = crypto_bignum_init();
+	gx2 = crypto_bignum_init();
+	if (!u2 || !t1 || !t2 || !z || !t || !zero || !one || !two || !three ||
+	    !x1a || !x1b || !x2 || !gx1 || !gx2)
+		goto fail;
+
+	if (z_int < 0 && crypto_bignum_sub(prime, z, z) < 0)
+		goto fail;
+
+	/* m = z^2 * u^4 + z * u^2 */
+	/* --> tmp = z * u^2, m = tmp^2 + tmp */
+
+	/* u2 = u^2
+	 * t1 = z * u2
+	 * t2 = t1^2
+	 * m = t1 = t1 + t2 */
+	if (crypto_bignum_sqrmod(u, prime, u2) < 0 ||
+	    crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+	    crypto_bignum_sqrmod(t1, prime, t2) < 0 ||
+	    crypto_bignum_addmod(t1, t2, prime, t1) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: m", t1, prime_len);
+
+	/* l = CEQ(m, 0)
+	 * t = CSEL(l, 0, inverse(m); where inverse(x) is calculated as
+	 * x^(p-2) modulo p which will handle m == 0 case correctly */
+	/* TODO: Make sure crypto_bignum_is_zero() is constant time */
+	m_is_zero = const_time_eq(crypto_bignum_is_zero(t1), 1);
+	/* t = m^(p-2) modulo p */
+	if (crypto_bignum_sub(prime, two, t2) < 0 ||
+	    crypto_bignum_exptmod(t1, t2, prime, t) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: t", t, prime_len);
+
+	/* b / (z * a) */
+	if (crypto_bignum_mulmod(z, a, prime, t1) < 0 ||
+	    crypto_bignum_inverse(t1, prime, t1) < 0 ||
+	    crypto_bignum_mulmod(b, t1, prime, x1a) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: x1a = b / (z * a)", x1a, prime_len);
+
+	/* (-b/a) * (1 + t) */
+	if (crypto_bignum_sub(prime, b, t1) < 0 ||
+	    crypto_bignum_inverse(a, prime, t2) < 0 ||
+	    crypto_bignum_mulmod(t1, t2, prime, t1) < 0 ||
+	    crypto_bignum_addmod(one, t, prime, t2) < 0 ||
+	    crypto_bignum_mulmod(t1, t2, prime, x1b) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: x1b = (-b/a) * (1 + t)", x1b, prime_len);
+
+	/* x1 = CSEL(CEQ(m, 0), x1a, x1b) */
+	if (crypto_bignum_to_bin(x1a, bin1, sizeof(bin1), prime_len) < 0 ||
+	    crypto_bignum_to_bin(x1b, bin2, sizeof(bin2), prime_len) < 0)
+		goto fail;
+	const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
+	x1 = crypto_bignum_init_set(bin, prime_len);
+	debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
+
+	/* gx1 = x1^3 + a * x1 + b */
+	if (crypto_bignum_exptmod(x1, three, prime, t1) < 0 ||
+	    crypto_bignum_mulmod(a, x1, prime, t2) < 0 ||
+	    crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+	    crypto_bignum_addmod(t1, b, prime, gx1) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: gx1 = x1^3 + a * x1 + b", gx1, prime_len);
+
+	/* x2 = z * u^2 * x1 */
+	if (crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+	    crypto_bignum_mulmod(t1, x1, prime, x2) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: x2 = z * u^2 * x1", x2, prime_len);
+
+	/* gx2 = x2^3 + a * x2 + b */
+	if (crypto_bignum_exptmod(x2, three, prime, t1) < 0 ||
+	    crypto_bignum_mulmod(a, x2, prime, t2) < 0 ||
+	    crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+	    crypto_bignum_addmod(t1, b, prime, gx2) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: gx2 = x2^3 + a * x2 + b", gx2, prime_len);
+
+	/* l = gx1 is a quadratic residue modulo p
+	 * --> gx1^((p-1)/2) modulo p is zero or one */
+	if (crypto_bignum_sub(prime, one, t1) < 0 ||
+	    crypto_bignum_rshift(t1, 1, t1) < 0 ||
+	    crypto_bignum_exptmod(gx1, t1, prime, t1) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: gx1^((p-1)/2) modulo p", t1, prime_len);
+	is_qr = const_time_eq(crypto_bignum_is_zero(t1) |
+			      crypto_bignum_is_one(t1), 1);
+
+	/* v = CSEL(l, gx1, gx2) */
+	if (crypto_bignum_to_bin(gx1, bin1, sizeof(bin1), prime_len) < 0 ||
+	    crypto_bignum_to_bin(gx2, bin2, sizeof(bin2), prime_len) < 0)
+		goto fail;
+	const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
+	v = crypto_bignum_init_set(bin, prime_len);
+	debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
+
+	/* x = CSEL(l, x1, x2) */
+	if (crypto_bignum_to_bin(x1, bin1, sizeof(bin1), prime_len) < 0 ||
+	    crypto_bignum_to_bin(x2, bin2, sizeof(bin2), prime_len) < 0)
+		goto fail;
+	const_time_select_bin(is_qr, bin1, bin2, prime_len, x_y);
+	wpa_hexdump_key(MSG_DEBUG, "SSWU: x = CSEL(l, x1, x2)", x_y, prime_len);
+
+	/* y = sqrt(v)
+	 * For prime p such that p = 3 mod 4 --> v^((p+1)/4) */
+	if (crypto_bignum_to_bin(prime, bin1, sizeof(bin1), prime_len) < 0)
+		goto fail;
+	if ((bin1[prime_len - 1] & 0x03) != 3) {
+		wpa_printf(MSG_DEBUG, "SSWU: prime does not have p = 3 mod 4");
+		goto fail;
+	}
+	y = crypto_bignum_init();
+	if (!y ||
+	    crypto_bignum_add(prime, one, t1) < 0 ||
+	    crypto_bignum_rshift(t1, 2, t1) < 0 ||
+	    crypto_bignum_exptmod(v, t1, prime, y) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: y = sqrt(v)", y, prime_len);
+
+	/* l = CEQ(LSB(u), LSB(y)) */
+	if (crypto_bignum_to_bin(u, bin1, sizeof(bin1), prime_len) < 0 ||
+	    crypto_bignum_to_bin(y, bin2, sizeof(bin2), prime_len) < 0)
+		goto fail;
+	is_eq = const_time_eq(bin1[prime_len - 1] & 0x01,
+			      bin2[prime_len - 1] & 0x01);
+
+	/* P = CSEL(l, (x,y), (x, p-y)) */
+	if (crypto_bignum_sub(prime, y, t1) < 0)
+		goto fail;
+	debug_print_bignum("SSWU: p - y", t1, prime_len);
+	if (crypto_bignum_to_bin(y, bin1, sizeof(bin1), prime_len) < 0 ||
+	    crypto_bignum_to_bin(t1, bin2, sizeof(bin2), prime_len) < 0)
+		goto fail;
+	const_time_select_bin(is_eq, bin1, bin2, prime_len, &x_y[prime_len]);
+
+	/* output P */
+	wpa_hexdump_key(MSG_DEBUG, "SSWU: P.x", x_y, prime_len);
+	wpa_hexdump_key(MSG_DEBUG, "SSWU: P.y", &x_y[prime_len], prime_len);
+	p = crypto_ec_point_from_bin(ec, x_y);
+
+fail:
+	crypto_bignum_deinit(u2, 1);
+	crypto_bignum_deinit(t1, 1);
+	crypto_bignum_deinit(t2, 1);
+	crypto_bignum_deinit(z, 0);
+	crypto_bignum_deinit(t, 1);
+	crypto_bignum_deinit(x1a, 1);
+	crypto_bignum_deinit(x1b, 1);
+	crypto_bignum_deinit(x1, 1);
+	crypto_bignum_deinit(x2, 1);
+	crypto_bignum_deinit(gx1, 1);
+	crypto_bignum_deinit(gx2, 1);
+	crypto_bignum_deinit(y, 1);
+	crypto_bignum_deinit(v, 1);
+	crypto_bignum_deinit(zero, 0);
+	crypto_bignum_deinit(one, 0);
+	crypto_bignum_deinit(two, 0);
+	crypto_bignum_deinit(three, 0);
+	forced_memzero(bin, sizeof(bin));
+	forced_memzero(bin1, sizeof(bin1));
+	forced_memzero(bin2, sizeof(bin2));
+	forced_memzero(x_y, sizeof(x_y));
+	return p;
+}
+
+
+static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len,
+			const u8 *password, size_t password_len,
+			const char *identifier, u8 *pwd_seed)
+{
+	const u8 *addr[2];
+	size_t len[2];
+	size_t num_elem;
+
+	/* pwd-seed = HKDF-Extract(ssid, password [ || identifier ]) */
+	addr[0] = password;
+	len[0] = password_len;
+	num_elem = 1;
+	wpa_hexdump_ascii(MSG_DEBUG, "SAE: SSID", ssid, ssid_len);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+			      password, password_len);
+	if (identifier) {
+		wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+			   identifier);
+		addr[num_elem] = (const u8 *) identifier;
+		len[num_elem] = os_strlen(identifier);
+		num_elem++;
+	}
+	if (hkdf_extract(hash_len, ssid, ssid_len, num_elem, addr, len,
+			 pwd_seed) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, hash_len);
+	return 0;
+}
+
+
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len)
+{
+	if (prime_len <= 256 / 8)
+		return 32;
+	if (prime_len <= 384 / 8)
+		return 48;
+	return 64;
+}
+
+
+struct crypto_ec_point *
+sae_derive_pt_ecc(struct crypto_ec *ec, int group,
+		  const u8 *ssid, size_t ssid_len,
+		  const u8 *password, size_t password_len,
+		  const char *identifier)
+{
+	u8 pwd_seed[64];
+	u8 pwd_value[SAE_MAX_ECC_PRIME_LEN * 2];
+	size_t pwd_value_len, hash_len, prime_len;
+	const struct crypto_bignum *prime;
+	struct crypto_bignum *bn = NULL;
+	struct crypto_ec_point *p1 = NULL, *p2 = NULL, *pt = NULL;
+
+	prime = crypto_ec_get_prime(ec);
+	prime_len = crypto_ec_prime_len(ec);
+	if (prime_len > SAE_MAX_ECC_PRIME_LEN)
+		goto fail;
+	hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+
+	/* len = olen(p) + ceil(olen(p)/2) */
+	pwd_value_len = prime_len + (prime_len + 1) / 2;
+
+	if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+			 identifier, pwd_seed) < 0)
+		goto fail;
+
+	/* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len)
+	 */
+	if (hkdf_expand(hash_len, pwd_seed, hash_len,
+			"SAE Hash to Element u1 P1", pwd_value, pwd_value_len) <
+	    0)
+		goto fail;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u1 P1)",
+			pwd_value, pwd_value_len);
+
+	/* u1 = pwd-value modulo p */
+	bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+	if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+	    crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+				 prime_len) < 0)
+		goto fail;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: u1", pwd_value, prime_len);
+
+	/* P1 = SSWU(u1) */
+	p1 = sswu(ec, group, bn);
+	if (!p1)
+		goto fail;
+
+	/* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u2 P2", len)
+	 */
+	if (hkdf_expand(hash_len, pwd_seed, hash_len,
+			"SAE Hash to Element u2 P2", pwd_value,
+			pwd_value_len) < 0)
+		goto fail;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u2 P2)",
+			pwd_value, pwd_value_len);
+
+	/* u2 = pwd-value modulo p */
+	crypto_bignum_deinit(bn, 1);
+	bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+	if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+	    crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+				 prime_len) < 0)
+		goto fail;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: u2", pwd_value, prime_len);
+
+	/* P2 = SSWU(u2) */
+	p2 = sswu(ec, group, bn);
+	if (!p2)
+		goto fail;
+
+	/* PT = elem-op(P1, P2) */
+	pt = crypto_ec_point_init(ec);
+	if (!pt)
+		goto fail;
+	if (crypto_ec_point_add(ec, p1, p2, pt) < 0) {
+		crypto_ec_point_deinit(pt, 1);
+		pt = NULL;
+	}
+
+fail:
+	forced_memzero(pwd_seed, sizeof(pwd_seed));
+	forced_memzero(pwd_value, sizeof(pwd_value));
+	crypto_bignum_deinit(bn, 1);
+	crypto_ec_point_deinit(p1, 1);
+	crypto_ec_point_deinit(p2, 1);
+	return pt;
+}
+
+
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len)
+{
+	if (prime_len <= 2048 / 8)
+		return 32;
+	if (prime_len <= 3072 / 8)
+		return 48;
+	return 64;
+}
+
+
+static struct crypto_bignum *
+sae_derive_pt_ffc(const struct dh_group *dh, int group,
+		  const u8 *ssid, size_t ssid_len,
+		  const u8 *password, size_t password_len,
+		  const char *identifier)
+{
+	size_t hash_len, prime_len, pwd_value_len;
+	struct crypto_bignum *prime, *order;
+	struct crypto_bignum *one = NULL, *two = NULL, *bn = NULL, *tmp = NULL,
+		*pt = NULL;
+	u8 pwd_seed[64];
+	u8 pwd_value[SAE_MAX_PRIME_LEN + SAE_MAX_PRIME_LEN / 2];
+
+	prime = crypto_bignum_init_set(dh->prime, dh->prime_len);
+	order = crypto_bignum_init_set(dh->order, dh->order_len);
+	if (!prime || !order)
+		goto fail;
+	prime_len = dh->prime_len;
+	if (prime_len > SAE_MAX_PRIME_LEN)
+		goto fail;
+	hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+
+	/* len = olen(p) + ceil(olen(p)/2) */
+	pwd_value_len = prime_len + (prime_len + 1) / 2;
+	if (pwd_value_len > sizeof(pwd_value))
+		goto fail;
+
+	if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+			 identifier, pwd_seed) < 0)
+		goto fail;
+
+	/* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element", len) */
+	if (hkdf_expand(hash_len, pwd_seed, hash_len,
+			"SAE Hash to Element", pwd_value, pwd_value_len) < 0)
+		goto fail;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+			pwd_value, pwd_value_len);
+
+	/* pwd-value = (pwd-value modulo (p-2)) + 2 */
+	bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+	one = crypto_bignum_init_uint(1);
+	two = crypto_bignum_init_uint(2);
+	tmp = crypto_bignum_init();
+	if (!bn || !one || !two || !tmp ||
+	    crypto_bignum_sub(prime, two, tmp) < 0 ||
+	    crypto_bignum_mod(bn, tmp, bn) < 0 ||
+	    crypto_bignum_add(bn, two, bn) < 0 ||
+	    crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+				 prime_len) < 0)
+		goto fail;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value(reduced)",
+			pwd_value, prime_len);
+
+	/* PT = pwd-value^((p-1)/q) modulo p */
+	pt = crypto_bignum_init();
+	if (!pt ||
+	    crypto_bignum_sub(prime, one, tmp) < 0 ||
+	    crypto_bignum_div(tmp, order, tmp) < 0 ||
+	    crypto_bignum_exptmod(bn, tmp, prime, pt) < 0) {
+		crypto_bignum_deinit(pt, 1);
+		pt = NULL;
+		goto fail;
+	}
+	debug_print_bignum("SAE: PT", pt, prime_len);
+
+fail:
+	forced_memzero(pwd_seed, sizeof(pwd_seed));
+	forced_memzero(pwd_value, sizeof(pwd_value));
+	crypto_bignum_deinit(bn, 1);
+	crypto_bignum_deinit(tmp, 1);
+	crypto_bignum_deinit(one, 0);
+	crypto_bignum_deinit(two, 0);
+	crypto_bignum_deinit(prime, 0);
+	crypto_bignum_deinit(order, 0);
+	return pt;
+}
+
+
+static struct sae_pt *
+sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
+		    const u8 *password, size_t password_len,
+		    const char *identifier)
+{
+	struct sae_pt *pt;
+
+	wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
+
+	pt = os_zalloc(sizeof(*pt));
+	if (!pt)
+		return NULL;
+
+	pt->group = group;
+	pt->ec = crypto_ec_init(group);
+	if (pt->ec) {
+		pt->ecc_pt = sae_derive_pt_ecc(pt->ec, group, ssid, ssid_len,
+					       password, password_len,
+					       identifier);
+		if (!pt->ecc_pt) {
+			wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+			goto fail;
+		}
+
+		return pt;
+	}
+
+	pt->dh = dh_groups_get(group);
+	if (!pt->dh) {
+		wpa_printf(MSG_DEBUG, "SAE: Unsupported group %d", group);
+		goto fail;
+	}
+
+	pt->ffc_pt = sae_derive_pt_ffc(pt->dh, group, ssid, ssid_len,
+				       password, password_len, identifier);
+	if (!pt->ffc_pt) {
+		wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+		goto fail;
+	}
+
+	return pt;
+fail:
+	sae_deinit_pt(pt);
+	return NULL;
+}
+
+
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+			      const u8 *password, size_t password_len,
+			      const char *identifier)
+{
+	struct sae_pt *pt = NULL, *last = NULL, *tmp;
+	int default_groups[] = { 19, 0 };
+	int i;
+
+	if (!groups)
+		groups = default_groups;
+	for (i = 0; groups[i] > 0; i++) {
+		tmp = sae_derive_pt_group(groups[i], ssid, ssid_len, password,
+					  password_len, identifier);
+		if (!tmp)
+			continue;
+
+		if (last)
+			last->next = tmp;
+		else
+			pt = tmp;
+		last = tmp;
+	}
+
+	return pt;
+}
+
+
+static void sae_max_min_addr(const u8 *addr[], size_t len[],
+			     const u8 *addr1, const u8 *addr2)
+{
+	len[0] = ETH_ALEN;
+	len[1] = ETH_ALEN;
+	if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+		addr[0] = addr1;
+		addr[1] = addr2;
+	} else {
+		addr[0] = addr2;
+		addr[1] = addr1;
+	}
+}
+
+
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+			   const u8 *addr1, const u8 *addr2)
+{
+	u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+	size_t prime_len;
+	const u8 *addr[2];
+	size_t len[2];
+	u8 salt[64], hash[64];
+	size_t hash_len;
+	const struct crypto_bignum *order;
+	struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+	struct crypto_ec_point *pwe = NULL;
+
+	wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+	prime_len = crypto_ec_prime_len(pt->ec);
+	if (crypto_ec_point_to_bin(pt->ec, pt->ecc_pt,
+				   bin, bin + prime_len) < 0)
+		return NULL;
+	wpa_hexdump_key(MSG_DEBUG, "SAE: PT.x", bin, prime_len);
+	wpa_hexdump_key(MSG_DEBUG, "SAE: PT.y", bin + prime_len, prime_len);
+
+	sae_max_min_addr(addr, len, addr1, addr2);
+
+	/* val = H(0^n,
+	 *         MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+	wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+	hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+	os_memset(salt, 0, hash_len);
+	if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+		goto fail;
+	wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+	/* val = val modulo (q - 1) + 1 */
+	order = crypto_ec_get_order(pt->ec);
+	tmp = crypto_bignum_init();
+	val = crypto_bignum_init_set(hash, hash_len);
+	one = crypto_bignum_init_uint(1);
+	if (!tmp || !val || !one ||
+	    crypto_bignum_sub(order, one, tmp) < 0 ||
+	    crypto_bignum_mod(val, tmp, val) < 0 ||
+	    crypto_bignum_add(val, one, val) < 0)
+		goto fail;
+	debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+	/* PWE = scalar-op(val, PT) */
+	pwe = crypto_ec_point_init(pt->ec);
+	if (!pwe ||
+	    crypto_ec_point_mul(pt->ec, pt->ecc_pt, val, pwe) < 0 ||
+	    crypto_ec_point_to_bin(pt->ec, pwe, bin, bin + prime_len) < 0) {
+		crypto_ec_point_deinit(pwe, 1);
+		pwe = NULL;
+		goto fail;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.x", bin, prime_len);
+	wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.y", bin + prime_len, prime_len);
+
+fail:
+	crypto_bignum_deinit(tmp, 1);
+	crypto_bignum_deinit(val, 1);
+	crypto_bignum_deinit(one, 0);
+	return pwe;
+}
+
+
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+			   const u8 *addr1, const u8 *addr2)
+{
+	size_t prime_len;
+	const u8 *addr[2];
+	size_t len[2];
+	u8 salt[64], hash[64];
+	size_t hash_len;
+	struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+	struct crypto_bignum *pwe = NULL, *order = NULL, *prime = NULL;
+
+	wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+	prime = crypto_bignum_init_set(pt->dh->prime, pt->dh->prime_len);
+	order = crypto_bignum_init_set(pt->dh->order, pt->dh->order_len);
+	if (!prime || !order)
+		goto fail;
+	prime_len = pt->dh->prime_len;
+
+	sae_max_min_addr(addr, len, addr1, addr2);
+
+	/* val = H(0^n,
+	 *         MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+	wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+	hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+	os_memset(salt, 0, hash_len);
+	if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+		goto fail;
+	wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+	/* val = val modulo (q - 1) + 1 */
+	tmp = crypto_bignum_init();
+	val = crypto_bignum_init_set(hash, hash_len);
+	one = crypto_bignum_init_uint(1);
+	if (!tmp || !val || !one ||
+	    crypto_bignum_sub(order, one, tmp) < 0 ||
+	    crypto_bignum_mod(val, tmp, val) < 0 ||
+	    crypto_bignum_add(val, one, val) < 0)
+		goto fail;
+	debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+	/* PWE = scalar-op(val, PT) */
+	pwe = crypto_bignum_init();
+	if (!pwe || crypto_bignum_exptmod(pt->ffc_pt, val, prime, pwe) < 0) {
+		crypto_bignum_deinit(pwe, 1);
+		pwe = NULL;
+		goto fail;
+	}
+	debug_print_bignum("SAE: PWE", pwe, prime_len);
+
+fail:
+	crypto_bignum_deinit(tmp, 1);
+	crypto_bignum_deinit(val, 1);
+	crypto_bignum_deinit(one, 0);
+	crypto_bignum_deinit(prime, 0);
+	crypto_bignum_deinit(order, 0);
+	return pwe;
+}
+
+
+void sae_deinit_pt(struct sae_pt *pt)
+{
+	struct sae_pt *prev;
+
+	while (pt) {
+		crypto_ec_point_deinit(pt->ecc_pt, 1);
+		crypto_bignum_deinit(pt->ffc_pt, 1);
+		crypto_ec_deinit(pt->ec);
+		prev = pt;
+		pt = pt->next;
+		os_free(prev);
+	}
+}
+
+
 static int sae_derive_commit_element_ecc(struct sae_data *sae,
 					 struct crypto_bignum *mask)
 {
@@ -607,10 +1344,66 @@
 						identifier) < 0) ||
 	    (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
 						password_len,
-						identifier) < 0) ||
-	    sae_derive_commit(sae) < 0)
+						identifier) < 0))
 		return -1;
-	return 0;
+
+	sae->tmp->h2e = 0;
+	return sae_derive_commit(sae);
+}
+
+
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+			  const u8 *addr1, const u8 *addr2,
+			  int *rejected_groups)
+{
+	if (!sae->tmp)
+		return -1;
+
+	while (pt) {
+		if (pt->group == sae->group)
+			break;
+		pt = pt->next;
+	}
+	if (!pt) {
+		wpa_printf(MSG_INFO, "SAE: Could not find PT for group %u",
+			   sae->group);
+		return -1;
+	}
+
+	sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
+	wpabuf_free(sae->tmp->own_rejected_groups);
+	sae->tmp->own_rejected_groups = NULL;
+	if (rejected_groups) {
+		int count, i;
+		struct wpabuf *groups;
+
+		count = int_array_len(rejected_groups);
+		groups = wpabuf_alloc(count * 2);
+		if (!groups)
+			return -1;
+		for (i = 0; i < count; i++)
+			wpabuf_put_le16(groups, rejected_groups[i]);
+		sae->tmp->own_rejected_groups = groups;
+	}
+
+	if (pt->ec) {
+		crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
+		sae->tmp->pwe_ecc = sae_derive_pwe_from_pt_ecc(pt, addr1,
+							       addr2);
+		if (!sae->tmp->pwe_ecc)
+			return -1;
+	}
+
+	if (pt->dh) {
+		crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+		sae->tmp->pwe_ffc = sae_derive_pwe_from_pt_ffc(pt, addr1,
+							       addr2);
+		if (!sae->tmp->pwe_ffc)
+			return -1;
+	}
+
+	sae->tmp->h2e = 1;
+	return sae_derive_commit(sae);
 }
 
 
@@ -688,47 +1481,124 @@
 }
 
 
+static int sae_kdf_hash(size_t hash_len, const u8 *k, const char *label,
+			const u8 *context, size_t context_len,
+			u8 *out, size_t out_len)
+{
+	if (hash_len == 32)
+		return sha256_prf(k, hash_len, label,
+				  context, context_len, out, out_len);
+#ifdef CONFIG_SHA384
+	if (hash_len == 48)
+		return sha384_prf(k, hash_len, label,
+				  context, context_len, out, out_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+	if (hash_len == 64)
+		return sha512_prf(k, hash_len, label,
+				  context, context_len, out, out_len);
+#endif /* CONFIG_SHA512 */
+	return -1;
+}
+
+
 static int sae_derive_keys(struct sae_data *sae, const u8 *k)
 {
-	u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
-	u8 keyseed[SHA256_MAC_LEN];
-	u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+	u8 zero[SAE_MAX_HASH_LEN], val[SAE_MAX_PRIME_LEN];
+	const u8 *salt;
+	struct wpabuf *rejected_groups = NULL;
+	u8 keyseed[SAE_MAX_HASH_LEN];
+	u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
 	struct crypto_bignum *tmp;
 	int ret = -1;
+	size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
+	const u8 *addr[1];
+	size_t len[1];
 
 	tmp = crypto_bignum_init();
 	if (tmp == NULL)
 		goto fail;
 
-	/* keyseed = H(<0>32, k)
-	 * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+	/* keyseed = H(salt, k)
+	 * KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
 	 *                      (commit-scalar + peer-commit-scalar) modulo r)
 	 * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
 	 */
+	if (!sae->tmp->h2e)
+		hash_len = SHA256_MAC_LEN;
+	else if (sae->tmp->dh)
+		hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+	else
+		hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+	if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
+			      sae->tmp->peer_rejected_groups)) {
+		struct wpabuf *own, *peer;
 
-	os_memset(null_key, 0, sizeof(null_key));
-	hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
-		    keyseed);
-	wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
-
-	crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
-			  tmp);
-	crypto_bignum_mod(tmp, sae->tmp->order, tmp);
-	crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
-	wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
-	if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
-		       val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
+		own = sae->tmp->own_rejected_groups;
+		peer = sae->tmp->peer_rejected_groups;
+		salt_len = 0;
+		if (own)
+			salt_len += wpabuf_len(own);
+		if (peer)
+			salt_len += wpabuf_len(peer);
+		rejected_groups = wpabuf_alloc(salt_len);
+		if (!rejected_groups)
+			goto fail;
+		if (sae->tmp->own_addr_higher) {
+			if (own)
+				wpabuf_put_buf(rejected_groups, own);
+			if (peer)
+				wpabuf_put_buf(rejected_groups, peer);
+		} else {
+			if (peer)
+				wpabuf_put_buf(rejected_groups, peer);
+			if (own)
+				wpabuf_put_buf(rejected_groups, own);
+		}
+		salt = wpabuf_head(rejected_groups);
+		salt_len = wpabuf_len(rejected_groups);
+	} else {
+		os_memset(zero, 0, hash_len);
+		salt = zero;
+		salt_len = hash_len;
+	}
+	wpa_hexdump(MSG_DEBUG, "SAE: salt for keyseed derivation",
+		    salt, salt_len);
+	addr[0] = k;
+	len[0] = prime_len;
+	if (hkdf_extract(hash_len, salt, salt_len, 1, addr, len, keyseed) < 0)
 		goto fail;
-	os_memset(keyseed, 0, sizeof(keyseed));
-	os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
-	os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, hash_len);
+
+	if (crypto_bignum_add(sae->tmp->own_commit_scalar,
+			      sae->peer_commit_scalar, tmp) < 0 ||
+	    crypto_bignum_mod(tmp, sae->tmp->order, tmp) < 0)
+		goto fail;
+	/* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
+	 * string that is needed for KCK, PMK, and PMKID derivation, but it
+	 * seems to make most sense to encode the
+	 * (commit-scalar + peer-commit-scalar) mod r part as a bit string by
+	 * zero padding it from left to the length of the order (in full
+	 * octets). */
+	crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
+	wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+	if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+			 val, sae->tmp->order_len,
+			 keys, hash_len + SAE_PMK_LEN) < 0)
+		goto fail;
+	forced_memzero(keyseed, sizeof(keyseed));
+	os_memcpy(sae->tmp->kck, keys, hash_len);
+	sae->tmp->kck_len = hash_len;
+	os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
 	os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
-	os_memset(keys, 0, sizeof(keys));
-	wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
+	forced_memzero(keys, sizeof(keys));
+	wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
+			sae->tmp->kck, sae->tmp->kck_len);
 	wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
 
 	ret = 0;
 fail:
+	wpabuf_free(rejected_groups);
 	crypto_bignum_deinit(tmp, 0);
 	return ret;
 }
@@ -791,6 +1661,16 @@
 		wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
 			   identifier);
 	}
+
+	if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
+		wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
+				sae->tmp->own_rejected_groups);
+		wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+		wpabuf_put_u8(buf,
+			      1 + wpabuf_len(sae->tmp->own_rejected_groups));
+		wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
+		wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
+	}
 }
 
 
@@ -846,9 +1726,19 @@
 }
 
 
+static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
+{
+	return end - pos >= 3 &&
+		pos[0] == WLAN_EID_EXTENSION &&
+		pos[1] >= 2 &&
+		end - pos - 2 >= pos[1] &&
+		pos[2] == WLAN_EID_EXT_REJECTED_GROUPS;
+}
+
+
 static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
 				   const u8 *end, const u8 **token,
-				   size_t *token_len)
+				   size_t *token_len, int h2e)
 {
 	size_t scalar_elem_len, tlen;
 	const u8 *elem;
@@ -869,6 +1759,8 @@
 	 * fields, so use that length as a requirement for the received
 	 * token and check for the presence of possible Password
 	 * Identifier element based on the element header information.
+	 * When parsing H2E case, also consider the Rejected Groupd element
+	 * similarly.
 	 */
 	tlen = end - (*pos + scalar_elem_len);
 
@@ -886,12 +1778,27 @@
 		  * this frame. */
 		return;
 	}
+	if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+		 /* Rejected Groups takes out all available extra octets, so
+		  * there can be no Anti-Clogging token in this frame. */
+		return;
+	}
 
 	elem += SHA256_MAC_LEN;
 	if (sae_is_password_id_elem(elem, end)) {
 		 /* Password Identifier element is included in the end, so
 		  * remove its length from the Anti-Clogging token field. */
 		tlen -= 2 + elem[1];
+		elem += 2 + elem[1];
+		if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+			/* Also remove Rejected Groups element from the
+			 * Anti-Clogging token field length */
+			tlen -= 2 + elem[1];
+		}
+	} else if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+		 /* Rejected Groups element is included in the end, so
+		  * remove its length from the Anti-Clogging token field. */
+		tlen -= 2 + elem[1];
 	}
 
 	wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
@@ -1058,11 +1965,11 @@
 
 
 static int sae_parse_password_identifier(struct sae_data *sae,
-					 const u8 *pos, const u8 *end)
+					 const u8 **pos, const u8 *end)
 {
 	wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
-		    pos, end - pos);
-	if (!sae_is_password_id_elem(pos, end)) {
+		    *pos, end - *pos);
+	if (!sae_is_password_id_elem(*pos, end)) {
 		if (sae->tmp->pw_id) {
 			wpa_printf(MSG_DEBUG,
 				   "SAE: No Password Identifier included, but expected one (%s)",
@@ -1075,8 +1982,8 @@
 	}
 
 	if (sae->tmp->pw_id &&
-	    (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
-	     os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
+	    ((*pos)[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
+	     os_memcmp(sae->tmp->pw_id, (*pos) + 3, (*pos)[1] - 1) != 0)) {
 		wpa_printf(MSG_DEBUG,
 			   "SAE: The included Password Identifier does not match the expected one (%s)",
 			   sae->tmp->pw_id);
@@ -1084,19 +1991,39 @@
 	}
 
 	os_free(sae->tmp->pw_id);
-	sae->tmp->pw_id = os_malloc(pos[1]);
+	sae->tmp->pw_id = os_malloc((*pos)[1]);
 	if (!sae->tmp->pw_id)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
-	sae->tmp->pw_id[pos[1] - 1] = '\0';
+	os_memcpy(sae->tmp->pw_id, (*pos) + 3, (*pos)[1] - 1);
+	sae->tmp->pw_id[(*pos)[1] - 1] = '\0';
 	wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
-			  sae->tmp->pw_id, pos[1] -  1);
+			  sae->tmp->pw_id, (*pos)[1] -  1);
+	*pos = *pos + 2 + (*pos)[1];
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static int sae_parse_rejected_groups(struct sae_data *sae,
+				     const u8 *pos, const u8 *end)
+{
+	wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+		    pos, end - pos);
+	if (!sae_is_rejected_groups_elem(pos, end))
+		return WLAN_STATUS_SUCCESS;
+	wpabuf_free(sae->tmp->peer_rejected_groups);
+	sae->tmp->peer_rejected_groups = wpabuf_alloc(pos[1] - 1);
+	if (!sae->tmp->peer_rejected_groups)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	wpabuf_put_data(sae->tmp->peer_rejected_groups, pos + 3, pos[1] - 1);
+	wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
+			sae->tmp->peer_rejected_groups);
 	return WLAN_STATUS_SUCCESS;
 }
 
 
 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
-		     const u8 **token, size_t *token_len, int *allowed_groups)
+		     const u8 **token, size_t *token_len, int *allowed_groups,
+		     int h2e)
 {
 	const u8 *pos = data, *end = data + len;
 	u16 res;
@@ -1110,7 +2037,7 @@
 	pos += 2;
 
 	/* Optional Anti-Clogging Token */
-	sae_parse_commit_token(sae, &pos, end, token, token_len);
+	sae_parse_commit_token(sae, &pos, end, token, token_len, h2e);
 
 	/* commit-scalar */
 	res = sae_parse_commit_scalar(sae, &pos, end);
@@ -1123,10 +2050,17 @@
 		return res;
 
 	/* Optional Password Identifier element */
-	res = sae_parse_password_identifier(sae, pos, end);
+	res = sae_parse_password_identifier(sae, &pos, end);
 	if (res != WLAN_STATUS_SUCCESS)
 		return res;
 
+	/* Conditional Rejected Groups element */
+	if (h2e) {
+		res = sae_parse_rejected_groups(sae, pos, end);
+		if (res != WLAN_STATUS_SUCCESS)
+			return res;
+	}
+
 	/*
 	 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
 	 * the values we sent which would be evidence of a reflection attack.
@@ -1154,12 +2088,12 @@
 }
 
 
-static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
-			   const struct crypto_bignum *scalar1,
-			   const u8 *element1, size_t element1_len,
-			   const struct crypto_bignum *scalar2,
-			   const u8 *element2, size_t element2_len,
-			   u8 *confirm)
+static int sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+			  const struct crypto_bignum *scalar1,
+			  const u8 *element1, size_t element1_len,
+			  const struct crypto_bignum *scalar2,
+			  const u8 *element2, size_t element2_len,
+			  u8 *confirm)
 {
 	const u8 *addr[5];
 	size_t len[5];
@@ -1173,72 +2107,81 @@
 	 * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
 	 *               PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
 	 */
+	if (crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+				 sae->tmp->prime_len) < 0 ||
+	    crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+				 sae->tmp->prime_len) < 0)
+		return -1;
 	addr[0] = sc;
 	len[0] = 2;
-	crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
-			     sae->tmp->prime_len);
 	addr[1] = scalar_b1;
 	len[1] = sae->tmp->prime_len;
 	addr[2] = element1;
 	len[2] = element1_len;
-	crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
-			     sae->tmp->prime_len);
 	addr[3] = scalar_b2;
 	len[3] = sae->tmp->prime_len;
 	addr[4] = element2;
 	len[4] = element2_len;
-	hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
-			   confirm);
+	return hkdf_extract(sae->tmp->kck_len, sae->tmp->kck, sae->tmp->kck_len,
+			    5, addr, len, confirm);
 }
 
 
-static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
-			       const struct crypto_bignum *scalar1,
-			       const struct crypto_ec_point *element1,
-			       const struct crypto_bignum *scalar2,
-			       const struct crypto_ec_point *element2,
-			       u8 *confirm)
+static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+			      const struct crypto_bignum *scalar1,
+			      const struct crypto_ec_point *element1,
+			      const struct crypto_bignum *scalar2,
+			      const struct crypto_ec_point *element2,
+			      u8 *confirm)
 {
 	u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
 	u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
 
-	crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
-			       element_b1 + sae->tmp->prime_len);
-	crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
-			       element_b2 + sae->tmp->prime_len);
-
-	sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
-		       scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+	if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+				   element_b1 + sae->tmp->prime_len) < 0 ||
+	    crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+				   element_b2 + sae->tmp->prime_len) < 0 ||
+	    sae_cn_confirm(sae, sc, scalar1, element_b1,
+			   2 * sae->tmp->prime_len,
+			   scalar2, element_b2, 2 * sae->tmp->prime_len,
+			   confirm) < 0)
+		return -1;
+	return 0;
 }
 
 
-static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
-			       const struct crypto_bignum *scalar1,
-			       const struct crypto_bignum *element1,
-			       const struct crypto_bignum *scalar2,
-			       const struct crypto_bignum *element2,
-			       u8 *confirm)
+static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+			      const struct crypto_bignum *scalar1,
+			      const struct crypto_bignum *element1,
+			      const struct crypto_bignum *scalar2,
+			      const struct crypto_bignum *element2,
+			      u8 *confirm)
 {
 	u8 element_b1[SAE_MAX_PRIME_LEN];
 	u8 element_b2[SAE_MAX_PRIME_LEN];
 
-	crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
-			     sae->tmp->prime_len);
-	crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
-			     sae->tmp->prime_len);
-
-	sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
-		       scalar2, element_b2, sae->tmp->prime_len, confirm);
+	if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+				 sae->tmp->prime_len) < 0 ||
+	    crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+				 sae->tmp->prime_len) < 0 ||
+	    sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+			   scalar2, element_b2, sae->tmp->prime_len,
+			   confirm) < 0)
+		return -1;
+	return 0;
 }
 
 
 void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
 {
 	const u8 *sc;
+	size_t hash_len;
 
 	if (sae->tmp == NULL)
 		return;
 
+	hash_len = sae->tmp->kck_len;
+
 	/* Send-Confirm */
 	sc = wpabuf_put(buf, 0);
 	wpabuf_put_le16(buf, sae->send_confirm);
@@ -1250,59 +2193,63 @@
 				   sae->tmp->own_commit_element_ecc,
 				   sae->peer_commit_scalar,
 				   sae->tmp->peer_commit_element_ecc,
-				   wpabuf_put(buf, SHA256_MAC_LEN));
+				   wpabuf_put(buf, hash_len));
 	else
 		sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
 				   sae->tmp->own_commit_element_ffc,
 				   sae->peer_commit_scalar,
 				   sae->tmp->peer_commit_element_ffc,
-				   wpabuf_put(buf, SHA256_MAC_LEN));
+				   wpabuf_put(buf, hash_len));
 }
 
 
 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
 {
-	u8 verifier[SHA256_MAC_LEN];
+	u8 verifier[SAE_MAX_HASH_LEN];
+	size_t hash_len;
 
-	if (len < 2 + SHA256_MAC_LEN) {
+	if (!sae->tmp)
+		return -1;
+
+	hash_len = sae->tmp->kck_len;
+	if (len < 2 + hash_len) {
 		wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
 		return -1;
 	}
 
 	wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
 
-	if (!sae->tmp || !sae->peer_commit_scalar ||
-	    !sae->tmp->own_commit_scalar) {
+	if (!sae->peer_commit_scalar || !sae->tmp->own_commit_scalar) {
 		wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
 		return -1;
 	}
 
 	if (sae->tmp->ec) {
 		if (!sae->tmp->peer_commit_element_ecc ||
-		    !sae->tmp->own_commit_element_ecc)
+		    !sae->tmp->own_commit_element_ecc ||
+		    sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
+				       sae->tmp->peer_commit_element_ecc,
+				       sae->tmp->own_commit_scalar,
+				       sae->tmp->own_commit_element_ecc,
+				       verifier) < 0)
 			return -1;
-		sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
-				   sae->tmp->peer_commit_element_ecc,
-				   sae->tmp->own_commit_scalar,
-				   sae->tmp->own_commit_element_ecc,
-				   verifier);
 	} else {
 		if (!sae->tmp->peer_commit_element_ffc ||
-		    !sae->tmp->own_commit_element_ffc)
+		    !sae->tmp->own_commit_element_ffc ||
+		    sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
+				       sae->tmp->peer_commit_element_ffc,
+				       sae->tmp->own_commit_scalar,
+				       sae->tmp->own_commit_element_ffc,
+				       verifier) < 0)
 			return -1;
-		sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
-				   sae->tmp->peer_commit_element_ffc,
-				   sae->tmp->own_commit_scalar,
-				   sae->tmp->own_commit_element_ffc,
-				   verifier);
 	}
 
-	if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+	if (os_memcmp_const(verifier, data + 2, hash_len) != 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
 		wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
-			    data + 2, SHA256_MAC_LEN);
+			    data + 2, hash_len);
 		wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
-			    verifier, SHA256_MAC_LEN);
+			    verifier, hash_len);
 		return -1;
 	}
 
diff --git a/src/common/sae.h b/src/common/sae.h
index 3eb6e32..b3787e4 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -12,17 +12,18 @@
 #define SAE_KCK_LEN 32
 #define SAE_PMK_LEN 32
 #define SAE_PMKID_LEN 16
-#define SAE_KEYSEED_KEY_LEN 32
 #define SAE_MAX_PRIME_LEN 512
 #define SAE_MAX_ECC_PRIME_LEN 66
-#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
-#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+#define SAE_MAX_HASH_LEN 64
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN + 255)
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_HASH_LEN)
 
 /* Special value returned by sae_parse_commit() */
 #define SAE_SILENTLY_DISCARD 65535
 
 struct sae_temporary_data {
-	u8 kck[SAE_KCK_LEN];
+	u8 kck[SAE_MAX_HASH_LEN];
+	size_t kck_len;
 	struct crypto_bignum *own_commit_scalar;
 	struct crypto_bignum *own_commit_element_ffc;
 	struct crypto_ec_point *own_commit_element_ecc;
@@ -33,6 +34,7 @@
 	struct crypto_bignum *sae_rand;
 	struct crypto_ec *ec;
 	int prime_len;
+	int order_len;
 	const struct dh_group *dh;
 	const struct crypto_bignum *prime;
 	const struct crypto_bignum *order;
@@ -42,6 +44,20 @@
 	char *pw_id;
 	int vlan_id;
 	u8 bssid[ETH_ALEN];
+	struct wpabuf *own_rejected_groups;
+	struct wpabuf *peer_rejected_groups;
+	unsigned int h2e:1;
+	unsigned int own_addr_higher:1;
+};
+
+struct sae_pt {
+	struct sae_pt *next;
+	int group;
+	struct crypto_ec *ec;
+	struct crypto_ec_point *ecc_pt;
+
+	const struct dh_group *dh;
+	struct crypto_bignum *ffc_pt;
 };
 
 enum sae_state {
@@ -67,14 +83,28 @@
 int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
 		       const u8 *password, size_t password_len,
 		       const char *identifier, struct sae_data *sae);
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+			  const u8 *addr1, const u8 *addr2,
+			  int *rejected_groups);
 int sae_process_commit(struct sae_data *sae);
 void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
 		      const struct wpabuf *token, const char *identifier);
 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
-		     const u8 **token, size_t *token_len, int *allowed_groups);
+		     const u8 **token, size_t *token_len, int *allowed_groups,
+		     int h2e);
 void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
 u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
 const char * sae_state_txt(enum sae_state state);
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+			      const u8 *password, size_t password_len,
+			      const char *identifier);
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+			   const u8 *addr1, const u8 *addr2);
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+			   const u8 *addr1, const u8 *addr2);
+void sae_deinit_pt(struct sae_pt *pt);
 
 #endif /* SAE_H */
diff --git a/src/common/version.h b/src/common/version.h
index 031d1be..0235c9b 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -9,6 +9,6 @@
 #define GIT_VERSION_STR_POSTFIX ""
 #endif /* GIT_VERSION_STR_POSTFIX */
 
-#define VERSION_STR "2.9-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.10-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index ed2d1c2..ea9f7a2 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -212,11 +212,9 @@
 			return -1;
 		os_memcpy(mic, hash, MD5_MAC_LEN);
 		break;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
 	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
 		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
 		return omac1_aes_128(key, buf, len, mic);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
 	case WPA_KEY_INFO_TYPE_AKM_DEFINED:
 		switch (akmp) {
 #ifdef CONFIG_SAE
@@ -410,14 +408,10 @@
 		return -1;
 #endif /* CONFIG_SUITEB192 || CONFIG_FILS */
 	} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
 		if (sha256_prf(pmk, pmk_len, label, data, data_len,
 			       tmp, ptk_len) < 0)
 			return -1;
-#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
-		return -1;
-#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
 #ifdef CONFIG_DPP
 	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -692,7 +686,7 @@
 	len[2] = ETH_ALEN;
 	addr[3] = bssid;
 	len[3] = ETH_ALEN;
-	if (g_sta && g_ap_len && g_ap && g_ap_len) {
+	if (g_sta && g_sta_len && g_ap && g_ap_len) {
 		addr[4] = g_sta;
 		len[4] = g_sta_len;
 		addr[5] = g_ap;
@@ -723,7 +717,7 @@
 	addr[1] = snonce;
 	addr[2] = bssid;
 	addr[3] = sta_addr;
-	if (g_sta && g_ap_len && g_ap && g_ap_len) {
+	if (g_sta && g_sta_len && g_ap && g_ap_len) {
 		addr[4] = g_ap;
 		len[4] = g_ap_len;
 		addr[5] = g_sta;
@@ -756,10 +750,12 @@
 	       const u8 *mdie, size_t mdie_len,
 	       const u8 *ftie, size_t ftie_len,
 	       const u8 *rsnie, size_t rsnie_len,
-	       const u8 *ric, size_t ric_len, u8 *mic)
+	       const u8 *ric, size_t ric_len,
+	       const u8 *rsnxe, size_t rsnxe_len,
+	       u8 *mic)
 {
-	const u8 *addr[9];
-	size_t len[9];
+	const u8 *addr[10];
+	size_t len[10];
 	size_t i, num_elem = 0;
 	u8 zero_mic[24];
 	size_t mic_len, fte_fixed_len;
@@ -826,6 +822,12 @@
 		num_elem++;
 	}
 
+	if (rsnxe) {
+		addr[num_elem] = rsnxe;
+		len[num_elem] = rsnxe_len;
+		num_elem++;
+	}
+
 	for (i = 0; i < num_elem; i++)
 		wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
 #ifdef CONFIG_SHA384
@@ -892,12 +894,10 @@
 			parse->r0kh_id = pos;
 			parse->r0kh_id_len = len;
 			break;
-#ifdef CONFIG_IEEE80211W
 		case FTIE_SUBELEM_IGTK:
 			parse->igtk = pos;
 			parse->igtk_len = len;
 			break;
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_OCV
 		case FTIE_SUBELEM_OCI:
 			parse->oci = pos;
@@ -958,6 +958,7 @@
 					   "RSN IE: %d", ret);
 				return -1;
 			}
+			parse->rsn_capab = data.capabilities;
 			if (data.num_pmkid == 1 && data.pmkid)
 				parse->rsn_pmkid = data.pmkid;
 			parse->key_mgmt = data.key_mgmt;
@@ -968,6 +969,13 @@
 				update_use_sha384 = 0;
 			}
 			break;
+		case WLAN_EID_RSNX:
+			wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
+			if (len < 1)
+				break;
+			parse->rsnxe = pos;
+			parse->rsnxe_len = len;
+			break;
 		case WLAN_EID_MOBILITY_DOMAIN:
 			wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
 			if (len < sizeof(struct rsn_mdie))
@@ -989,9 +997,11 @@
 				wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
 					    ftie_sha384->mic,
 					    sizeof(ftie_sha384->mic));
+				parse->fte_anonce = ftie_sha384->anonce;
 				wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
 					    ftie_sha384->anonce,
 					    WPA_NONCE_LEN);
+				parse->fte_snonce = ftie_sha384->snonce;
 				wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
 					    ftie_sha384->snonce,
 					    WPA_NONCE_LEN);
@@ -1008,8 +1018,10 @@
 				    ftie->mic_control, 2);
 			wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
 				    ftie->mic, sizeof(ftie->mic));
+			parse->fte_anonce = ftie->anonce;
 			wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
 				    ftie->anonce, WPA_NONCE_LEN);
+			parse->fte_snonce = ftie->snonce;
 			wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
 				    ftie->snonce, WPA_NONCE_LEN);
 			prot_ie_count = ftie->mic_control[1];
@@ -1046,6 +1058,8 @@
 		prot_ie_count--;
 	if (parse->ftie)
 		prot_ie_count--;
+	if (parse->rsnxe)
+		prot_ie_count--;
 	if (prot_ie_count < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
 			   "the protected IE count");
@@ -1087,10 +1101,8 @@
 		return WPA_CIPHER_TKIP;
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
 		return WPA_CIPHER_CCMP;
-#ifdef CONFIG_IEEE80211W
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
 		return WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
 		return WPA_CIPHER_GCMP;
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
@@ -1125,12 +1137,10 @@
 		return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
 #endif /* CONFIG_SHA384 */
 #endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
 		return WPA_KEY_MGMT_IEEE8021X_SHA256;
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
 		return WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_SAE
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
 		return WPA_KEY_MGMT_SAE;
@@ -1170,7 +1180,6 @@
 }
 
 
-#ifdef CONFIG_IEEE80211W
 int wpa_cipher_valid_mgmt_group(int cipher)
 {
 	return cipher == WPA_CIPHER_AES_128_CMAC ||
@@ -1178,7 +1187,6 @@
 		cipher == WPA_CIPHER_BIP_GMAC_256 ||
 		cipher == WPA_CIPHER_BIP_CMAC_256;
 }
-#endif /* CONFIG_IEEE80211W */
 
 
 /**
@@ -1203,11 +1211,7 @@
 	data->capabilities = 0;
 	data->pmkid = NULL;
 	data->num_pmkid = 0;
-#ifdef CONFIG_IEEE80211W
 	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-#else /* CONFIG_IEEE80211W */
-	data->mgmt_group_cipher = 0;
-#endif /* CONFIG_IEEE80211W */
 
 	if (rsn_ie_len == 0) {
 		/* No RSN IE - fail silently */
@@ -1282,13 +1286,11 @@
 			pos += RSN_SELECTOR_LEN;
 			left -= RSN_SELECTOR_LEN;
 		}
-#ifdef CONFIG_IEEE80211W
 		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
 			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
 				   "pairwise cipher", __func__);
 			return -1;
 		}
-#endif /* CONFIG_IEEE80211W */
 	} else if (left == 1) {
 		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
 			   __func__);
@@ -1340,7 +1342,6 @@
 		}
 	}
 
-#ifdef CONFIG_IEEE80211W
 	if (left >= 4) {
 		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
 		if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
@@ -1353,7 +1354,6 @@
 		pos += RSN_SELECTOR_LEN;
 		left -= RSN_SELECTOR_LEN;
 	}
-#endif /* CONFIG_IEEE80211W */
 
 	if (left > 0) {
 		wpa_hexdump(MSG_DEBUG,
@@ -1852,11 +1852,9 @@
 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
 		hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
 #endif /* CONFIG_FILS || CONFIG_SHA384 */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
 	} else if (wpa_key_mgmt_sha256(akmp)) {
 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
 		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
-#endif /* CONFIG_IEEE80211W || CONFIG_FILS */
 	} else {
 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
 		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
@@ -2007,12 +2005,10 @@
 	case WPA_KEY_MGMT_FT_PSK:
 		return "FT-PSK";
 #endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
 	case WPA_KEY_MGMT_IEEE8021X_SHA256:
 		return "WPA2-EAP-SHA256";
 	case WPA_KEY_MGMT_PSK_SHA256:
 		return "WPA2-PSK-SHA256";
-#endif /* CONFIG_IEEE80211W */
 	case WPA_KEY_MGMT_WPS:
 		return "WPS";
 	case WPA_KEY_MGMT_SAE:
@@ -2075,6 +2071,16 @@
 		return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
 	if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
 		return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+	if (akm & WPA_KEY_MGMT_SAE)
+		return RSN_AUTH_KEY_MGMT_SAE;
+	if (akm & WPA_KEY_MGMT_FT_SAE)
+		return RSN_AUTH_KEY_MGMT_FT_SAE;
+	if (akm & WPA_KEY_MGMT_OWE)
+		return RSN_AUTH_KEY_MGMT_OWE;
+	if (akm & WPA_KEY_MGMT_DPP)
+		return RSN_AUTH_KEY_MGMT_DPP;
+	if (akm & WPA_KEY_MGMT_OSEN)
+		return RSN_AUTH_KEY_MGMT_OSEN;
 	return 0;
 }
 
@@ -2116,7 +2122,6 @@
 }
 
 
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
 int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
 {
 	u8 *start, *end, *rpos, *rend;
@@ -2131,11 +2136,10 @@
 		start += 2 + start[1];
 	}
 	if (start >= end) {
-		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
-			   "IEs data");
+		wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
 		return -1;
 	}
-	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+	wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
 		    start, 2 + start[1]);
 
 	/* Find start of PMKID-Count */
@@ -2161,8 +2165,8 @@
 		/* Skip RSN Capabilities */
 		rpos += 2;
 		if (rpos > rend) {
-			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
-				   "IEs data");
+			wpa_printf(MSG_ERROR,
+				   "RSN: Could not parse RSNE in IEs data");
 			return -1;
 		}
 	}
@@ -2193,7 +2197,7 @@
 			 * PMKID(s) first before adding the new one.
 			 */
 			wpa_printf(MSG_DEBUG,
-				   "FT: Remove %u old PMKID(s) from RSN IE",
+				   "RSN: Remove %u old PMKID(s) from RSNE",
 				   num_pmkid);
 			after = rpos + 2 + num_pmkid * PMKID_LEN;
 			os_memmove(rpos + 2, after, rend - after);
@@ -2208,14 +2212,13 @@
 		start[1] += PMKID_LEN;
 	}
 
-	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
-		    "(PMKID inserted)", start, 2 + start[1]);
+	wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
+		    start, 2 + start[1]);
 
 	*ies_len += added;
 
 	return 0;
 }
-#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
 
 
 int wpa_cipher_key_len(int cipher)
@@ -2600,3 +2603,266 @@
 	return 0;
 }
 #endif /* CONFIG_FILS */
+
+
+/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+				     struct wpa_eapol_ie_parse *ie)
+{
+	unsigned int oui;
+
+	if (pos[1] < 4) {
+		wpa_printf(MSG_MSGDUMP,
+			   "Too short vendor specific IE ignored (len=%u)",
+			   pos[1]);
+		return 1;
+	}
+
+	oui = WPA_GET_BE24(&pos[2]);
+	if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+		if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+			ie->wmm = &pos[2];
+			ie->wmm_len = pos[1];
+			wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+				    ie->wmm, ie->wmm_len);
+		} else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+			ie->wmm = &pos[2];
+			ie->wmm_len = pos[1];
+			wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+				    ie->wmm, ie->wmm_len);
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	if (pos[1] == 0)
+		return 1;
+
+	if (pos[1] >= 6 &&
+	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
+	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+		ie->wpa_ie = pos;
+		ie->wpa_ie_len = pos[1] + 2;
+		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+			    ie->wpa_ie, ie->wpa_ie_len);
+		return 0;
+	}
+
+	if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+		ie->osen = pos;
+		ie->osen_len = pos[1] + 2;
+		return 0;
+	}
+
+	if (1 + RSN_SELECTOR_LEN < end - pos &&
+	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+		ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+			    ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+
+	if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+		ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG,
+			    "WPA: IP Address Allocation in EAPOL-Key",
+			    ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+		ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+		ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end;
+	int ret = 0;
+
+	os_memset(ie, 0, sizeof(*ie));
+	for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+		if (pos[0] == 0xdd &&
+		    ((pos == buf + len - 1) || pos[1] == 0)) {
+			/* Ignore padding */
+			break;
+		}
+		if (2 + pos[1] > end - pos) {
+			wpa_printf(MSG_DEBUG,
+				   "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
+				   pos[0], pos[1], (int) (pos - buf));
+			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len);
+			ret = -1;
+			break;
+		}
+		if (*pos == WLAN_EID_RSN) {
+			ie->rsn_ie = pos;
+			ie->rsn_ie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+				    ie->rsn_ie, ie->rsn_ie_len);
+		} else if (*pos == WLAN_EID_RSNX) {
+			ie->rsnxe = pos;
+			ie->rsnxe_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
+				    ie->rsnxe, ie->rsnxe_len);
+		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+			ie->mdie = pos;
+			ie->mdie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+				    ie->mdie, ie->mdie_len);
+		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+			ie->ftie = pos;
+			ie->ftie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+				    ie->ftie, ie->ftie_len);
+		} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+			if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+				ie->reassoc_deadline = pos;
+				wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+					    "in EAPOL-Key",
+					    ie->reassoc_deadline, pos[1] + 2);
+			} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+				ie->key_lifetime = pos;
+				wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+					    "in EAPOL-Key",
+					    ie->key_lifetime, pos[1] + 2);
+			} else {
+				wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+					    "EAPOL-Key Key Data IE",
+					    pos, 2 + pos[1]);
+			}
+		} else if (*pos == WLAN_EID_LINK_ID) {
+			if (pos[1] >= 18) {
+				ie->lnkid = pos;
+				ie->lnkid_len = pos[1] + 2;
+			}
+		} else if (*pos == WLAN_EID_EXT_CAPAB) {
+			ie->ext_capab = pos;
+			ie->ext_capab_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_SUPP_RATES) {
+			ie->supp_rates = pos;
+			ie->supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+			ie->ext_supp_rates = pos;
+			ie->ext_supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_HT_CAP &&
+			   pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
+			ie->ht_capabilities = pos + 2;
+		} else if (*pos == WLAN_EID_VHT_AID) {
+			if (pos[1] >= 2)
+				ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
+		} else if (*pos == WLAN_EID_VHT_CAP &&
+			   pos[1] >= sizeof(struct ieee80211_vht_capabilities))
+		{
+			ie->vht_capabilities = pos + 2;
+		} else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+			ie->qosinfo = pos[2];
+		} else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+			ie->supp_channels = pos + 2;
+			ie->supp_channels_len = pos[1];
+		} else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+			/*
+			 * The value of the Length field of the Supported
+			 * Operating Classes element is between 2 and 253.
+			 * Silently skip invalid elements to avoid interop
+			 * issues when trying to use the value.
+			 */
+			if (pos[1] >= 2 && pos[1] <= 253) {
+				ie->supp_oper_classes = pos + 2;
+				ie->supp_oper_classes_len = pos[1];
+			}
+		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+			ret = wpa_parse_generic(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
+
+			ret = wpa_parse_vendor_specific(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
+		} else {
+			wpa_hexdump(MSG_DEBUG,
+				    "WPA: Unrecognized EAPOL-Key Key Data IE",
+				    pos, 2 + pos[1]);
+		}
+	}
+
+	return ret;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index e83d688..beb1ecd 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -104,9 +104,7 @@
 #endif
 #define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
 #define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#ifdef CONFIG_IEEE80211W
 #define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
-#endif /* CONFIG_IEEE80211W */
 #define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
 #define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
 #define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
@@ -130,10 +128,8 @@
 #pragma pack(push, 1)
 #endif /* _MSC_VER */
 
-#ifdef CONFIG_IEEE80211W
 #define WPA_IGTK_LEN 16
 #define WPA_IGTK_MAX_LEN 32
-#endif /* CONFIG_IEEE80211W */
 
 
 /* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -226,12 +222,10 @@
 	size_t gtk_len;
 };
 
-#ifdef CONFIG_IEEE80211W
 struct wpa_igtk {
 	u8 igtk[WPA_IGTK_MAX_LEN];
 	size_t igtk_len;
 };
-#endif /* CONFIG_IEEE80211W */
 
 /* WPA IE version 1
  * 00-50-f2:1 (OUI:OUI type)
@@ -291,14 +285,12 @@
 	be16 error_type;
 } STRUCT_PACKED;
 
-#ifdef CONFIG_IEEE80211W
 #define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
 struct wpa_igtk_kde {
 	u8 keyid[2];
 	u8 pn[6];
 	u8 igtk[WPA_IGTK_MAX_LEN];
 } STRUCT_PACKED;
-#endif /* CONFIG_IEEE80211W */
 
 struct rsn_mdie {
 	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@@ -372,7 +364,9 @@
 	       const u8 *mdie, size_t mdie_len,
 	       const u8 *ftie, size_t ftie_len,
 	       const u8 *rsnie, size_t rsnie_len,
-	       const u8 *ric, size_t ric_len, u8 *mic);
+	       const u8 *ric, size_t ric_len,
+	       const u8 *rsnxe, size_t rsnxe_len,
+	       u8 *mic);
 int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
 		      const u8 *ssid, size_t ssid_len,
 		      const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
@@ -451,8 +445,11 @@
 	size_t gtk_len;
 	const u8 *r0kh_id;
 	size_t r0kh_id_len;
+	const u8 *fte_anonce;
+	const u8 *fte_snonce;
 	const u8 *rsn;
 	size_t rsn_len;
+	u16 rsn_capab;
 	const u8 *rsn_pmkid;
 	const u8 *tie;
 	size_t tie_len;
@@ -466,11 +463,67 @@
 	size_t ric_len;
 	int key_mgmt;
 	int pairwise_cipher;
+	const u8 *rsnxe;
+	size_t rsnxe_len;
 };
 
 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
 		     int use_sha384);
 
+struct wpa_eapol_ie_parse {
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+	const u8 *rsn_ie;
+	size_t rsn_ie_len;
+	const u8 *pmkid;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *mac_addr;
+	size_t mac_addr_len;
+	const u8 *igtk;
+	size_t igtk_len;
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *ip_addr_req;
+	const u8 *ip_addr_alloc;
+	const u8 *oci;
+	size_t oci_len;
+	const u8 *osen;
+	size_t osen_len;
+	const u8 *rsnxe;
+	size_t rsnxe_len;
+	const u8 *reassoc_deadline;
+	const u8 *key_lifetime;
+	const u8 *lnkid;
+	size_t lnkid_len;
+	const u8 *ext_capab;
+	size_t ext_capab_len;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	const u8 *ext_supp_rates;
+	size_t ext_supp_rates_len;
+	const u8 *ht_capabilities;
+	const u8 *vht_capabilities;
+	const u8 *supp_channels;
+	size_t supp_channels_len;
+	const u8 *supp_oper_classes;
+	size_t supp_oper_classes_len;
+	u8 qosinfo;
+	u16 aid;
+	const u8 *wmm;
+	size_t wmm_len;
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
+static inline int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+					   struct wpa_eapol_ie_parse *ie)
+{
+	return wpa_parse_kde_ies(buf, len, ie);
+}
+
+
 int wpa_cipher_key_len(int cipher);
 int wpa_cipher_rsc_len(int cipher);
 enum wpa_alg wpa_cipher_to_alg(int cipher);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index b24ae63..70ecf5d 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -168,6 +168,7 @@
 #define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
 #define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
 #define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
+#define DPP_EVENT_CONN_STATUS_RESULT "DPP-CONN-STATUS-RESULT "
 #define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
 #define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
 #define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "