[wpa_supplicant] Cumulative patch from commit d68c0dd4d

Bug: 156933657
Test: Verify Passpoint ANQP functionality and Passpoint association
Test: Connect to Passpoint, Open, WPA2, WPA3 networks and run traffic
Test: Regression test passed (Bug: 171270733)

BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from Open source

d68c0dd4d build: lib.rules: Add common-clean
d34b33451 wpa_supplicant: Fix frequency config for VHT/HE cases
0747432ef Fix spelling of "unexpected" in messages
d720de929 hostapd: Fix typos
4c66894fa eap_peer: Add .gitignore with *.so
13256b8cf P2P: Stop old listen radio work before go to WAIT_PEER_IDLE state
0f7989d8a MSCS: Fix decapsulating subelements from MSCS descriptor
cc3d6efa8 Add QCA interface for driver to report various connect fail reason codes
39748963d build: Fix libeap_peer.a build
c3f37c35f DFS: Use helper functions for VHT/HE parameters
a72599b31 hw_features: Better debug messages for some error cases
5965c7da5 wpa_supplicant: Enable VHT and HE in default config parameters
df6745e8c wpa_supplicant: Handle HT40 and mode downgrade in AP mode
93da12fd9 mesh: Fix channel init order, disable pri/sec channel switch
7f8ac02e8 HE/VHT: Fix frequency setup with HE enabled
0f07230eb DPP2: Add privacyProtectionKey into Configurator backup/restore
a0ccc4017 DPP2: Use ppKey to decrypt E'-id on Configurator
99d7bf234 DPP2: Use the new privacy protection key to protect E-id on Enrollee
37df40845 DPP2: Copy received ppKey into wpa_supplicant network profile
a8ee2292b DPP2: Parse ppKey from Connector
2a8c92887 DPP2: Add ppKey into Connector
9c1fbff07 DPP2: Generate a privacy protection key for Configurator
1d1475845 DPP: Make dpp_keygen_configurator() a static function
1d0d8888a build: Make more library things common
f4b3d14e9 build: Make a common library build
ac1447ae9 build: Rebuild libs all the time
6c41d43f1 mesh: Stop SAE auth timer when mesh node is removed
154b18d95 build: Fix dependency file inclusion
79db311e8 macsec_linux: Fix receive-lowest-PN setting
e3b47cdf8 DPP2: Add DPP_CHIRP commands to hostapd_cli and wpa_cli
cb3b70936 P2P: Set ap_configured_cb during group reform process
0e9f62e51 P2P: Fallback to GO negotiation after running out of GO scan attempts
1a0169695 hostapd_cli: Add dpp_bootstrap_set command
7e4ed93d3 wpa_cli: Add dpp_bootstrap_set command
283eee8ee gitignore: Clean up a bit
ae0b90dfa mesh: Allow channel switch command
87098d332 build: Put archive files into build/ folder too
00b5e99b6 build: Use the new build system for fuzz tests
a49f62884 wolfSSL: Fix wrong types in tls_wolfssl.c
58c18bcf8 hostapd: Fix error message for radius_accept_attr config option
52a1b2834 nl80211: Unbreak mode processing due to presence of S1G band
4b96fafcd D-Bus: Share 'remove all networks' with CLI
2818e9ca9 wpa_supplicant: Do not retry scan if operation is not supported
c0b88d129 P2P: Limit P2P_DEVICE name to appropriate ifname size
566ea1b7c mesh: Set correct address for mesh default broadcast/multicast keys
17d6ba4c9 DBus: Add "Roam" command support
6e757bba8 Use consistent spelling of "homogeneous"
cff545720 wpa_supplicant: Clear blacklist when SSID configs change
bbbb3c04e wpa_supplicant: Add new blacklist tests
164b8dd8e wpa_supplicant: Add wpa_blacklist_update()
d53011002 wpa_supplicant: Implement time-based blacklisting
2fd35d985 wpa_supplicant: Track consecutive connection failures
6d6310701 Fix STA mode default TXOP Limit values for AC_VI and AC_VO
dcc5288e5 gitignore: Add various things
ce963433b build: Allow overriding BUILDDIR from command line
ad6e4a5c5 build: Remove hostapd vs. wpa_supplicant build checks
6acda5322 build: Add .config file to dependencies
722138cd2 build: Put object files into build/ folder
0464d5d5d build: Move config file handling into build.rules
0430bc826 build: Add a common-clean target
06a6adb54 build: Use build.rules in lib.rules
3ff115db6 build: Disable built-in rules
a41a29192 build: Pull common fragments into a build.rules file
21cc50a43 HS 2.0 server: Add a .gitignore file
a28d127b1 AP: Reflect status code in SAE reflection attack test
e8b85c078 iface match: Unspecified matched interfaces should not log driver fails
83fa0a100 op_classes: Don't report an error when there are none to add
8776551bf BSD: don't log SIOCG80211 errors during interface setup
41d20df7f D-Bus: Allow empty string in dbus network properties
4756ecabc Allow bgscan parameters to be reconfigured
922fa0997 Global parser functions to return 1 when property unchanged
a87173b1d D-Bus: Skip property update actions when wpa_config_set() returns 1
1c58317f5 D-Bus: Allow changing an interface bridge via D-Bus
14318ccff P2P: Add configuration support to disable P2P in 6 GHz band
debf3e216 OCV: Work around for misbehaving STAs that indicate OCVC=1 without OCI
d48a3a676 FT: Modify status code in FT Reassoc frame for invalid OCI channel info
0e8d569d4 DPP2: Presence Announcement notification in STA
980c4da41 DPP2: Presence Announcement notification in AP
8b667bfa1 DPP2: Presence Announcement notification
cf3d260c3 DPP2: Fix hostapd crash setting global configurator params on chirp RX
a8f304228 Document the missing ignore_broadcast_ssid network profile parameter
aa704020a DBus: Update dont_quote[] with ignore_broadcast_ssid parameter
88d3f43bd DPP2: Replace OneAsymmetricKey version number (v2 to v1)
8e5739c3a DPP2: Check channel 6 validity before adding it to chirp channel list
5c6c0d569 DPP: Fix GAS fragmentation for DPP Config Response from hostapd
a7f55f7f6 WPS: Enable SA Query checks for WPS AP
43ef227e9 P2P: Make use wpas_p2p_reconsider_moving_go timeout gets canceled
57536a567 P2P: Fix P2P interface remuval through wpa_supplicant_remove_iface()
760d10cde P2P: Include channels 149 to 161 for operating classes 128 and 130
ac882374a SAE: Fix error path handling for SSWU
e8a1e6a4a P2P: Fix a typo in a comment
fa63284af Add additional roam triggers to qca_vendor_roam_triggers
13feeaa10 Add a new status code to represent an already suspended TWT session
8175c2654 Add test configuration attr to start/stop transmitting FD frames
90e478aa0 DPP2: Use the PFS fallback if multiple key_mgmt values are enabled
cab139ebc Fix a typo in a comment
7e20502f7 hostapd: Resolved compiler uninitialized warning
e3ba0c4cd Do not start SA Query procedure without keys
a92660a00 Work around Supported Operating Classes element issues for 6 GHz
fd4a58ccd Additional attributes to QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL
8a6a2894d Add new QCA vendor attributes to get thermal level
41f818905 SAE-PK: Add support to skip sae_pk password check for testing purposes
a71b100c3 OCV: Allow connecting MFP incapable OCV STA when OCV is disabled in AP
5ecb45a41 OCV: Use more granular error codes for OCI validation failures
10c3e58b2 DPP2: Include E-nonce in reconfig ke derivation
4ae5e459d DPP2: Move E-nonce to be outside wrapped data in Reconfig Auth Resp
0ebf5aa34 DPP2: Replace I/R-nonce with C/E-nonce in reconfiguration
99f8506d3 Add QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS
93a73ce02 MSCS: Fix issues due to incorrect usage of wpa_hexdump_buf()
9afb68b03 OpenSSL: Allow systemwide secpolicy overrides for TLS version
c85206ba4 QCA vendor attributes for setting ANI level
d335ca953 Update QCA vendor interface for GPIO configuration
7ddb71224 DPP2: Support QR mutual auth scan-during-auth-exchange (hostapd)
c043b1e00 DPP: Remove unnecessary dpp_global_config parameters
4ecb6dd16 DPP2: Controller support in hostapd
cd17f6877 Add QCA vendor event for firmware statistics
ba3081f1d dpp-nfc: Start listen operation more completely for NFC Tag write cases
e4adbacaf GAS: Fix memory leak on some DPP error paths
8aa91282a Fix EAPOL-Key msg 1/4 processing in a corner case
96e63008f OWE: Do not add DH Params element in AssocResp with PMKSA caching
9bc881153 DPP2: Fix build without IEEE8021X_EAPOL
2caff11d7 LibreSSL: Fix build with LibreSSL versions older than 2.9.1
55a366d7a dpp-nfc: Fix recv_octets() regression
90e05626f Add test configuration to ignore SA Query timeout
a2d35b49e Fix documentation for the test configuration attributes of FT-SAE/OCV
5d2218e61 Add get_sta_info vendor attrs to get BIP failure counters for STA mode
c6a760b9c DPP: Add process_conf_obj into TCP connection data struct
7f366fcbd DPP: Add msg_ctx into TCP connection data struct
6aa7aa808 DPP2: hostapd/AP as Enrollee/Initiator over TCP
d21dde9da MSCS: Send MSCS change/remove frames only if MSCS setup exists
af8ab3208 MSCS: Parse result of MSCS setup in (Re)Association Response frames
c504ff539 MSCS: Add support to populate MSCS Descriptor IE in (Re)AssocReq
bbd3178af MSCS: Add support to process MSCS Response frames
a11804724 MSCS: Add support to send MSCS Request frames
1733e356e dpp-nfc: Fix handover client wait for receiving handover select
596d99567 SME: Process channel switch event in SME only when supplicant's SME is used
0fa274d2b Derive seg0_idx and seg1_idx for 6 GHz when processing channel switch
5644b23de QCA vendor command to update SSID
cd708e8ff Add a vendor command for medium assessment
cc9fe46b3 Add AllPlay type to the QCA vendor element
170775232 ANQP: Add support to specify frequency in ANQP_GET command
43106e122 GAS: Update source MAC address on preassoc_mac_addr randomization
1289ecf4c GAS: Ignore preassoc_mac_addr when gas_rand_mac_addr enabled
dbe485a35 SAE-PK: Check psk param also to look for SAE-PK acceptable BSS
f5388b34e Add channel TX/RX times to QCA vendor interface of LL stats
9f9c11048 Fix QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO interface documentation
096456c0c Enhancements to the TWT attributes/parameters (vendor command)
3adc1c623 DPP2: Disconnect before starting reconfiguration
574a8fa6c DPP: Do not interpret unknown channel as missing channel list for NFC
fc3efe083 DPP2: Support mutual auth with QR in scan-during-auth-exchange case
2e956c37d DPP2: Do not close TCP socket when waiting for full Auth Resp
e4e95aabb DPP2: Allow Controller to be configured to require QR mutual auth
61c249c49 Add QCA vendor attribute to configure number of TX/RX chains
86fd6755c dpp-nfc: Use --altchan value in handover server
315422196 dpp-nfc: Update listen channel based on channel list when writing a tag
66ffe9d24 DPP2: Update Reconfig Flags attribute format
5caf4e094 DPP2: Support RA/CA functionality in Controller initiated case
9304d1b3c DPP2: Regenerate Reconfig Announcement for each transmission
b591810f9 DPP2: Add DPP Status attribute into Reconfig Auth Confirm
6d0217119 DPP2: Allow iteration count to be configured for DPP_RECONFIG
c6d0e5a93 DPP2: Add E-id in Reconfig Announcement
e5be6e68c DPP2: Add Enrollee netAccessKey group into Reconfig Announcement
2a58968d3 SAE-PK: Allow SAE-PK password to be set using the psk parameter
7ca81190a SAE-PK: Allow SAE-PK style wpa_passphrase if SAE-PK is enabled with same
844ecc70a Additional TWT attributes for response path and resume
0a9d7b169 SAE-PK: Update design for fingerprint encoding into password
2f858254c Extend GET_PMK to check PMKSA cache on the AP
b28b9dfcb OCV: OCI channel override support for testing (STA)
d309dd52b Fix the documentation for QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE
87971ff05 SAE-PK: Fix SAE confirm writing in some AP cases with transition mode
240e9af4d SAE-PK: Make no-KEK debug prints distinct
38ef655eb dpp-nfc: Report negotiated connection handover result
4d5461842 dpp-nfc: Stop only_one run after failed handover attempt
f7b5a1d34 dpp-nfc: Do not indicate no initial HS as failure if alt HR will be sent
475b34665 dpp-nfc: Improved version of HandoverServer::serve()
dc0795e4f dpp-nfc: Stop process after successful handover client completion
b00bbbfe5 dpp-nfc: Optimize HandoverClient message receiving for alternative HR case
bbfb7b9fe dpp-nfc: Use a single handover client thread
aaa8638ed dpp-nfc: Add a class for maintaining connection handover state
66d74626b dpp-nfc: Reuse the same handover client for alternative URI
6e904441c dpp-nfc: Add peer URI into the HS in testing mode
3021b14c4 dpp-nfc: Enable more verbose nfcpy debugging
7c04bab71 tests: AES-CTR encrypt test vectors
1d3e16d0b dpp-nfc: Skip P2P management interfaces
e9c192ffc dpp-nfc: Ignore (no) response to initial handover request
7d27bcb8e dpp-nfc: Do not allow more than one alternative channel proposal
6eaee933d dpp-nfc: Add test mode for negotiated connection handover
730fc307b Update documentation for vendor attributes to ignore BSSIDs during roaming
f4877083e Rename driver op for temporarily disallowed BSSIDs
f8c756c5b FT: Rename temporary blocking of nonresponsive R0KH
15018d4f4 DPP2: Fix auth termination after receiving Configurator backup
74cd38ac6 dpp-nfc: Return failure status if operation fails
7e2edfbc1 dpp-nfc: Add color and details for interactive operations
09c22bb78 dpp-nfc: Fix regression in NFC Tag writing
1e4a42c74 dpp-nfc: Detect a non-NDEF tag when trying to write
288c0ffaa dpp-nfc: Do not hardcode netrole for NFC Tag writing cases
ebd5e764f Vendor attribute to configure QoS/AC upgrade for UDP frames
d91fb3ce3 Add a vendor command to fetch the currently enabled band(s)
29e47c416 Vendor command to configure TWT
8f396ad68 Enhance the qca_set_band enum values to be used as a bitmap
cc6153a8a nl80211: Fix sending proper VLAN ID attr value when using VLAN offload
a57f98754 Fix enabling 40/80 MHz bandwidth support in the 6 GHz band
885097125 mesh: Fix peer link counting when removing a mesh peer
8632dea4a DPP2: Make sure dpp_auth gets cleared with external config processing
a7ae42296 DPP2: Do not allow reconfiguration to be started with pending auth
d93df9989 DPP2: Debug print reason for rejecting reconfiguration
5d8c5f344 SAE-PK: Fix password validation check for Sec
0ce6883f6 tests: Fix SAE-PK password module tests
c9dc075fc dpp-nfc: Fix connection handover renegotiation
d0819a11c FILS: Use FILS auth alg when connecting using PMKSA caching
70b80c31f nl80211: Do not send FILS ERP sequence number without rRK
52a325762 6 GHz: Change 6 GHz channels per IEEE P802.11ax/D6.1
5908fedc1 dpp-nfc: Support channel list negotiation
eddf22e1f dpp-nfc: Update debug print for tag-read-only operation
b62e46f69 DPP2: Fix DPP_CA_SET processing with authentication not having peer BI
4f4a52c3c DPP: Clear bootstrap entries only after clearing authentication state
67efd19e0 nl80211: Use control port TX (status) in AP mode if possible
569497bf4 nl80211: Work around misdelivered control port TX status
87065881b nl80211: Use ext ack handler for TX control port
6f19cc4d7 nl80211: Handle control port TX status events over nl80211
f7c657b79 nl80211: Add custom ack handler arguments to send_and_recv()
73ea1ad7f nl80211: Clean up SO_WIFI_STATUS error reporting
cd99a8c43 EAP-TEAP (server): Allow Phase 2 skip based on client certificate
519629392 EAP-TEAP (client): Allow Phase 2 to be skipped if certificate is used
9593ce658 OpenSSL: Provide access to peer subject and own certificate use
b5dab03a1 Convert int to bool for throughput estimate tables
b97aa038b Add WPA_EVENT_{DO,SKIP}_ROAM events
d6b450e89 Refactor wpa_supplicant_need_to_roam()
2ff5a1fdb Use lookup-table instead of macro for TX rate estimates
fa09b85c4 DPP2: Remove forgetten development time debug prints
0bbab6465 DPP2: Fix dot1x config object parsing without trustedEapServerName
8f88dcf05 DPP2: Add an automatic peer_bi entry for CSR matching if needed
b25ddfe9d DPP2: Add Enrollee name into CSR as the commonName
11aa77e00 DPP2: GAS comeback response processing for Enrollee over TCP
18e013a93 DPP2: GAS comeback request processing for Configurator over TCP
68d9586a4 DPP2: GAS Comeback Request for the TCP case
a352c7230 DPP2: Comeback delay response for certificate in over TCP case
0f9463d6e DPP2: CSR wait in Configurator when using TCP
1f86b2c24 DPP2: CSR generation in TCP Client/Enrollee
697fa0c4b DPP2: Do not try to proceed with GAS client if CSR building fails
ffc8ae507 Define a new QCA vendor attribute for Optimized Power Management
3a3eded0d DPP2: Allow CSR processing by CA/RA to reject configuration
3b60f1174 DPP2: Validate CSR on Configurator before forwarding to CA/RA
c98db9f1f DPP2: Add challengePassword into CSR
dbbb0d5b8 OpenSSL: Use EVP-based interface for ECDSA sign/verify
ace3723d9 DPP2: Enterprise provisioning (Enrollee)
6568e5d20 DPP2: Enterprise provisioning (Configurator)
4643b2fee DPP2: Enterprise provisioning definitions for dot1x AKM
812d52ae2 OpenSSL: Support EC key from private_key blob
4b834df5e OpenSSL: Support PEM encoded chain from client_cert blob
68ac45d53 GAS server: Support comeback delay from the request handler
608adae5b JSON: Add base64 helper functions
c7e6dbdad base64: Add no-LF variant for encoding
6dc2c0118 Update DFS terminology in attribute value documentation
621745917 Allow HE-without-VHT to add the Channel Switch Wrapper element
d51b1b7a6 Move hostapd_eid_wb_chsw_wrapper() to non-VHT-specific file
1f72bbbef AP: Reject association request upon invalid HE capabilities
088bef178 AP: Restrict Vendor VHT to 2.4 GHz only
6a34bd300 HE: Use device HE capability instead of HT/VHT for 6 GHz IEs
9272ebae8 nl80211: Fetch HE 6 GHz capability from the driver
f25c51a9f Sync with mac80211-next.git include/uapi/linux/nl80211.h
518be614f SAE-PK: Advertise RSNXE capability bit in STA mode
a77d6d220 SAE-PK: Update SAE confirm IE design
363dbf1ec SAE-PK: Remove requirement of SAE group matching SAE-PK (K_AP) group
2e80aeae4 WPS UPnP: Support build on OS X
f119f8a04 WPS UPnP: Fix FreeBSD build
cc2d03601 HS 2.0: Use global pmf=2 for the created network block
790026c3d Allow TX queue parameters to be configured for wpa_supplicant AP/P2P GO
c7cb42d53 Remove unused enum values
411e42673 Move local TX queue parameter parser into a common file
fcef598ea Do not try to connect with zero-length SSID
85aac526a WPS UPnP: Handle HTTP initiation failures for events more properly
f7d268864 WPS UPnP: Fix event message generation using a long URL path
5b78c8f96 WPS UPnP: Do not allow event subscriptions with URLs to other networks
e30dcda3b SAE-PK: Fix FILS Public Key element Key Type for ECDSA
4c3fbb234 SAE-PK: Check minimum password length more accurate
43a191b89 tests: Remove too short SAE-PK passwords
4ff0df39e SAE-PK: Testing functionality to allow behavior overrides
0c4ffce46 Allow transition_disable updates during the lifetime of a BSS
5f48d36b4 SAE-PK: Select SAE-PK network over SAE without PK
d654ca24d Clean up wpa_scan_res_match()
9ad010c29 SAE-PK: Allow automatic SAE-PK to be disabled
85ca13ebc wpa_cli: Add all_bss command to print all scan results (BSS entries)
215b4d8a7 FT: Do not add PMKID to the driver for FT-EAP if caching is disabled
5cf91afee QCA vendor attribute for dynamic bandwidth adjustment
1a28589b2 QCA vendor attributes for setting channel width
63653307d Add support for indicating missing driver AKM capability flags
18f3f99ac Add vendor attributes to configure testing functionality for FT/OCV/SAE
e53756a64 Fix a typo vendor attribute documentation
960e8e533 QCA vendor attribute to configure NSS
8d1cbaaff SAE-PK: Transition mode disabled indication processing
a75269529 SAE: Add sae_h2e and sae_pk to wpa_supplicant STATUS command
cc22fb1b8 SAE: Move H2E and PK flags to main sae_data
bc908daac Document more network profile parameters
1c846d647 SAE-PK: Allow SAE authentication without PK to be disabled
40240735b WPS UPnP: Do not update Beacon frames unnecessarily on subscription removal
c85b39ec5 SAE-PK: Increment the minimum password length to 9
2c7b5a2c5 tests: Skip too short SAE-PK passwords in positive testing
d777156e1 SAE-PK: Determine hash algorithm from K_AP group instead of SAE group
fb09ec87f SAE-PK: A tool for generating SAE-PK Modifier and password
b6bcd74e5 Show SAE capabilities in control interface
9bf576870 Show SAE flags in scan results
e7aeb6d8a SAE-PK: STA functionality
20ccf97b3 SAE-PK: AP functionality
00e4fbdcc tests: Module test for SAE-PK
6b9e99e57 SAE-PK: Extend SAE functionality for AP validation
b6dcbd01a SAE-PK: Identifier definitions
aed01b82d OpenSSL: Additional EC functionality for SAE-PK
8c1f61e82 OCV: Report OCI validation failures with OCV-FAILURE messages (STA)
661e66118 OCV: Allow OCI channel to be overridden for testing (AP)
d10a57f6e DPP2: Derive a separate key for enveloped data
32d3360f3 DPP: Fix a typo in a comment
5a7bcb772 OSEN: Do not send the actual BIGTK to OSEN STAs
2d6cc0e67 FT: Do not expose GTK/IGTK in FT Reassociation Response frame in OSEN
a99833789 WNM: Do not expose GTK/IGTK in WNM Sleep Mode Response frame in OSEN
d578e890e OWE: Skip beacon update of transition BSS if it is not yet enabled
88436baaa Add a vendor attribute to get OEM data
3f9a89ca1 Vendor attributes for configuring LDPC, TX STBC, RX STBC
8ee0bc622 OCV: Disconnect STAs that do not use SA Query after CSA
01ceb88c7 OCV: Report validation errors for (Re)Association Request frames
a3556d581 OCV: Report validation errors for EAPOL-Key messages in AP mode
d52067a5b OCV: Report validation errors for SA Query Request/Response in AP mode
52579be86 OCV: Move "OCV failed" prefix to callers
2d118f557 OCV: Add support to override channel info OCI element (STA)
c2080e865 Clear current PMKSA cache selection on association/roam
d9532eb70 Debug print PMK-R0/R1 and PMKR0/R1Name in the helper functions
5ab8ad4cf Vendor attributes for ssetting TX A-MSDU and RX A-MSDU parameters
f7a904a28 QCA vendor command for adding and deleting TSPEC
82867456e Vendor attributes to configure PMF protection and disassoc Tx for testing
e5e275745 Add QCA vendor interface support to configure PHY modes
db0d0b84a nl80211: Control the registration for RRM frame with driver_param

Change-Id: I07d9feb8f019a22917ffc0088126c04b7d80115a
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 5cc9c65..3a99bb6 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -128,6 +128,7 @@
 OBJS += wmm_ac.c
 OBJS += op_classes.c
 OBJS += rrm.c
+OBJS += robust_av.c
 OBJS_p = wpa_passphrase.c
 OBJS_p += src/utils/common.c
 OBJS_p += src/utils/wpa_debug.c
@@ -265,6 +266,10 @@
 ifdef CONFIG_SAE
 L_CFLAGS += -DCONFIG_SAE
 OBJS += src/common/sae.c
+ifdef CONFIG_SAE_PK
+L_CFLAGS += -DCONFIG_SAE_PK
+OBJS += src/common/sae_pk.c
+endif
 NEED_ECC=y
 NEED_DH_GROUPS=y
 NEED_HMAC_SHA256_KDF=y
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index b35d11e..08522de 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1,11 +1,24 @@
-ifndef CC
-CC=gcc
+BINALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+BINALL += wpa_passphrase
 endif
 
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
+ALL = $(BINALL)
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant@.service
+ALL += systemd/wpa_supplicant-nl80211@.service
+ALL += systemd/wpa_supplicant-wired@.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+ifdef CONFIG_BUILD_WPA_CLIENT_SO
+ALL += libwpa_client.so
 endif
 
+EXTRA_TARGETS=dynamic_eap_methods
+
+CONFIG_FILE=.config
+include ../src/build.rules
+
 ifdef LIBS
 # If LIBS is set with some global build system defaults, clone those for
 # LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
@@ -26,8 +39,6 @@
 CFLAGS += -I$(abspath ../src)
 CFLAGS += -I$(abspath ../src/utils)
 
--include .config
-
 ifndef CONFIG_NO_GITVER
 # Add VERSION_STR postfix for builds from a git repository
 ifeq ($(wildcard ../.git),../.git)
@@ -44,34 +55,6 @@
 CONFIG_TDLS_TESTING=y
 endif
 
-BINALL=wpa_supplicant wpa_cli
-
-ifndef CONFIG_NO_WPA_PASSPHRASE
-BINALL += wpa_passphrase
-endif
-
-ALL = $(BINALL)
-ALL += systemd/wpa_supplicant.service
-ALL += systemd/wpa_supplicant@.service
-ALL += systemd/wpa_supplicant-nl80211@.service
-ALL += systemd/wpa_supplicant-wired@.service
-ALL += dbus/fi.w1.wpa_supplicant1.service
-ifdef CONFIG_BUILD_WPA_CLIENT_SO
-ALL += libwpa_client.so
-endif
-
-
-all: verify_config $(ALL) dynamic_eap_methods
-
-verify_config:
-	@if [ ! -r .config ]; then \
-		echo 'Building wpa_supplicant requires a configuration file'; \
-		echo '(.config). See README for more instructions. You can'; \
-		echo 'run "cp defconfig .config" to create an example'; \
-		echo 'configuration.'; \
-		exit 1; \
-	fi
-
 mkconfig:
 	@if [ -f .config ]; then \
 		echo '.config exists - did not replace it'; \
@@ -107,6 +90,7 @@
 OBJS += ../src/utils/crc32.o
 OBJS += op_classes.o
 OBJS += rrm.o
+OBJS += robust_av.o
 OBJS_p = wpa_passphrase.o
 OBJS_p += ../src/utils/common.o
 OBJS_p += ../src/utils/wpa_debug.o
@@ -267,6 +251,10 @@
 ifdef CONFIG_SAE
 CFLAGS += -DCONFIG_SAE
 OBJS += ../src/common/sae.o
+ifdef CONFIG_SAE_PK
+CFLAGS += -DCONFIG_SAE_PK
+OBJS += ../src/common/sae_pk.o
+endif
 NEED_ECC=y
 NEED_DH_GROUPS=y
 NEED_HMAC_SHA256_KDF=y
@@ -1866,53 +1854,40 @@
 CFLAGS += -DCONFIG_NO_TKIP
 endif
 
-ifndef LDO
-LDO=$(CC)
-endif
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-endif
-
 dynamic_eap_methods: $(EAPDYN)
 
-../src/drivers/build.wpa_supplicant:
-	@if [ -f ../src/drivers/build.hostapd ]; then \
-		$(MAKE) -C ../src/drivers clean; \
-	fi
-	@touch ../src/drivers/build.wpa_supplicant
-
-BCHECK=../src/drivers/build.wpa_supplicant
-
+_OBJS_VAR := OBJS_priv
+include ../src/objs.mk
 wpa_priv: $(BCHECK) $(OBJS_priv)
 	$(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
 	@$(E) "  LD " $@
 
-$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
-
+_OBJS_VAR := OBJS
+include ../src/objs.mk
 wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
 	$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
 	@$(E) "  LD " $@
 
+_OBJS_VAR := OBJS_t
+include ../src/objs.mk
 eapol_test: $(OBJS_t)
 	$(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
 	@$(E) "  LD " $@
 
+_OBJS_VAR := OBJS_t2
+include ../src/objs.mk
 preauth_test: $(OBJS_t2)
 	$(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
 	@$(E) "  LD " $@
 
+_OBJS_VAR := OBJS_p
+include ../src/objs.mk
 wpa_passphrase: $(OBJS_p)
 	$(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) $(LIBS)
 	@$(E) "  LD " $@
 
+_OBJS_VAR := OBJS_c
+include ../src/objs.mk
 wpa_cli: $(OBJS_c)
 	$(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
 	@$(E) "  LD " $@
@@ -1926,6 +1901,8 @@
 LIBCTRLSO += ../src/utils/common.c
 LIBCTRLSO += ../src/utils/wpa_debug.c
 
+_OBJS_VAR := LIBCTRL
+include ../src/objs.mk
 libwpa_client.a: $(LIBCTRL)
 	$(Q)rm -f $@
 	$(Q)$(AR) crs $@ $?
@@ -1935,14 +1912,19 @@
 	@$(E) "  CC  $@ ($^)"
 	$(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^
 
-libwpa_test1: libwpa_test.o libwpa_client.a
-	$(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 libwpa_test.o libwpa_client.a $(LIBS_c)
+OBJS_wpatest := libwpa_test.o
+_OBJS_VAR := OBJS_wpatest
+include ../src/objs.mk
+libwpa_test1: $(OBJS_wpatest) libwpa_client.a
+	$(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 $(OBJS_wpatest) libwpa_client.a $(LIBS_c)
 	@$(E) "  LD " $@
 
-libwpa_test2: libwpa_test.o libwpa_client.so
-	$(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 libwpa_test.o -L. -lwpa_client $(LIBS_c)
+libwpa_test2: $(OBJS_wpatest) libwpa_client.so
+	$(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 $(OBJS_wpatest) -L. -lwpa_client $(LIBS_c)
 	@$(E) "  LD " $@
 
+_OBJS_VAR := OBJS_nfc
+include ../src/objs.mk
 nfc_pw_token: $(OBJS_nfc)
 	$(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
 	@$(E) "  LD " $@
@@ -1979,16 +1961,6 @@
 	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
 		-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
 
-ifdef CONFIG_CODE_COVERAGE
-%.o: %.c
-	@$(E) "  CC " $<
-	$(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
-else
-%.o: %.c
-	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
-	@$(E) "  CC " $<
-endif
-
 %.service: %.service.in
 	$(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
 	@$(E) "  sed" $<
@@ -2030,15 +2002,16 @@
 fips:
 	$(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
 
-lcov-html: wpa_supplicant.gcda
-	lcov -c -d .. > lcov.info
+.PHONY: lcov-html
+lcov-html: $(call BUILDOBJ,wpa_supplicant.gcda)
+	lcov -c -d $(BUILDDIR) > lcov.info
 	genhtml lcov.info --output-directory lcov-html
 
-clean:
+clean: common-clean
 	$(MAKE) -C ../src clean
 	$(MAKE) -C dbus clean
 	rm -f core *~ *.o *.d *.gcno *.gcda *.gcov
-	rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
+	rm -f eap_*.so $(WINALL) eapol_test preauth_test
 	rm -f wpa_priv
 	rm -f nfc_pw_token
 	rm -f lcov.info
@@ -2046,5 +2019,3 @@
 	rm -f libwpa_client.a
 	rm -f libwpa_client.so
 	rm -f libwpa_test1 libwpa_test2
-
--include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6241682..a4892e7 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -53,30 +53,37 @@
 	u8 center_chan = 0;
 	u8 channel = conf->channel;
 #endif /* CONFIG_P2P */
+	u8 freq_seg_idx;
 
 	if (!conf->secondary_channel)
 		goto no_vht;
 
 	/* Use the maximum oper channel width if it's given. */
 	if (ssid->max_oper_chwidth)
-		conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+		hostapd_set_oper_chwidth(conf, ssid->max_oper_chwidth);
 
-	ieee80211_freq_to_chan(ssid->vht_center_freq2,
-			       &conf->vht_oper_centr_freq_seg1_idx);
+	if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) {
+		ieee80211_freq_to_chan(ssid->vht_center_freq2,
+				       &freq_seg_idx);
+		hostapd_set_oper_centr_freq_seg1_idx(conf, freq_seg_idx);
+	}
 
 	if (!ssid->p2p_group) {
-		if (!ssid->vht_center_freq1 ||
-		    conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+		if (!ssid->vht_center_freq1)
 			goto no_vht;
 		ieee80211_freq_to_chan(ssid->vht_center_freq1,
-				       &conf->vht_oper_centr_freq_seg0_idx);
-		wpa_printf(MSG_DEBUG, "VHT seg0 index %d for AP",
-			   conf->vht_oper_centr_freq_seg0_idx);
+				       &freq_seg_idx);
+		hostapd_set_oper_centr_freq_seg0_idx(conf, freq_seg_idx);
+
+		wpa_printf(MSG_DEBUG,
+			   "VHT seg0 index %d and seg1 index %d for AP",
+			   hostapd_get_oper_centr_freq_seg0_idx(conf),
+			   hostapd_get_oper_centr_freq_seg1_idx(conf));
 		return;
 	}
 
 #ifdef CONFIG_P2P
-	switch (conf->vht_oper_chwidth) {
+	switch (hostapd_get_oper_chwidth(conf)) {
 	case CHANWIDTH_80MHZ:
 	case CHANWIDTH_80P80MHZ:
 		center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
@@ -96,14 +103,14 @@
 		 * try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
 		 * not supported.
 		 */
-		conf->vht_oper_chwidth = CHANWIDTH_160MHZ;
+		hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
 		center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
 		if (center_chan) {
 			wpa_printf(MSG_DEBUG,
 				   "VHT center channel %u for auto-selected 160 MHz bandwidth",
 				   center_chan);
 		} else {
-			conf->vht_oper_chwidth = CHANWIDTH_80MHZ;
+			hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
 			center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
 								channel);
 			wpa_printf(MSG_DEBUG,
@@ -115,9 +122,9 @@
 	if (!center_chan)
 		goto no_vht;
 
-	conf->vht_oper_centr_freq_seg0_idx = center_chan;
+	hostapd_set_oper_centr_freq_seg0_idx(conf, center_chan);
 	wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO",
-		   conf->vht_oper_centr_freq_seg0_idx);
+		   hostapd_get_oper_centr_freq_seg0_idx(conf));
 	return;
 #endif /* CONFIG_P2P */
 
@@ -125,9 +132,27 @@
 	wpa_printf(MSG_DEBUG,
 		   "No VHT higher bandwidth support for the selected channel %d",
 		   conf->channel);
-	conf->vht_oper_centr_freq_seg0_idx =
-		conf->channel + conf->secondary_channel * 2;
-	conf->vht_oper_chwidth = CHANWIDTH_USE_HT;
+	hostapd_set_oper_centr_freq_seg0_idx(
+		conf, conf->channel + conf->secondary_channel * 2);
+	hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+}
+
+
+static struct hostapd_hw_modes *
+wpa_supplicant_find_hw_mode(struct wpa_supplicant *wpa_s,
+			    enum hostapd_hw_mode hw_mode)
+{
+	struct hostapd_hw_modes *mode = NULL;
+	int i;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		if (wpa_s->hw.modes[i].mode == hw_mode) {
+			mode = &wpa_s->hw.modes[i];
+			break;
+		}
+	}
+
+	return mode;
 }
 
 
@@ -144,9 +169,6 @@
 		return -1;
 	}
 
-	/* TODO: enable HT40 if driver supports it;
-	 * drop to 11b if driver does not support 11g */
-
 	/*
 	 * Enable HT20 if the driver supports it, by setting conf->ieee80211n
 	 * and a mask of allowed capabilities within conf->ht_capab.
@@ -155,17 +177,28 @@
 	 */
 	if (wpa_s->hw.modes) {
 		struct hostapd_hw_modes *mode = NULL;
-		int i, no_ht = 0;
+		int no_ht = 0;
 
 		wpa_printf(MSG_DEBUG,
 			   "Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)",
 			   ssid->frequency, conf->channel);
 
-		for (i = 0; i < wpa_s->hw.num_modes; i++) {
-			if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
-				mode = &wpa_s->hw.modes[i];
-				break;
-			}
+		mode = wpa_supplicant_find_hw_mode(wpa_s, conf->hw_mode);
+
+		/* May drop to IEEE 802.11b if the driver does not support IEEE
+		 * 802.11g */
+		if (!mode && conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+			conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+			wpa_printf(MSG_INFO,
+				   "Try downgrade to IEEE 802.11b as 802.11g is not supported by the current hardware");
+			mode = wpa_supplicant_find_hw_mode(wpa_s,
+							   conf->hw_mode);
+		}
+
+		if (!mode) {
+			wpa_printf(MSG_ERROR,
+				   "No match between requested and supported hw modes found");
+			return -1;
 		}
 
 #ifdef CONFIG_HT_OVERRIDES
@@ -190,6 +223,14 @@
 				      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET),
 				   ssid->ht40);
 			conf->ieee80211n = 1;
+
+			if (ssid->ht40 &&
+			    (mode->ht_capab &
+			     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+				conf->secondary_channel = ssid->ht40;
+			else
+				conf->secondary_channel = 0;
+
 #ifdef CONFIG_P2P
 			if (ssid->p2p_group &&
 			    conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
@@ -231,16 +272,19 @@
 				 HT_CAP_INFO_TX_STBC |
 				 HT_CAP_INFO_MAX_AMSDU_SIZE);
 
+			/* check this before VHT, because setting oper chan
+			 * width and friends is the same call for HE and VHT
+			 * and checks if conf->ieee8021ax == 1 */
+			if (mode->he_capab[wpas_mode_to_ieee80211_mode(
+					    ssid->mode)].he_supported &&
+			    ssid->he)
+				conf->ieee80211ax = 1;
+
 			if (mode->vht_capab && ssid->vht) {
 				conf->ieee80211ac = 1;
 				conf->vht_capab |= mode->vht_capab;
 				wpas_conf_ap_vht(wpa_s, ssid, conf, mode);
 			}
-
-			if (mode->he_capab[wpas_mode_to_ieee80211_mode(
-					    ssid->mode)].he_supported &&
-			    ssid->he)
-				conf->ieee80211ax = 1;
 		}
 	}
 
@@ -858,6 +902,9 @@
 		  wpa_s->conf->wmm_ac_params,
 		  sizeof(wpa_s->conf->wmm_ac_params));
 
+	os_memcpy(wpa_s->ap_iface->conf->tx_queue, wpa_s->conf->tx_queue,
+		  sizeof(wpa_s->conf->tx_queue));
+
 	if (params.uapsd > 0) {
 		conf->bss[0]->wmm_enabled = 1;
 		conf->bss[0]->wmm_uapsd = 1;
@@ -1415,10 +1462,17 @@
 		      struct csa_settings *settings)
 {
 #ifdef NEED_AP_MLME
-	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+	struct hostapd_iface *iface = NULL;
+
+	if (wpa_s->ap_iface)
+		iface = wpa_s->ap_iface;
+	else if (wpa_s->ifmsh)
+		iface = wpa_s->ifmsh;
+
+	if (!iface || !iface->bss[0])
 		return -1;
 
-	return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+	return hostapd_switch_channel(iface->bss[0], settings);
 #else /* NEED_AP_MLME */
 	return -1;
 #endif /* NEED_AP_MLME */
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c
index e53dc38..2f32644 100644
--- a/wpa_supplicant/blacklist.c
+++ b/wpa_supplicant/blacklist.c
@@ -26,6 +26,15 @@
 	if (wpa_s == NULL || bssid == NULL)
 		return NULL;
 
+	if (wpa_s->current_ssid &&
+	    wpa_s->current_ssid->was_recently_reconfigured) {
+		wpa_blacklist_clear(wpa_s);
+		wpa_s->current_ssid->was_recently_reconfigured = false;
+		return NULL;
+	}
+
+	wpa_blacklist_update(wpa_s);
+
 	e = wpa_s->blacklist;
 	while (e) {
 		if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
@@ -56,16 +65,29 @@
 int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
 {
 	struct wpa_blacklist *e;
+	struct os_reltime now;
 
 	if (wpa_s == NULL || bssid == NULL)
 		return -1;
 
 	e = wpa_blacklist_get(wpa_s, bssid);
+	os_get_reltime(&now);
 	if (e) {
+		e->blacklist_start = now;
 		e->count++;
-		wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
-			   "incremented to %d",
-			   MAC2STR(bssid), e->count);
+		if (e->count > 5)
+			e->timeout_secs = 1800;
+		else if (e->count == 5)
+			e->timeout_secs = 600;
+		else if (e->count == 4)
+			e->timeout_secs = 120;
+		else if (e->count == 3)
+			e->timeout_secs = 60;
+		else
+			e->timeout_secs = 10;
+		wpa_printf(MSG_INFO, "BSSID " MACSTR
+			   " blacklist count incremented to %d, blacklisting for %d seconds",
+			   MAC2STR(bssid), e->count, e->timeout_secs);
 		return e->count;
 	}
 
@@ -74,10 +96,13 @@
 		return -1;
 	os_memcpy(e->bssid, bssid, ETH_ALEN);
 	e->count = 1;
+	e->timeout_secs = 10;
+	e->blacklist_start = now;
 	e->next = wpa_s->blacklist;
 	wpa_s->blacklist = e;
-	wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
-		   MAC2STR(bssid));
+	wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR
+		   " into blacklist, blacklisting for %d seconds",
+		   MAC2STR(bssid), e->timeout_secs);
 
 	return e->count;
 }
@@ -117,25 +142,80 @@
 
 
 /**
+ * wpa_blacklist_is_blacklisted - Check the blacklist status of a BSS
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be checked
+ * Returns: count if BSS is currently considered to be blacklisted, 0 otherwise
+ */
+int wpa_blacklist_is_blacklisted(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_blacklist *e;
+	struct os_reltime now;
+
+	e = wpa_blacklist_get(wpa_s, bssid);
+	if (!e)
+		return 0;
+	os_get_reltime(&now);
+	if (os_reltime_expired(&now, &e->blacklist_start, e->timeout_secs))
+		return 0;
+	return e->count;
+}
+
+
+/**
  * wpa_blacklist_clear - Clear the blacklist of all entries
  * @wpa_s: Pointer to wpa_supplicant data
  */
 void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_blacklist *e, *prev;
-	int max_count = 0;
 
 	e = wpa_s->blacklist;
 	wpa_s->blacklist = NULL;
 	while (e) {
-		if (e->count > max_count)
-			max_count = e->count;
 		prev = e;
 		e = e->next;
 		wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
 			   "blacklist (clear)", MAC2STR(prev->bssid));
 		os_free(prev);
 	}
+}
 
-	wpa_s->extra_blacklist_count += max_count;
+
+/**
+ * wpa_blacklist_update - Update the entries in the blacklist,
+ * deleting entries that have been expired for over an hour.
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_blacklist_update(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_blacklist *e, *prev = NULL;
+	struct os_reltime now;
+
+	if (!wpa_s)
+		return;
+
+	e = wpa_s->blacklist;
+	os_get_reltime(&now);
+	while (e) {
+		if (os_reltime_expired(&now, &e->blacklist_start,
+				       e->timeout_secs + 3600)) {
+			struct wpa_blacklist *to_delete = e;
+
+			if (prev) {
+				prev->next = e->next;
+				e = prev->next;
+			} else {
+				wpa_s->blacklist = e->next;
+				e = wpa_s->blacklist;
+			}
+			wpa_printf(MSG_INFO, "Removed BSSID " MACSTR
+				   " from blacklist (expired)",
+				   MAC2STR(to_delete->bssid));
+			os_free(to_delete);
+		} else {
+			prev = e;
+			e = e->next;
+		}
+	}
 }
diff --git a/wpa_supplicant/blacklist.h b/wpa_supplicant/blacklist.h
index ae06986..a1c60d5 100644
--- a/wpa_supplicant/blacklist.h
+++ b/wpa_supplicant/blacklist.h
@@ -13,12 +13,21 @@
 	struct wpa_blacklist *next;
 	u8 bssid[ETH_ALEN];
 	int count;
+	/* Time of most recent blacklist event. */
+	struct os_reltime blacklist_start;
+	/*
+	 * Number of seconds after blacklist_start that the entry will be
+	 * considered blacklisted.
+	 */
+	int timeout_secs;
 };
 
 struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
 					 const u8 *bssid);
 int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
 int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_blacklist_is_blacklisted(struct wpa_supplicant *wpa_s, const u8 *bssid);
 void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
+void wpa_blacklist_update(struct wpa_supplicant *wpa_s);
 
 #endif /* BLACKLIST_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index e1d9824..8a8765b 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2573,6 +2573,7 @@
 	{ STR_LEN(dpp_netaccesskey) },
 	{ INT(dpp_netaccesskey_expiry) },
 	{ STR_LEN(dpp_csign) },
+	{ STR_LEN(dpp_pp_key) },
 	{ INT_RANGE(dpp_pfs, 0, 2) },
 #endif /* CONFIG_DPP */
 	{ INT_RANGE(owe_group, 0, 65535) },
@@ -2582,6 +2583,7 @@
 	{ INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
 	{ INT_RANGE(beacon_prot, 0, 1) },
 	{ INT_RANGE(transition_disable, 0, 255) },
+	{ INT_RANGE(sae_pk, 0, 2) },
 };
 
 #undef OFFSET
@@ -2775,6 +2777,7 @@
 	os_free(ssid->dpp_connector);
 	bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
 	os_free(ssid->dpp_csign);
+	os_free(ssid->dpp_pp_key);
 	while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
 				    list))) {
 		dl_list_del(&psk->list);
@@ -3035,6 +3038,8 @@
 	ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
 	ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
 	ssid->ht = 1;
+	ssid->vht = 1;
+	ssid->he = 1;
 #ifdef IEEE8021X_EAPOL
 	ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
 	ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -3141,6 +3146,7 @@
 		}
 		ret = -1;
 	}
+	ssid->was_recently_reconfigured = true;
 
 	return ret;
 }
@@ -4254,6 +4260,8 @@
 struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 					   const char *driver_param)
 {
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
 	struct wpa_config *config;
 	const int aCWmin = 4, aCWmax = 10;
 	const struct hostapd_wmm_ac_params ac_bk =
@@ -4261,9 +4269,20 @@
 	const struct hostapd_wmm_ac_params ac_be =
 		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
 	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
-		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+		{ aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
 	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
-		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+		{ aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 };
+	const struct hostapd_tx_queue_params txq_bk =
+		{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+	const struct hostapd_tx_queue_params txq_be =
+		{ 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0 };
+	const struct hostapd_tx_queue_params txq_vi =
+		{ 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30 };
+	const struct hostapd_tx_queue_params txq_vo =
+		{ 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+		  (ecw2cw(aCWmin) + 1) / 2 - 1, 15 };
+
+#undef ecw2cw
 
 	config = os_zalloc(sizeof(*config));
 	if (config == NULL)
@@ -4293,6 +4312,10 @@
 	config->wmm_ac_params[1] = ac_bk;
 	config->wmm_ac_params[2] = ac_vi;
 	config->wmm_ac_params[3] = ac_vo;
+	config->tx_queue[0] = txq_vo;
+	config->tx_queue[1] = txq_vi;
+	config->tx_queue[2] = txq_be;
+	config->tx_queue[3] = txq_bk;
 	config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
 	config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
 	config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
@@ -4342,13 +4365,31 @@
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
 
+/**
+ * Structure for global configuration parsing. This data is used to implement a
+ * generic parser for the global interface configuration. The table of variables
+ * is defined below in this file (global_fields[]).
+ */
 struct global_parse_data {
+	/* Configuration variable name */
 	char *name;
+
+	/* Parser function for this variable. The parser functions return 0 or 1
+	 * to indicate success. Value 0 indicates that the parameter value may
+	 * have changed while value 1 means that the value did not change.
+	 * Error cases (failure to parse the string) are indicated by returning
+	 * -1. */
 	int (*parser)(const struct global_parse_data *data,
 		      struct wpa_config *config, int line, const char *value);
+
+	/* Getter function to print the variable in text format to buf. */
 	int (*get)(const char *name, struct wpa_config *config, long offset,
 		   char *buf, size_t buflen, int pretty_print);
+
+	/* Variable specific parameters for the parser. */
 	void *param1, *param2, *param3;
+
+	/* Indicates which configuration variable has changed. */
 	unsigned int changed_flag;
 };
 
@@ -4359,6 +4400,7 @@
 {
 	int val, *dst;
 	char *end;
+	bool same;
 
 	dst = (int *) (((u8 *) config) + (long) data->param1);
 	val = strtol(pos, &end, 0);
@@ -4367,6 +4409,7 @@
 			   line, pos);
 		return -1;
 	}
+	same = *dst == val;
 	*dst = val;
 
 	wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
@@ -4387,7 +4430,7 @@
 		return -1;
 	}
 
-	return 0;
+	return same;
 }
 
 
@@ -4395,7 +4438,7 @@
 				       struct wpa_config *config, int line,
 				       const char *pos)
 {
-	size_t len;
+	size_t len, prev_len;
 	char **dst, *tmp;
 
 	len = os_strlen(pos);
@@ -4419,11 +4462,22 @@
 		return -1;
 	}
 
+	dst = (char **) (((u8 *) config) + (long) data->param1);
+	if (*dst)
+		prev_len = os_strlen(*dst);
+	else
+		prev_len = 0;
+
+	/* No change to the previously configured value */
+	if ((!(*dst) && !pos) ||
+	    (*dst && pos && prev_len == len &&
+	     os_memcmp(*dst, pos, len) == 0))
+		return 1;
+
 	tmp = os_strdup(pos);
 	if (tmp == NULL)
 		return -1;
 
-	dst = (char **) (((u8 *) config) + (long) data->param1);
 	os_free(*dst);
 	*dst = tmp;
 	wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
@@ -4464,6 +4518,10 @@
 		return -1;
 
 	dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+	if (wpabuf_cmp(*dst, tmp) == 0) {
+		wpabuf_free(tmp);
+		return 1;
+	}
 	wpabuf_free(*dst);
 	*dst = tmp;
 	wpa_printf(MSG_DEBUG, "%s", data->name);
@@ -4505,6 +4563,8 @@
 		return -1;
 
 	dst = (u32 *) (((u8 *) config) + (long) data->param1);
+	if (os_memcmp(dst, &addr.u.v4.s_addr, 4) == 0)
+		return 1;
 	os_memcpy(dst, &addr.u.v4.s_addr, 4);
 	wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
 		   WPA_GET_BE32((u8 *) dst));
@@ -4522,6 +4582,8 @@
 		wpa_printf(MSG_DEBUG, "Invalid country set");
 		return -1;
 	}
+	if (pos[0] == config->country[0] && pos[1] == config->country[1])
+		return 1;
 	config->country[0] = pos[0];
 	config->country[1] = pos[1];
 	wpa_printf(MSG_DEBUG, "country='%c%c'",
@@ -4905,7 +4967,7 @@
 	{ INT_RANGE(eapol_version, 1, 2), 0 },
 #endif /* CONFIG_MACSEC */
 	{ INT(ap_scan), 0 },
-	{ FUNC(bgscan), 0 },
+	{ FUNC(bgscan), CFG_CHANGED_BGSCAN },
 #ifdef CONFIG_MESH
 	{ INT(user_mpm), 0 },
 	{ INT_RANGE(max_peer_links, 0, 255), 0 },
@@ -4979,6 +5041,7 @@
 	{ INT(p2p_device_random_mac_addr), 0 },
 	{ FUNC(p2p_device_persistent_mac_addr), 0 },
 	{ INT(p2p_interface_random_mac_addr), 0 },
+	{ INT(p2p_6ghz_disable), 0 },
 #endif /* CONFIG_P2P */
 	{ FUNC(country), CFG_CHANGED_COUNTRY },
 	{ INT(bss_max_count), 0 },
@@ -5140,6 +5203,19 @@
 }
 
 
+/**
+ * wpa_config_process_global - Set a variable in global configuration
+ * @config: Pointer to global configuration data
+ * @pos: Name and value in the format "{name}={value}"
+ * @line: Line number in configuration file or 0 if not used
+ * Returns: 0 on success with a possible change in value, 1 on success with no
+ * change to previously configured value, or -1 on failure
+ *
+ * This function can be used to set global configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
 {
 	size_t i;
@@ -5152,11 +5228,14 @@
 		    pos[flen] != '=')
 			continue;
 
-		if (field->parser(field, config, line, pos + flen + 1)) {
+		ret = field->parser(field, config, line, pos + flen + 1);
+		if (ret < 0) {
 			wpa_printf(MSG_ERROR, "Line %d: failed to "
 				   "parse '%s'.", line, pos);
 			ret = -1;
 		}
+		if (ret == 1)
+			break;
 		if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
 			config->wps_nfc_pw_from_config = 1;
 		config->changed_parameters |= field->changed_flag;
@@ -5164,6 +5243,26 @@
 	}
 	if (i == NUM_GLOBAL_FIELDS) {
 #ifdef CONFIG_AP
+		if (os_strncmp(pos, "tx_queue_", 9) == 0) {
+			char *tmp = os_strchr(pos, '=');
+
+			if (!tmp) {
+				if (line < 0)
+					wpa_printf(MSG_ERROR,
+						   "Line %d: invalid line %s",
+						   line, pos);
+				return -1;
+			}
+			*tmp++ = '\0';
+			if (hostapd_config_tx_queue(config->tx_queue, pos,
+						    tmp)) {
+				wpa_printf(MSG_ERROR,
+					   "Line %d: invalid TX queue item",
+					   line);
+				return -1;
+			}
+		}
+
 		if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
 			char *tmp = os_strchr(pos, '=');
 			if (tmp == NULL) {
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 0ca27cb..0b9e3db 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -376,6 +376,7 @@
 #define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
 #define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18)
 #define CFG_CHANGED_DISABLE_BTM BIT(19)
+#define CFG_CHANGED_BGSCAN BIT(20)
 
 /**
  * struct wpa_config - wpa_supplicant configuration data
@@ -779,6 +780,8 @@
 	int p2p_ignore_shared_freq;
 	int p2p_optimize_listen_chan;
 
+	int p2p_6ghz_disable;
+
 	struct wpabuf *wps_vendor_ext_m1;
 
 #define MAX_WPS_VENDOR_EXT 10
@@ -974,7 +977,7 @@
 	int go_venue_type;
 
 	/**
-	 * hessid - Homogenous ESS identifier
+	 * hessid - Homogeneous ESS identifier
 	 *
 	 * If this is set (any octet is non-zero), scans will be used to
 	 * request response only from BSSes belonging to the specified
@@ -1058,6 +1061,7 @@
 	int p2p_go_max_inactivity;
 
 	struct hostapd_wmm_ac_params wmm_ac_params[4];
+	struct hostapd_tx_queue_params tx_queue[4];
 
 	/**
 	 * auto_interworking - Whether to use network selection automatically
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 52e1372..74f91d3 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -876,9 +876,10 @@
 	write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
 	INT(disabled);
 	INT(mixed_cell);
-	INT(vht);
+	INT_DEF(vht, 1);
 	INT_DEF(ht, 1);
 	INT(ht40);
+	INT_DEF(he, 1);
 	INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH);
 	INT(vht_center_freq1);
 	INT(vht_center_freq2);
@@ -928,6 +929,7 @@
 	STR(dpp_netaccesskey);
 	INT(dpp_netaccesskey_expiry);
 	STR(dpp_csign);
+	STR(dpp_pp_key);
 	INT(dpp_pfs);
 #endif /* CONFIG_DPP */
 	INT(owe_group);
@@ -937,6 +939,7 @@
 	INT(ft_eap_pmksa_caching);
 	INT(beacon_prot);
 	INT(transition_disable);
+	INT(sae_pk);
 #ifdef CONFIG_HT_OVERRIDES
 	INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
 	INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
@@ -1332,6 +1335,10 @@
 	if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE)
 		fprintf(f, "p2p_go_freq_change_policy=%u\n",
 			config->p2p_go_freq_change_policy);
+
+	if (config->p2p_6ghz_disable)
+		fprintf(f, "p2p_6ghz_disable=%d\n", config->p2p_6ghz_disable);
+
 	if (WPA_GET_BE32(config->ip_addr_go))
 		fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
 			config->ip_addr_go[0], config->ip_addr_go[1],
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 6737223..ecf258c 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -61,6 +61,12 @@
 	WPAS_MODE_MESH = 5,
 };
 
+enum sae_pk_mode {
+	SAE_PK_MODE_AUTOMATIC = 0,
+	SAE_PK_MODE_ONLY = 1,
+	SAE_PK_MODE_DISABLED = 2,
+};
+
 /**
  * struct wpa_ssid - Network configuration data
  *
@@ -1017,6 +1023,16 @@
 	size_t dpp_csign_len;
 
 	/**
+	 * dpp_pp_key - ppKey (Configurator privacy protection public key)
+	 */
+	u8 *dpp_pp_key;
+
+	/**
+	 * dpp_pp_key_len - ppKey length in octets
+	 */
+	size_t dpp_pp_key_len;
+
+	/**
 	 * dpp_pfs - DPP PFS
 	 * 0: allow PFS to be used or not used
 	 * 1: require PFS to be used (note: not compatible with DPP R1)
@@ -1120,6 +1136,25 @@
 	 *	OWE)
 	 */
 	u8 transition_disable;
+
+	/**
+	 * sae_pk - SAE-PK mode
+	 * 0 = automatic SAE/SAE-PK selection based on password; enable
+	 * transition mode (allow SAE authentication without SAE-PK)
+	 * 1 = SAE-PK only (disable transition mode; allow SAE authentication
+	 * only with SAE-PK)
+	 * 2 = disable SAE-PK (allow SAE authentication only without SAE-PK)
+	 */
+	enum sae_pk_mode sae_pk;
+
+	/**
+	 * was_recently_reconfigured - Whether this SSID config has been changed
+	 * recently
+	 *
+	 * This is an internally used variable, i.e., not used in external
+	 * configuration.
+	 */
+	bool was_recently_reconfigured;
 };
 
 #endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index f2d4d01..f5c6587 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -751,6 +751,26 @@
 		}
 	} else if (os_strcasecmp(cmd, "ft_rsnxe_used") == 0) {
 		wpa_s->ft_rsnxe_used = atoi(value);
+	} else if (os_strcasecmp(cmd, "oci_freq_override_eapol") == 0) {
+		wpa_s->oci_freq_override_eapol = atoi(value);
+	} else if (os_strcasecmp(cmd, "oci_freq_override_saquery_req") == 0) {
+		wpa_s->oci_freq_override_saquery_req = atoi(value);
+	} else if (os_strcasecmp(cmd, "oci_freq_override_saquery_resp") == 0) {
+		wpa_s->oci_freq_override_saquery_resp = atoi(value);
+	} else if (os_strcasecmp(cmd, "oci_freq_override_eapol_g2") == 0) {
+		wpa_s->oci_freq_override_eapol_g2 = atoi(value);
+		/* Populate value to wpa_sm if already associated. */
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+				 wpa_s->oci_freq_override_eapol_g2);
+	} else if (os_strcasecmp(cmd, "oci_freq_override_ft_assoc") == 0) {
+		wpa_s->oci_freq_override_ft_assoc = atoi(value);
+		/* Populate value to wpa_sm if already associated. */
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+				 wpa_s->oci_freq_override_ft_assoc);
+	} else if (os_strcasecmp(cmd, "oci_freq_override_fils_assoc") == 0) {
+		wpa_s->oci_freq_override_fils_assoc = atoi(value);
+	} else if (os_strcasecmp(cmd, "oci_freq_override_wnm_sleep") == 0) {
+		wpa_s->oci_freq_override_wnm_sleep = atoi(value);
 	} else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
 		wpabuf_free(wpa_s->rsne_override_eapol);
 		if (os_strcmp(value, "NULL") == 0)
@@ -878,6 +898,8 @@
 		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
 		if (ret == 0)
 			wpa_supplicant_update_config(wpa_s);
+		else if (ret == 1)
+			ret = 0;
 	}
 
 	return ret;
@@ -2277,8 +2299,12 @@
 	    !wpa_s->ap_iface &&
 #endif /* CONFIG_AP */
 	    wpa_s->sme.sae.state == SAE_ACCEPTED) {
-		ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
-				  wpa_s->sme.sae.group);
+		ret = os_snprintf(pos, end - pos, "sae_group=%d\n"
+				  "sae_h2e=%d\n"
+				  "sae_pk=%d\n",
+				  wpa_s->sme.sae.group,
+				  wpa_s->sme.sae.h2e,
+				  wpa_s->sme.sae.pk);
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
@@ -2934,7 +2960,7 @@
 {
 	char *pos, *end;
 	int ret;
-	const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe;
+	const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe, *rsnxe;
 
 	mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
 	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2961,6 +2987,21 @@
 		pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
 					    ie2, 2 + ie2[1]);
 	}
+	rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+	if (rsnxe && rsnxe[1] >= 1) {
+		if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) {
+			ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+			if (os_snprintf_error(end - pos, ret))
+				return -1;
+			pos += ret;
+		}
+		if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) {
+			ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+			if (os_snprintf_error(end - pos, ret))
+				return -1;
+			pos += ret;
+		}
+	}
 	osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
 	if (osen_ie)
 		pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -3439,38 +3480,12 @@
 	struct wpa_supplicant *wpa_s, char *cmd)
 {
 	int id;
-	struct wpa_ssid *ssid;
 	int result;
 
 	/* cmd: "<network id>" or "all" */
 	if (os_strcmp(cmd, "all") == 0) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
-		if (wpa_s->sched_scanning)
-			wpa_supplicant_cancel_sched_scan(wpa_s);
-
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
-		if (wpa_s->current_ssid) {
-#ifdef CONFIG_SME
-			wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
-			wpa_sm_set_config(wpa_s->wpa, NULL);
-			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-			if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
-				wpa_s->own_disconnect_req = 1;
-			wpa_supplicant_deauthenticate(
-				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-		}
-		ssid = wpa_s->conf->ssid;
-		while (ssid) {
-			struct wpa_ssid *remove_ssid = ssid;
-			id = ssid->id;
-			ssid = ssid->next;
-			if (wpa_s->last_ssid == remove_ssid)
-				wpa_s->last_ssid = NULL;
-			wpas_notify_network_removed(wpa_s, remove_ssid);
-			wpa_config_remove_network(wpa_s->conf, id);
-		}
-		return 0;
+		return wpa_supplicant_remove_all_networks(wpa_s);
 	}
 
 	id = atoi(cmd);
@@ -3506,6 +3521,20 @@
 	if (ret == 1)
 		return 0; /* No change to the previously configured value */
 
+#ifdef CONFIG_BGSCAN
+	if (os_strcmp(name, "bgscan") == 0) {
+		/*
+		 * Reset the bgscan parameters for the current network and
+		 * return. There's no need to flush caches for bgscan parameter
+		 * changes.
+		 */
+		if (wpa_s->current_ssid == ssid &&
+		    wpa_s->wpa_state == WPA_COMPLETED)
+			wpa_supplicant_reset_bgscan(wpa_s);
+		return 0;
+	}
+#endif /* CONFIG_BGSCAN */
+
 	if (os_strcmp(name, "bssid") != 0 &&
 	    os_strcmp(name, "bssid_hint") != 0 &&
 	    os_strcmp(name, "priority") != 0) {
@@ -4771,6 +4800,20 @@
 	}
 #endif /* CONFIG_DPP */
 
+#ifdef CONFIG_SAE
+	if (os_strcmp(field, "sae") == 0 &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+#ifdef CONFIG_SAE_PK
+		res = os_snprintf(buf, buflen, "H2E PK");
+#else /* CONFIG_SAE_PK */
+		res = os_snprintf(buf, buflen, "H2E");
+#endif /* CONFIG_SAE_PK */
+		if (os_snprintf_error(buflen, res))
+			return -1;
+		return res;
+	}
+#endif /* CONFIG_SAE */
+
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
 		   field);
 
@@ -4891,7 +4934,7 @@
 	size_t i;
 	int ret;
 	char *pos, *end;
-	const u8 *ie, *ie2, *osen_ie, *mesh, *owe;
+	const u8 *ie, *ie2, *osen_ie, *mesh, *owe, *rsnxe;
 
 	pos = buf;
 	end = buf + buflen;
@@ -5011,6 +5054,21 @@
 			pos = wpa_supplicant_ie_txt(pos, end,
 						    mesh ? "RSN" : "WPA2", ie2,
 						    2 + ie2[1]);
+		rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+		if (rsnxe && rsnxe[1] >= 1) {
+			if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) {
+				ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+				if (os_snprintf_error(end - pos, ret))
+					return -1;
+				pos += ret;
+			}
+			if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) {
+				ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+				if (os_snprintf_error(end - pos, ret))
+					return -1;
+				pos += ret;
+			}
+		}
 		osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
 		if (osen_ie)
 			pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -7398,7 +7456,7 @@
 static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
 {
 	u8 dst_addr[ETH_ALEN];
-	int used;
+	int used, freq = 0;
 	char *pos;
 #define MAX_ANQP_INFO_ID 100
 	u16 id[MAX_ANQP_INFO_ID];
@@ -7412,6 +7470,15 @@
 	pos = dst + used;
 	if (*pos == ' ')
 		pos++;
+
+	if (os_strncmp(pos, "freq=", 5) == 0) {
+		freq = atoi(pos + 5);
+		pos = os_strchr(pos, ' ');
+		if (!pos)
+			return -1;
+		pos++;
+	}
+
 	while (num_id < MAX_ANQP_INFO_ID) {
 		if (os_strncmp(pos, "hs20:", 5) == 0) {
 #ifdef CONFIG_HS20
@@ -7446,7 +7513,7 @@
 	if (num_id == 0 && !subtypes && !mbo_subtypes)
 		return -1;
 
-	return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+	return anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes,
 			     mbo_subtypes);
 }
 
@@ -8325,9 +8392,10 @@
 	wpa_s->set_sta_uapsd = 0;
 	wpa_s->sta_uapsd = 0;
 
+	wpa_s->consecutive_conn_failures = 0;
+
 	wpa_drv_radio_disable(wpa_s, 0);
 	wpa_blacklist_clear(wpa_s);
-	wpa_s->extra_blacklist_count = 0;
 	wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
 	wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
 	wpa_config_flush_blobs(wpa_s->conf);
@@ -8381,6 +8449,13 @@
 	wpabuf_free(wpa_s->rsnxe_override_eapol);
 	wpa_s->rsnxe_override_eapol = NULL;
 	wpas_clear_driver_signal_override(wpa_s);
+	wpa_s->oci_freq_override_eapol = 0;
+	wpa_s->oci_freq_override_saquery_req = 0;
+	wpa_s->oci_freq_override_saquery_resp = 0;
+	wpa_s->oci_freq_override_eapol_g2 = 0;
+	wpa_s->oci_freq_override_ft_assoc = 0;
+	wpa_s->oci_freq_override_fils_assoc = 0;
+	wpa_s->oci_freq_override_wnm_sleep = 0;
 #ifdef CONFIG_DPP
 	os_free(wpa_s->dpp_config_obj_override);
 	wpa_s->dpp_config_obj_override = NULL;
@@ -8399,6 +8474,7 @@
 	wpa_s->next_scan_bssid_wildcard_ssid = 0;
 	os_free(wpa_s->select_network_scan_freqs);
 	wpa_s->select_network_scan_freqs = NULL;
+	os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
 
 	wpa_bss_flush(wpa_s);
 	if (!dl_list_empty(&wpa_s->bss)) {
@@ -8424,6 +8500,8 @@
 	wpa_supplicant_update_channel_list(wpa_s, NULL);
 
 	free_bss_tmp_disallowed(wpa_s);
+
+	os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
 }
 
 
@@ -9264,7 +9342,7 @@
 
 	if (ip.ip_hl != 5 || ip.ip_v != 4 || ntohs(ip.ip_len) > HWSIM_IP_LEN) {
 		wpa_printf(MSG_DEBUG,
-			   "test data: RX - ignore unexpect IP header");
+			   "test data: RX - ignore unexpected IP header");
 		return;
 	}
 
@@ -10258,6 +10336,76 @@
 }
 
 
+static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s,
+					  const char *cmd)
+{
+	size_t frame_classifier_len;
+	const char *pos, *end;
+	struct robust_av_data *robust_av = &wpa_s->robust_av;
+	int val;
+
+	/*
+	 * format:
+	 * <add|remove|change> [up_bitmap=<hex byte>] [up_limit=<integer>]
+	 * [stream_timeout=<in TUs>] [frame_classifier=<hex bytes>]
+	 */
+	os_memset(robust_av, 0, sizeof(struct robust_av_data));
+	if (os_strncmp(cmd, "add ", 4) == 0) {
+		robust_av->request_type = SCS_REQ_ADD;
+	} else if (os_strcmp(cmd, "remove") == 0) {
+		robust_av->request_type = SCS_REQ_REMOVE;
+		robust_av->valid_config = false;
+		return wpas_send_mscs_req(wpa_s);
+	} else if (os_strncmp(cmd, "change ", 7) == 0) {
+		robust_av->request_type = SCS_REQ_CHANGE;
+	} else {
+		return -1;
+	}
+
+	pos = os_strstr(cmd, "up_bitmap=");
+	if (!pos)
+		return -1;
+
+	val = hex2byte(pos + 10);
+	if (val < 0)
+		return -1;
+	robust_av->up_bitmap = val;
+
+	pos = os_strstr(cmd, "up_limit=");
+	if (!pos)
+		return -1;
+
+	robust_av->up_limit = atoi(pos + 9);
+
+	pos = os_strstr(cmd, "stream_timeout=");
+	if (!pos)
+		return -1;
+
+	robust_av->stream_timeout = atoi(pos + 15);
+	if (robust_av->stream_timeout == 0)
+		return -1;
+
+	pos = os_strstr(cmd, "frame_classifier=");
+	if (!pos)
+		return -1;
+
+	pos += 17;
+	end = os_strchr(pos, ' ');
+	if (!end)
+		end = pos + os_strlen(pos);
+
+	frame_classifier_len = (end - pos) / 2;
+	if (frame_classifier_len > sizeof(robust_av->frame_classifier) ||
+	    hexstr2bin(pos, robust_av->frame_classifier, frame_classifier_len))
+		return -1;
+
+	robust_av->frame_classifier_len = frame_classifier_len;
+	robust_av->valid_config = true;
+
+	return wpas_send_mscs_req(wpa_s);
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 					 char *buf, size_t *resp_len)
 {
@@ -11142,13 +11290,16 @@
 	} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
 		wpas_dpp_chirp_stop(wpa_s);
 	} else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) {
-		struct wpa_ssid *ssid;
-
-		ssid = wpa_config_get_network(wpa_s->conf, atoi(buf + 13));
-		if (!ssid || wpas_dpp_reconfig(wpa_s, ssid) < 0)
+		if (wpas_dpp_reconfig(wpa_s, buf + 13) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DPP_CA_SET ", 11) == 0) {
+		if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0)
 			reply_len = -1;
 #endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
+	} else if (os_strncmp(buf, "MSCS ", 5) == 0) {
+		if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5))
+			reply_len = -1;
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 793a881..6dcd948 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3212,6 +3212,14 @@
 		  END_ARGS
 	  }
 	},
+	{ "Roam", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_roam,
+	  {
+		  { "addr", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+
 #ifndef CONFIG_NO_CONFIG_BLOBS
 	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
 	  (WPADBusMethodHandler) wpas_dbus_handler_add_blob,
@@ -3613,7 +3621,7 @@
 	},
 	{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
 	  wpas_dbus_getter_bridge_ifname,
-	  NULL,
+	  wpas_dbus_setter_bridge_ifname,
 	  NULL
 	},
 	{ "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index d1f9607..86f8560 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -139,6 +139,7 @@
 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
 	"bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
 	"bssid_blacklist", "bssid_whitelist", "group_mgmt",
+	"ignore_broadcast_ssid",
 #ifdef CONFIG_MESH
 	"mesh_basic_rates",
 #endif /* CONFIG_MESH */
@@ -229,8 +230,6 @@
 		} else if (entry.type == DBUS_TYPE_STRING) {
 			if (should_quote_opt(entry.key)) {
 				size = os_strlen(entry.str_value);
-				if (size == 0)
-					goto error;
 
 				size += 3;
 				value = os_zalloc(size);
@@ -267,8 +266,28 @@
 		} else
 			goto error;
 
-		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
+		ret = wpa_config_set(ssid, entry.key, value, 0);
+		if (ret < 0)
 			goto error;
+		if (ret == 1)
+			goto skip_update;
+
+#ifdef CONFIG_BGSCAN
+		if (os_strcmp(entry.key, "bgscan") == 0) {
+			/*
+			 * Reset the bgscan parameters for the current network
+			 * and continue. There's no need to flush caches for
+			 * bgscan parameter changes.
+			 */
+			if (wpa_s->current_ssid == ssid &&
+			    wpa_s->wpa_state == WPA_COMPLETED)
+				wpa_supplicant_reset_bgscan(wpa_s);
+			os_free(value);
+			value = NULL;
+			wpa_dbus_dict_entry_clear(&entry);
+			continue;
+		}
+#endif /* CONFIG_BGSCAN */
 
 		if (os_strcmp(entry.key, "bssid") != 0 &&
 		    os_strcmp(entry.key, "priority") != 0)
@@ -290,6 +309,7 @@
 		else if (os_strcmp(entry.key, "priority") == 0)
 			wpa_config_update_prio_list(wpa_s->conf);
 
+	skip_update:
 		os_free(value);
 		value = NULL;
 		wpa_dbus_dict_entry_clear(&entry);
@@ -1797,25 +1817,6 @@
 }
 
 
-static void remove_network(void *arg, struct wpa_ssid *ssid)
-{
-	struct wpa_supplicant *wpa_s = arg;
-
-	wpas_notify_network_removed(wpa_s, ssid);
-
-	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
-		wpa_printf(MSG_ERROR,
-			   "%s[dbus]: error occurred when removing network %d",
-			   __func__, ssid->id);
-		return;
-	}
-
-	if (ssid == wpa_s->current_ssid)
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-}
-
-
 /**
  * wpas_dbus_handler_remove_all_networks - Remove all configured networks
  * @message: Pointer to incoming dbus message
@@ -1827,11 +1828,8 @@
 DBusMessage * wpas_dbus_handler_remove_all_networks(
 	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s->sched_scanning)
-		wpa_supplicant_cancel_sched_scan(wpa_s);
-
 	/* NB: could check for failure and return an error */
-	wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
+	wpa_supplicant_remove_all_networks(wpa_s);
 	return NULL;
 }
 
@@ -1956,6 +1954,55 @@
 }
 
 
+/**
+ * wpas_dbus_handler_roam - Initiate a roam to another BSS within the ESS
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "Roam" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+				     struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+	return wpas_dbus_error_unknown_error(message,
+					     "scan processing not included");
+#else /* CONFIG_NO_SCAN_PROCESSING */
+	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	char *addr;
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr,
+				   DBUS_TYPE_INVALID))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	if (hwaddr_aton(addr, bssid))
+		return wpas_dbus_error_invalid_args(
+			message, "Invalid hardware address format");
+
+	wpa_printf(MSG_DEBUG, "dbus: Roam " MACSTR, MAC2STR(bssid));
+
+	if (!ssid)
+		return dbus_message_new_error(
+			message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+			"This interface is not connected");
+
+	bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "dbus: Roam: Target BSS not found");
+		return wpas_dbus_error_invalid_args(
+			message, "Target BSS not found");
+	}
+
+	wpa_s->reassociate = 1;
+	wpa_supplicant_connect(wpa_s, bss, ssid);
+
+	return NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
 #ifndef CONFIG_NO_CONFIG_BLOBS
 
 /**
@@ -3634,6 +3681,43 @@
 }
 
 
+dbus_bool_t wpas_dbus_setter_bridge_ifname(
+	const struct wpa_dbus_property_desc *property_desc,
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *bridge_ifname = NULL;
+	const char *msg;
+	int r;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &bridge_ifname))
+		return FALSE;
+
+	r = wpa_supplicant_update_bridge_ifname(wpa_s, bridge_ifname);
+	if (r != 0) {
+		switch (r) {
+		case -EINVAL:
+			msg = "invalid interface name";
+			break;
+		case -EBUSY:
+			msg = "interface is busy";
+			break;
+		case -EIO:
+			msg = "socket error";
+			break;
+		default:
+			msg = "unknown error";
+			break;
+		}
+		dbus_set_error_const(error, DBUS_ERROR_FAILED, msg);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
 /**
  * wpas_dbus_getter_config_file - Get interface configuration file path
  * @iter: Pointer to incoming dbus message iter
@@ -3941,14 +4025,15 @@
 		return FALSE;
 	}
 
-	if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
+	ret = wpa_config_process_global(wpa_s->conf, buf, -1);
+	if (ret < 0) {
 		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
 			       "Failed to set interface property %s",
 			       property_desc->dbus_property);
 		return FALSE;
+	} else if (ret == 0) {
+		wpa_supplicant_update_config(wpa_s);
 	}
-
-	wpa_supplicant_update_config(wpa_s);
 	return TRUE;
 }
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index afa26ef..c36383f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -117,6 +117,9 @@
 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
 					      struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+				     struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
 					 struct wpa_supplicant *wpa_s);
 
@@ -167,6 +170,7 @@
 DECLARE_ACCESSOR(wpas_dbus_getter_ifname);
 DECLARE_ACCESSOR(wpas_dbus_getter_driver);
 DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname);
+DECLARE_ACCESSOR(wpas_dbus_setter_bridge_ifname);
 DECLARE_ACCESSOR(wpas_dbus_getter_config_file);
 DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
 DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
diff --git a/wpa_supplicant/doc/docbook/.gitignore b/wpa_supplicant/doc/docbook/.gitignore
index 8c3945c..dac35c5 100644
--- a/wpa_supplicant/doc/docbook/.gitignore
+++ b/wpa_supplicant/doc/docbook/.gitignore
@@ -1,5 +1,6 @@
 manpage.links
 manpage.refs
+manpage.log
 *.8
 *.5
 *.html
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 8c2e302..2d0c636 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -12,6 +12,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/ip_addr.h"
+#include "utils/base64.h"
 #include "common/dpp.h"
 #include "common/gas.h"
 #include "common/gas_server.h"
@@ -49,6 +50,9 @@
 #ifdef CONFIG_DPP2
 static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
 						 void *timeout_ctx);
+static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s);
+static int wpas_dpp_process_conf_obj(void *ctx,
+				     struct dpp_authentication *auth);
 #endif /* CONFIG_DPP2 */
 
 static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -89,6 +93,10 @@
 				       500, wpas_dpp_tx_status, 0);
 	}
 
+#ifdef CONFIG_DPP2
+	dpp_controller_new_qr_code(wpa_s->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
 	return bi->id;
 }
 
@@ -832,7 +840,9 @@
 
 #ifdef CONFIG_DPP2
 	if (tcp)
-		return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
+		return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
+				    wpa_s->conf->dpp_name, DPP_NETROLE_STA,
+				    wpa_s, wpa_s, wpas_dpp_process_conf_obj);
 #endif /* CONFIG_DPP2 */
 
 	wpa_s->dpp_auth = auth;
@@ -1185,6 +1195,15 @@
 		ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
 	}
 
+	if (conf->pp_key) {
+		ssid->dpp_pp_key = os_malloc(wpabuf_len(conf->pp_key));
+		if (!ssid->dpp_pp_key)
+			goto fail;
+		os_memcpy(ssid->dpp_pp_key, wpabuf_head(conf->pp_key),
+			  wpabuf_len(conf->pp_key));
+		ssid->dpp_pp_key_len = wpabuf_len(conf->pp_key);
+	}
+
 	if (auth->net_access_key) {
 		ssid->dpp_netaccesskey =
 			os_malloc(wpabuf_len(auth->net_access_key));
@@ -1220,6 +1239,102 @@
 		}
 	}
 
+#if defined(CONFIG_DPP2) && defined(IEEE8021X_EAPOL)
+	if (conf->akm == DPP_AKM_DOT1X) {
+		int i;
+		char name[100], blobname[128];
+		struct wpa_config_blob *blob;
+
+		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X |
+			WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			WPA_KEY_MGMT_IEEE8021X_SHA256;
+		ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+
+		if (conf->cacert) {
+			/* caCert is DER-encoded X.509v3 certificate for the
+			 * server certificate if that is different from the
+			 * trust root included in certBag. */
+			/* TODO: ssid->eap.cert.ca_cert */
+		}
+
+		if (conf->certs) {
+			for (i = 0; ; i++) {
+				os_snprintf(name, sizeof(name), "dpp-certs-%d",
+					    i);
+				if (!wpa_config_get_blob(wpa_s->conf, name))
+					break;
+			}
+
+			blob = os_zalloc(sizeof(*blob));
+			if (!blob)
+				goto fail;
+			blob->len = wpabuf_len(conf->certs);
+			blob->name = os_strdup(name);
+			blob->data = os_malloc(blob->len);
+			if (!blob->name || !blob->data) {
+				wpa_config_free_blob(blob);
+				goto fail;
+			}
+			os_memcpy(blob->data, wpabuf_head(conf->certs),
+				  blob->len);
+			os_snprintf(blobname, sizeof(blobname), "blob://%s",
+				    name);
+			wpa_config_set_blob(wpa_s->conf, blob);
+			wpa_printf(MSG_DEBUG, "DPP: Added certificate blob %s",
+				   name);
+			ssid->eap.cert.client_cert = os_strdup(blobname);
+			if (!ssid->eap.cert.client_cert)
+				goto fail;
+
+			/* TODO: ssid->eap.identity from own certificate */
+			if (wpa_config_set(ssid, "identity", "\"dpp-ent\"",
+					   0) < 0)
+				goto fail;
+		}
+
+		if (auth->priv_key) {
+			for (i = 0; ; i++) {
+				os_snprintf(name, sizeof(name), "dpp-key-%d",
+					    i);
+				if (!wpa_config_get_blob(wpa_s->conf, name))
+					break;
+			}
+
+			blob = os_zalloc(sizeof(*blob));
+			if (!blob)
+				goto fail;
+			blob->len = wpabuf_len(auth->priv_key);
+			blob->name = os_strdup(name);
+			blob->data = os_malloc(blob->len);
+			if (!blob->name || !blob->data) {
+				wpa_config_free_blob(blob);
+				goto fail;
+			}
+			os_memcpy(blob->data, wpabuf_head(auth->priv_key),
+				  blob->len);
+			os_snprintf(blobname, sizeof(blobname), "blob://%s",
+				    name);
+			wpa_config_set_blob(wpa_s->conf, blob);
+			wpa_printf(MSG_DEBUG, "DPP: Added private key blob %s",
+				   name);
+			ssid->eap.cert.private_key = os_strdup(blobname);
+			if (!ssid->eap.cert.private_key)
+				goto fail;
+		}
+
+		if (conf->server_name) {
+			ssid->eap.cert.domain_suffix_match =
+				os_strdup(conf->server_name);
+			if (!ssid->eap.cert.domain_suffix_match)
+				goto fail;
+		}
+
+		/* TODO: Use entCreds::eapMethods */
+		if (wpa_config_set(ssid, "eap", "TLS", 0) < 0)
+			goto fail;
+	}
+#endif /* CONFIG_DPP2 && IEEE8021X_EAPOL */
+
 	os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
 	wpa_s->dpp_last_ssid_len = conf->ssid_len;
 
@@ -1329,6 +1444,20 @@
 			os_free(hex);
 		}
 	}
+	if (conf->pp_key) {
+		char *hex;
+		size_t hexlen;
+
+		hexlen = 2 * wpabuf_len(conf->pp_key) + 1;
+		hex = os_malloc(hexlen);
+		if (hex) {
+			wpa_snprintf_hex(hex, hexlen,
+					 wpabuf_head(conf->pp_key),
+					 wpabuf_len(conf->pp_key));
+			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PP_KEY "%s", hex);
+			os_free(hex);
+		}
+	}
 	if (auth->net_access_key) {
 		char *hex;
 		size_t hexlen;
@@ -1351,6 +1480,32 @@
 		}
 	}
 
+#ifdef CONFIG_DPP2
+	if (conf->certbag) {
+		char *b64;
+
+		b64 = base64_encode_no_lf(wpabuf_head(conf->certbag),
+					  wpabuf_len(conf->certbag), NULL);
+		if (b64)
+			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CERTBAG "%s", b64);
+		os_free(b64);
+	}
+
+	if (conf->cacert) {
+		char *b64;
+
+		b64 = base64_encode_no_lf(wpabuf_head(conf->cacert),
+					  wpabuf_len(conf->cacert), NULL);
+		if (b64)
+			wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CACERT "%s", b64);
+		os_free(b64);
+	}
+
+	if (conf->server_name)
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_SERVER_NAME "%s",
+			conf->server_name);
+#endif /* CONFIG_DPP2 */
+
 	return wpas_dpp_process_config(wpa_s, auth, conf);
 }
 
@@ -1366,6 +1521,7 @@
 
 	wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+	wpa_s->dpp_conf_backup_received = true;
 
 	while (key) {
 		res = dpp_configurator_from_backup(wpa_s->dpp, key);
@@ -1381,6 +1537,31 @@
 }
 
 
+#ifdef CONFIG_DPP2
+static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+	if (!auth || !auth->csrattrs)
+		return;
+
+	wpa_printf(MSG_DEBUG, "DPP: Build CSR");
+	wpabuf_free(auth->csr);
+	/* TODO: Additional information needed for CSR based on csrAttrs */
+	auth->csr = dpp_build_csr(auth, wpa_s->conf->dpp_name ?
+				  wpa_s->conf->dpp_name : "Test");
+	if (!auth->csr) {
+		dpp_auth_deinit(wpa_s->dpp_auth);
+		wpa_s->dpp_auth = NULL;
+		return;
+	}
+
+	wpas_dpp_start_gas_client(wpa_s);
+}
+#endif /* CONFIG_DPP2 */
+
+
 static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
 				 enum gas_query_result result,
 				 const struct wpabuf *adv_proto,
@@ -1425,11 +1606,20 @@
 		goto fail;
 	}
 
-	if (dpp_conf_resp_rx(auth, resp) < 0) {
+	res = dpp_conf_resp_rx(auth, resp);
+#ifdef CONFIG_DPP2
+	if (res == -2) {
+		wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+		eloop_register_timeout(0, 0, wpas_dpp_build_csr, wpa_s, NULL);
+		return;
+	}
+#endif /* CONFIG_DPP2 */
+	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
 		goto fail;
 	}
 
+	wpa_s->dpp_conf_backup_received = false;
 	for (i = 0; i < auth->num_conf_obj; i++) {
 		res = wpas_dpp_handle_config_obj(wpa_s, auth,
 						 &auth->conf_obj[i]);
@@ -1475,6 +1665,9 @@
 		wpabuf_free(msg);
 
 		/* This exchange will be terminated in the TX status handler */
+		if (wpa_s->conf->dpp_config_processing < 2 ||
+		    wpa_s->dpp_conf_backup_received)
+			auth->remove_on_tx_status = 1;
 		return;
 	}
 fail2:
@@ -1828,6 +2021,8 @@
 	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
 		    r_bootstrap, r_bootstrap_len);
 	peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
+	dpp_notify_chirp_received(wpa_s, peer_bi ? (int) peer_bi->id : -1, src,
+				  freq, r_bootstrap);
 	if (!peer_bi) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: No matching bootstrapping information found");
@@ -1879,11 +2074,12 @@
 				  const u8 *hdr, const u8 *buf, size_t len,
 				  unsigned int freq)
 {
-	const u8 *csign_hash;
-	u16 csign_hash_len;
+	const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+	u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
 	struct dpp_configurator *conf;
 	struct dpp_authentication *auth;
 	unsigned int wait_time, max_wait_time;
+	u16 group;
 
 	if (!wpa_s->dpp)
 		return;
@@ -1913,7 +2109,21 @@
 		return;
 	}
 
-	auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq);
+	fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+			       &fcgroup_len);
+	if (!fcgroup || fcgroup_len != 2) {
+		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+			"Missing or invalid required Finite Cyclic Group attribute");
+		return;
+	}
+	group = WPA_GET_LE16(fcgroup);
+	wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+	a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+	e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+	auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq, group,
+				 a_nonce, a_nonce_len, e_id, e_id_len);
 	if (!auth)
 		return;
 	wpas_dpp_set_testing_options(wpa_s, auth);
@@ -1963,17 +2173,29 @@
 	wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
 		   MACSTR, MAC2STR(src));
 
-	if (!wpa_s->dpp || wpa_s->dpp_auth ||
-	    !wpa_s->dpp_reconfig_announcement || !wpa_s->dpp_reconfig_ssid)
+	if (!wpa_s->dpp)
 		return;
+	if (wpa_s->dpp_auth) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Not ready for reconfiguration - pending authentication exchange in progress");
+		return;
+	}
+	if (!wpa_s->dpp_reconfig_ssid) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Not ready for reconfiguration - not requested");
+		return;
+	}
 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
 		if (ssid == wpa_s->dpp_reconfig_ssid &&
 		    ssid->id == wpa_s->dpp_reconfig_ssid_id)
 			break;
 	}
 	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
-	    !ssid->dpp_csign)
+	    !ssid->dpp_csign) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Not ready for reconfiguration - no matching network profile with Connector found");
 		return;
+	}
 
 	auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
 					ssid->dpp_netaccesskey,
@@ -2667,8 +2889,8 @@
 
 
 static struct wpabuf *
-wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
-			 size_t query_len)
+wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
+			 const u8 *query, size_t query_len, u16 *comeback_delay)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct dpp_authentication *auth = wpa_s->dpp_auth;
@@ -2699,6 +2921,16 @@
 	wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
 		MAC2STR(sa));
 	resp = dpp_conf_req_rx(auth, query, query_len);
+
+#ifdef CONFIG_DPP2
+	if (!resp && auth->waiting_cert) {
+		wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+		auth->cert_resp_ctx = resp_ctx;
+		*comeback_delay = 500;
+		return NULL;
+	}
+#endif /* CONFIG_DPP2 */
+
 	if (!resp) {
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
 		wpas_notify_dpp_configuration_failure(wpa_s);
@@ -2726,6 +2958,14 @@
 		return;
 	}
 
+#ifdef CONFIG_DPP2
+	if (auth->waiting_csr && ok) {
+		wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+		wpabuf_free(resp);
+		return;
+	}
+#endif /* CONFIG_DPP2 */
+
 	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
 		   ok);
 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
@@ -3087,10 +3327,8 @@
 		return -1;
 
 	os_memset(&config, 0, sizeof(config));
-	config.msg_ctx = wpa_s;
 	config.cb_ctx = wpa_s;
 #ifdef CONFIG_DPP2
-	config.process_conf_obj = wpas_dpp_process_conf_obj;
 	config.remove_bi = wpas_dpp_remove_bi;
 #endif /* CONFIG_DPP2 */
 	wpa_s->dpp = dpp_global_init(&config);
@@ -3111,7 +3349,6 @@
 #endif /* CONFIG_TESTING_OPTIONS */
 	if (!wpa_s->dpp)
 		return;
-	dpp_global_clear(wpa_s->dpp);
 	eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
@@ -3123,9 +3360,12 @@
 	eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
 			     wpa_s, NULL);
+	eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL);
 	dpp_pfs_free(wpa_s->dpp_pfs);
 	wpa_s->dpp_pfs = NULL;
 	wpas_dpp_chirp_stop(wpa_s);
+	dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+	wpa_s->dpp_reconfig_id = NULL;
 #endif /* CONFIG_DPP2 */
 	offchannel_send_action_done(wpa_s);
 	wpas_dpp_listen_stop(wpa_s);
@@ -3134,6 +3374,7 @@
 	os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
 	os_free(wpa_s->dpp_configurator_params);
 	wpa_s->dpp_configurator_params = NULL;
+	dpp_global_clear(wpa_s->dpp);
 }
 
 
@@ -3146,6 +3387,10 @@
 
 	os_memset(&config, 0, sizeof(config));
 	config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+	config.netrole = DPP_NETROLE_STA;
+	config.msg_ctx = wpa_s;
+	config.cb_ctx = wpa_s;
+	config.process_conf_obj = wpas_dpp_process_conf_obj;
 	if (cmd) {
 		pos = os_strstr(cmd, " tcp_port=");
 		if (pos) {
@@ -3166,6 +3411,8 @@
 			else
 				return -1;
 		}
+
+		config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
 	}
 	config.configurator_params = wpa_s->dpp_configurator_params;
 	return dpp_controller_start(wpa_s->dpp, &config);
@@ -3208,13 +3455,26 @@
 
 static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
 {
-	struct wpabuf *msg;
+	struct wpabuf *msg, *announce = NULL;
 	int type;
 
 	msg = wpa_s->dpp_presence_announcement;
 	type = DPP_PA_PRESENCE_ANNOUNCEMENT;
 	if (!msg) {
-		msg = wpa_s->dpp_reconfig_announcement;
+		struct wpa_ssid *ssid = wpa_s->dpp_reconfig_ssid;
+
+		if (ssid && wpa_s->dpp_reconfig_id &&
+		    wpa_config_get_network(wpa_s->conf,
+					   wpa_s->dpp_reconfig_ssid_id) ==
+		    ssid) {
+			announce = dpp_build_reconfig_announcement(
+				ssid->dpp_csign,
+				ssid->dpp_csign_len,
+				ssid->dpp_netaccesskey,
+				ssid->dpp_netaccesskey_len,
+				wpa_s->dpp_reconfig_id);
+			msg = announce;
+		}
 		if (!msg)
 			return;
 		type = DPP_PA_RECONFIG_ANNOUNCEMENT;
@@ -3228,6 +3488,8 @@
 		    wpabuf_head(msg), wpabuf_len(msg),
 		    2000, wpas_dpp_chirp_tx_status, 0) < 0)
 		wpas_dpp_chirp_stop(wpa_s);
+
+	wpabuf_free(announce);
 }
 
 
@@ -3239,8 +3501,9 @@
 	struct hostapd_hw_modes *mode;
 	int c;
 	struct wpa_bss *bss;
+	bool chan6;
 
-	if (!bi && !wpa_s->dpp_reconfig_announcement)
+	if (!bi && !wpa_s->dpp_reconfig_ssid)
 		return;
 
 	wpa_s->dpp_chirp_scan_done = 1;
@@ -3256,7 +3519,22 @@
 	}
 
 	/* Preferred chirping channels */
-	int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+			HOSTAPD_MODE_IEEE80211G, 0);
+	chan6 = mode == NULL;
+	if (mode) {
+		for (c = 0; c < mode->num_channels; c++) {
+			struct hostapd_channel_data *chan = &mode->channels[c];
+
+			if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+			    chan->freq != 2437)
+				continue;
+			chan6 = true;
+			break;
+		}
+	}
+	if (chan6)
+		int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
 
 	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
 			HOSTAPD_MODE_IEEE80211A, 0);
@@ -3428,15 +3706,13 @@
 void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->dpp_presence_announcement ||
-	    wpa_s->dpp_reconfig_announcement) {
+	    wpa_s->dpp_reconfig_ssid) {
 		offchannel_send_action_done(wpa_s);
 		wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
 	}
 	wpa_s->dpp_chirp_bi = NULL;
 	wpabuf_free(wpa_s->dpp_presence_announcement);
 	wpa_s->dpp_presence_announcement = NULL;
-	wpabuf_free(wpa_s->dpp_reconfig_announcement);
-	wpa_s->dpp_reconfig_announcement = NULL;
 	if (wpa_s->dpp_chirp_listen)
 		wpas_dpp_listen_stop(wpa_s);
 	wpa_s->dpp_chirp_listen = 0;
@@ -3452,23 +3728,55 @@
 }
 
 
-int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
 {
-	if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
-	    !ssid->dpp_csign)
-		return -1;
+	struct wpa_ssid *ssid;
+	int iter = 1;
+	const char *pos;
 
+	ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+	if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+	    !ssid->dpp_csign) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Not a valid network profile for reconfiguration");
+		return -1;
+	}
+
+	pos = os_strstr(cmd, " iter=");
+	if (pos) {
+		iter = atoi(pos + 6);
+		if (iter <= 0)
+			return -1;
+	}
+
+	if (wpa_s->dpp_auth) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Not ready to start reconfiguration - pending authentication exchange in progress");
+		return -1;
+	}
+
+	dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+	wpa_s->dpp_reconfig_id = dpp_gen_reconfig_id(ssid->dpp_csign,
+						     ssid->dpp_csign_len,
+						     ssid->dpp_pp_key,
+						     ssid->dpp_pp_key_len);
+	if (!wpa_s->dpp_reconfig_id) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Failed to generate E-id for reconfiguration");
+		return -1;
+	}
+	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+		wpa_printf(MSG_DEBUG, "DPP: Disconnect for reconfiguration");
+		wpa_s->own_disconnect_req = 1;
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	}
 	wpas_dpp_chirp_stop(wpa_s);
 	wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
 	wpa_s->dpp_qr_mutual = 0;
-	wpa_s->dpp_reconfig_announcement =
-		dpp_build_reconfig_announcement(ssid->dpp_csign,
-						ssid->dpp_csign_len);
-	if (!wpa_s->dpp_reconfig_announcement)
-		return -1;
 	wpa_s->dpp_reconfig_ssid = ssid;
 	wpa_s->dpp_reconfig_ssid_id = ssid->id;
-	wpa_s->dpp_chirp_iter = 1;
+	wpa_s->dpp_chirp_iter = iter;
 	wpa_s->dpp_chirp_round = 0;
 	wpa_s->dpp_chirp_scan_done = 0;
 	wpa_s->dpp_chirp_listen = 0;
@@ -3476,4 +3784,111 @@
 	return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
 }
 
+
+static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s,
+				    struct dpp_authentication *auth, bool tcp)
+{
+	struct wpabuf *resp;
+
+	resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len,
+				   auth->e_netrole, true);
+	if (!resp)
+		return -1;
+
+	if (tcp) {
+		auth->conf_resp_tcp = resp;
+		return 0;
+	}
+
+	if (gas_server_set_resp(wpa_s->gas_server, auth->cert_resp_ctx,
+				resp) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: Could not find pending GAS response");
+		wpabuf_free(resp);
+		return -1;
+	}
+	auth->conf_resp = resp;
+	return 0;
+}
+
+
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+	int peer = -1;
+	const char *pos, *value;
+	struct dpp_authentication *auth = wpa_s->dpp_auth;
+	u8 *bin;
+	size_t bin_len;
+	struct wpabuf *buf;
+	bool tcp = false;
+
+	pos = os_strstr(cmd, " peer=");
+	if (pos) {
+		peer = atoi(pos + 6);
+		if (!auth || !auth->waiting_cert ||
+		    (auth->peer_bi &&
+		     (unsigned int) peer != auth->peer_bi->id)) {
+			auth = dpp_controller_get_auth(wpa_s->dpp, peer);
+			tcp = true;
+		}
+	}
+
+	if (!auth || !auth->waiting_cert) {
+		wpa_printf(MSG_DEBUG,
+			   "DPP: No authentication exchange waiting for certificate information");
+		return -1;
+	}
+
+	if (peer >= 0 &&
+	    (!auth->peer_bi ||
+	     (unsigned int) peer != auth->peer_bi->id) &&
+	    (!auth->tmp_peer_bi ||
+	     (unsigned int) peer != auth->tmp_peer_bi->id)) {
+		wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
+		return -1;
+	}
+
+	pos = os_strstr(cmd, " value=");
+	if (!pos)
+		return -1;
+	value = pos + 7;
+
+	pos = os_strstr(cmd, " name=");
+	if (!pos)
+		return -1;
+	pos += 6;
+
+	if (os_strncmp(pos, "status ", 7) == 0) {
+		auth->force_conf_resp_status = atoi(value);
+		return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+	}
+
+	if (os_strncmp(pos, "trustedEapServerName ", 21) == 0) {
+		os_free(auth->trusted_eap_server_name);
+		auth->trusted_eap_server_name = os_strdup(value);
+		return auth->trusted_eap_server_name ? 0 : -1;
+	}
+
+	bin = base64_decode(value, os_strlen(value), &bin_len);
+	if (!bin)
+		return -1;
+	buf = wpabuf_alloc_copy(bin, bin_len);
+	os_free(bin);
+
+	if (os_strncmp(pos, "caCert ", 7) == 0) {
+		wpabuf_free(auth->cacert);
+		auth->cacert = buf;
+		return 0;
+	}
+
+	if (os_strncmp(pos, "certBag ", 8) == 0) {
+		wpabuf_free(auth->certbag);
+		auth->certbag = buf;
+		return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+	}
+
+	wpabuf_free(buf);
+	return -1;
+}
+
 #endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 2dc86e0..b0d5fcf 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -39,6 +39,7 @@
 				      enum dpp_status_error result);
 int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
 void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
-int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd);
 
 #endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 54ae03b..ba8cc55 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1069,14 +1069,14 @@
 	return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val);
 }
 
-static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s,
-					      unsigned int num_bssid,
-					      const u8 *bssids)
+static inline int wpa_drv_set_bssid_tmp_disallow(struct wpa_supplicant *wpa_s,
+						 unsigned int num_bssid,
+						 const u8 *bssids)
 {
-	if (!wpa_s->driver->set_bssid_blacklist)
+	if (!wpa_s->driver->set_bssid_tmp_disallow)
 		return -1;
-	return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid,
-						  bssids);
+	return wpa_s->driver->set_bssid_tmp_disallow(wpa_s->drv_priv, num_bssid,
+						     bssids);
 }
 
 static inline int wpa_drv_update_connect_params(
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 6b33ee3..fd4511d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -356,6 +356,9 @@
 	int pmksa_set = -1;
 	size_t i;
 
+	/* Start with assumption of no PMKSA cache entry match */
+	pmksa_cache_clear_current(wpa_s->wpa);
+
 	if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
 	    ie.pmkid == NULL)
 		return;
@@ -1080,32 +1083,407 @@
 }
 
 
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+			    const u8 *match_ssid, size_t match_ssid_len,
+			    struct wpa_bss *bss, int blacklist_count,
+			    bool debug_print);
+
+
+#ifdef CONFIG_SAE_PK
+static bool sae_pk_acceptable_bss_with_pk(struct wpa_supplicant *wpa_s,
+					  struct wpa_bss *orig_bss,
+					  struct wpa_ssid *ssid,
+					  const u8 *match_ssid,
+					  size_t match_ssid_len)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		int count;
+		const u8 *ie;
+		u8 rsnxe_capa = 0;
+
+		if (bss == orig_bss)
+			continue;
+		ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+		if (ie && ie[1] >= 1)
+			rsnxe_capa = ie[2];
+		if (!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)))
+			continue;
+
+		/* TODO: Could be more thorough in checking what kind of
+		 * signal strength or throughput estimate would be acceptable
+		 * compared to the originally selected BSS. */
+		if (bss->est_throughput < 2000)
+			return false;
+
+		count = wpa_blacklist_is_blacklisted(wpa_s, bss->bssid);
+		if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+				    bss, count, 0))
+			return true;
+	}
+
+	return false;
+}
+#endif /* CONFIG_SAE_PK */
+
+
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+			    const u8 *match_ssid, size_t match_ssid_len,
+			    struct wpa_bss *bss, int blacklist_count,
+			    bool debug_print)
+{
+	int res;
+	bool wpa, check_ssid, osen, rsn_osen = false;
+	struct wpa_ie_data data;
+#ifdef CONFIG_MBO
+	const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
+#ifdef CONFIG_SAE
+	u8 rsnxe_capa = 0;
+#endif /* CONFIG_SAE */
+	const u8 *ie;
+
+	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	wpa = ie && ie[1];
+	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	wpa |= ie && ie[1];
+	if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+	    (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+		rsn_osen = true;
+	ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+	osen = ie != NULL;
+
+#ifdef CONFIG_SAE
+	ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+	if (ie && ie[1] >= 1)
+		rsnxe_capa = ie[2];
+#endif /* CONFIG_SAE */
+
+	check_ssid = wpa || ssid->ssid_len > 0;
+
+	if (wpas_network_disabled(wpa_s, ssid)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
+		return false;
+	}
+
+	res = wpas_temp_disabled(wpa_s, ssid);
+	if (res > 0) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - disabled temporarily for %d second(s)",
+				res);
+		return false;
+	}
+
+#ifdef CONFIG_WPS
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && blacklist_count) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - blacklisted (WPS)");
+		return false;
+	}
+
+	if (wpa && ssid->ssid_len == 0 &&
+	    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+		check_ssid = false;
+
+	if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		/* Only allow wildcard SSID match if an AP advertises active
+		 * WPS operation that matches our mode. */
+		check_ssid = ssid->ssid_len > 0 ||
+			!wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss);
+	}
+#endif /* CONFIG_WPS */
+
+	if (ssid->bssid_set && ssid->ssid_len == 0 &&
+	    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+		check_ssid = false;
+
+	if (check_ssid &&
+	    (match_ssid_len != ssid->ssid_len ||
+	     os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID mismatch");
+		return false;
+	}
+
+	if (ssid->bssid_set &&
+	    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID mismatch");
+		return false;
+	}
+
+	/* check blacklist */
+	if (ssid->num_bssid_blacklist &&
+	    addr_in_list(bss->bssid, ssid->bssid_blacklist,
+			 ssid->num_bssid_blacklist)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - BSSID blacklisted");
+		return false;
+	}
+
+	/* if there is a whitelist, only accept those APs */
+	if (ssid->num_bssid_whitelist &&
+	    !addr_in_list(bss->bssid, ssid->bssid_whitelist,
+			  ssid->num_bssid_whitelist)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - BSSID not in whitelist");
+		return false;
+	}
+
+	if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss, debug_print))
+		return false;
+
+	if (!osen && !wpa &&
+	    !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+	    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+	    !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+	    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - non-WPA network not allowed");
+		return false;
+	}
+
+#ifdef CONFIG_WEP
+	if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - ignore WPA/WPA2 AP for WEP network block");
+		return false;
+	}
+#endif /* CONFIG_WEP */
+
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && !rsn_osen) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - non-OSEN network not allowed");
+		return false;
+	}
+
+	if (!wpa_supplicant_match_privacy(bss, ssid)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - privacy mismatch");
+		return false;
+	}
+
+	if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
+	    !bss_is_pbss(bss)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - not ESS, PBSS, or MBSS");
+		return false;
+	}
+
+	if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - PBSS mismatch (ssid %d bss %d)",
+				ssid->pbss, bss_is_pbss(bss));
+		return false;
+	}
+
+	if (!freq_allowed(ssid->freq_list, bss->freq)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - frequency not allowed");
+		return false;
+	}
+
+#ifdef CONFIG_MESH
+	if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
+	    ssid->frequency != bss->freq) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - frequency not allowed (mesh)");
+		return false;
+	}
+#endif /* CONFIG_MESH */
+
+	if (!rate_match(wpa_s, ssid, bss, debug_print)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - rate sets do not match");
+		return false;
+	}
+
+#ifdef CONFIG_SAE
+	if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+	    wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) &&
+	    !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - SAE H2E required, but not supported by the AP");
+		return false;
+	}
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_SAE_PK
+	if (ssid->sae_pk == SAE_PK_MODE_ONLY &&
+	    !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK))) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - SAE-PK required, but not supported by the AP");
+		return false;
+	}
+#endif /* CONFIG_SAE_PK */
+
+#ifndef CONFIG_IBSS_RSN
+	if (ssid->mode == WPAS_MODE_IBSS &&
+	    !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - IBSS RSN not supported in the build");
+		return false;
+	}
+#endif /* !CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_P2P
+	if (ssid->p2p_group &&
+	    !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+	    !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no P2P IE seen");
+		return false;
+	}
+
+	if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+		struct wpabuf *p2p_ie;
+		u8 dev_addr[ETH_ALEN];
+
+		ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+		if (!ie) {
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - no P2P element");
+			return false;
+		}
+		p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+		if (!p2p_ie) {
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - could not fetch P2P element");
+			return false;
+		}
+
+		if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0 ||
+		    os_memcmp(dev_addr, ssid->go_p2p_dev_addr, ETH_ALEN) != 0) {
+			if (debug_print)
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"   skip - no matching GO P2P Device Address in P2P element");
+			wpabuf_free(p2p_ie);
+			return false;
+		}
+		wpabuf_free(p2p_ie);
+	}
+
+	/*
+	 * TODO: skip the AP if its P2P IE has Group Formation bit set in the
+	 * P2P Group Capability Bitmap and we are not in Group Formation with
+	 * that device.
+	 */
+#endif /* CONFIG_P2P */
+
+	if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time)) {
+		struct os_reltime diff;
+
+		os_reltime_sub(&wpa_s->scan_min_time, &bss->last_update, &diff);
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - scan result not recent enough (%u.%06u seconds too old)",
+				(unsigned int) diff.sec,
+				(unsigned int) diff.usec);
+		return false;
+	}
+#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->ignore_assoc_disallow)
+		goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
+	assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+	if (assoc_disallow && assoc_disallow[1] >= 1) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - MBO association disallowed (reason %u)",
+				assoc_disallow[2]);
+		return false;
+	}
+
+	if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - AP temporarily disallowed");
+		return false;
+	}
+#ifdef CONFIG_TESTING_OPTIONS
+skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+	    !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+	    (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+	     !ssid->dpp_csign)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - no PMKSA entry for DPP");
+		return false;
+	}
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_SAE_PK
+	if (ssid->sae_pk == SAE_PK_MODE_AUTOMATIC &&
+	    wpa_key_mgmt_sae(ssid->key_mgmt) &&
+	    ((ssid->sae_password &&
+	      sae_pk_valid_password(ssid->sae_password)) ||
+	     (!ssid->sae_password && ssid->passphrase &&
+	      sae_pk_valid_password(ssid->passphrase))) &&
+	    !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+	    sae_pk_acceptable_bss_with_pk(wpa_s, bss, ssid, match_ssid,
+					  match_ssid_len)) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - another acceptable BSS with SAE-PK in the same ESS");
+		return false;
+	}
+#endif /* CONFIG_SAE_PK */
+
+	if (bss->ssid_len == 0) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - no SSID known for the BSS");
+		return false;
+	}
+
+	/* Matching configuration found */
+	return true;
+}
+
+
 struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 				     int i, struct wpa_bss *bss,
 				     struct wpa_ssid *group,
 				     int only_first_ssid, int debug_print)
 {
 	u8 wpa_ie_len, rsn_ie_len;
-	int wpa;
-	struct wpa_blacklist *e;
 	const u8 *ie;
 	struct wpa_ssid *ssid;
-	int osen, rsn_osen = 0;
-#ifdef CONFIG_MBO
-	const u8 *assoc_disallow;
-#endif /* CONFIG_MBO */
+	int osen;
 	const u8 *match_ssid;
 	size_t match_ssid_len;
-	struct wpa_ie_data data;
+	int blacklist_count;
 
 	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
 	wpa_ie_len = ie ? ie[1] : 0;
 
 	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
 	rsn_ie_len = ie ? ie[1] : 0;
-	if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
-	    (data.key_mgmt & WPA_KEY_MGMT_OSEN))
-		rsn_osen = 1;
 
 	ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
 	osen = ie != NULL;
@@ -1125,8 +1503,8 @@
 			osen ? " osen=1" : "");
 	}
 
-	e = wpa_blacklist_get(wpa_s, bss->bssid);
-	if (e) {
+	blacklist_count = wpa_blacklist_is_blacklisted(wpa_s, bss->bssid);
+	if (blacklist_count) {
 		int limit = 1;
 		if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
 			/*
@@ -1139,11 +1517,11 @@
 			 */
 			limit = 0;
 		}
-		if (e->count > limit) {
+		if (blacklist_count > limit) {
 			if (debug_print) {
 				wpa_dbg(wpa_s, MSG_DEBUG,
 					"   skip - blacklisted (count=%d limit=%d)",
-					e->count, limit);
+					blacklist_count, limit);
 			}
 			return NULL;
 		}
@@ -1177,299 +1555,10 @@
 		return NULL;
 	}
 
-	wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
-
 	for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
-		int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
-		int res;
-
-		if (wpas_network_disabled(wpa_s, ssid)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
-			continue;
-		}
-
-		res = wpas_temp_disabled(wpa_s, ssid);
-		if (res > 0) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - disabled temporarily for %d second(s)",
-					res);
-			continue;
-		}
-
-#ifdef CONFIG_WPS
-		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - blacklisted (WPS)");
-			continue;
-		}
-
-		if (wpa && ssid->ssid_len == 0 &&
-		    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
-			check_ssid = 0;
-
-		if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
-			/* Only allow wildcard SSID match if an AP
-			 * advertises active WPS operation that matches
-			 * with our mode. */
-			check_ssid = 1;
-			if (ssid->ssid_len == 0 &&
-			    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
-				check_ssid = 0;
-		}
-#endif /* CONFIG_WPS */
-
-		if (ssid->bssid_set && ssid->ssid_len == 0 &&
-		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
-			check_ssid = 0;
-
-		if (check_ssid &&
-		    (match_ssid_len != ssid->ssid_len ||
-		     os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - SSID mismatch");
-			continue;
-		}
-
-		if (ssid->bssid_set &&
-		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - BSSID mismatch");
-			continue;
-		}
-
-		/* check blacklist */
-		if (ssid->num_bssid_blacklist &&
-		    addr_in_list(bss->bssid, ssid->bssid_blacklist,
-				 ssid->num_bssid_blacklist)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - BSSID blacklisted");
-			continue;
-		}
-
-		/* if there is a whitelist, only accept those APs */
-		if (ssid->num_bssid_whitelist &&
-		    !addr_in_list(bss->bssid, ssid->bssid_whitelist,
-				  ssid->num_bssid_whitelist)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - BSSID not in whitelist");
-			continue;
-		}
-
-		if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
-						   debug_print))
-			continue;
-
-		if (!osen && !wpa &&
-		    !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
-		    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
-		    !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
-		    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - non-WPA network not allowed");
-			continue;
-		}
-
-#ifdef CONFIG_WEP
-		if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
-		    has_wep_key(ssid)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - ignore WPA/WPA2 AP for WEP network block");
-			continue;
-		}
-#endif /* CONFIG_WEP */
-
-		if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
-		    !rsn_osen) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - non-OSEN network not allowed");
-			continue;
-		}
-
-		if (!wpa_supplicant_match_privacy(bss, ssid)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - privacy mismatch");
-			continue;
-		}
-
-		if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
-		    !bss_is_pbss(bss)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - not ESS, PBSS, or MBSS");
-			continue;
-		}
-
-		if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - PBSS mismatch (ssid %d bss %d)",
-					ssid->pbss, bss_is_pbss(bss));
-			continue;
-		}
-
-		if (!freq_allowed(ssid->freq_list, bss->freq)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - frequency not allowed");
-			continue;
-		}
-
-#ifdef CONFIG_MESH
-		if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
-		    ssid->frequency != bss->freq) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - frequency not allowed (mesh)");
-			continue;
-		}
-#endif /* CONFIG_MESH */
-
-		if (!rate_match(wpa_s, ssid, bss, debug_print)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - rate sets do not match");
-			continue;
-		}
-
-#ifdef CONFIG_SAE
-		if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
-		    wpa_s->conf->sae_pwe != 3 &&
-		    wpa_key_mgmt_sae(ssid->key_mgmt) &&
-		    (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
-		     ie[1] < 1 ||
-		     !(ie[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)))) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - SAE H2E required, but not supported by the AP");
-			continue;
-		}
-#endif /* CONFIG_SAE */
-
-#ifndef CONFIG_IBSS_RSN
-		if (ssid->mode == WPAS_MODE_IBSS &&
-		    !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
-					WPA_KEY_MGMT_WPA_NONE))) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - IBSS RSN not supported in the build");
-			continue;
-		}
-#endif /* !CONFIG_IBSS_RSN */
-
-#ifdef CONFIG_P2P
-		if (ssid->p2p_group &&
-		    !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
-		    !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - no P2P IE seen");
-			continue;
-		}
-
-		if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
-			struct wpabuf *p2p_ie;
-			u8 dev_addr[ETH_ALEN];
-
-			ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
-			if (ie == NULL) {
-				if (debug_print)
-					wpa_dbg(wpa_s, MSG_DEBUG,
-						"   skip - no P2P element");
-				continue;
-			}
-			p2p_ie = wpa_bss_get_vendor_ie_multi(
-				bss, P2P_IE_VENDOR_TYPE);
-			if (p2p_ie == NULL) {
-				if (debug_print)
-					wpa_dbg(wpa_s, MSG_DEBUG,
-						"   skip - could not fetch P2P element");
-				continue;
-			}
-
-			if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
-			    || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
-					 ETH_ALEN) != 0) {
-				if (debug_print)
-					wpa_dbg(wpa_s, MSG_DEBUG,
-						"   skip - no matching GO P2P Device Address in P2P element");
-				wpabuf_free(p2p_ie);
-				continue;
-			}
-			wpabuf_free(p2p_ie);
-		}
-
-		/*
-		 * TODO: skip the AP if its P2P IE has Group Formation
-		 * bit set in the P2P Group Capability Bitmap and we
-		 * are not in Group Formation with that device.
-		 */
-#endif /* CONFIG_P2P */
-
-		if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time))
-		{
-			struct os_reltime diff;
-
-			os_reltime_sub(&wpa_s->scan_min_time,
-				       &bss->last_update, &diff);
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - scan result not recent enough (%u.%06u seconds too old)",
-				(unsigned int) diff.sec,
-				(unsigned int) diff.usec);
-			continue;
-		}
-#ifdef CONFIG_MBO
-#ifdef CONFIG_TESTING_OPTIONS
-		if (wpa_s->ignore_assoc_disallow)
-			goto skip_assoc_disallow;
-#endif /* CONFIG_TESTING_OPTIONS */
-		assoc_disallow = wpas_mbo_get_bss_attr(
-			bss, MBO_ATTR_ID_ASSOC_DISALLOW);
-		if (assoc_disallow && assoc_disallow[1] >= 1) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - MBO association disallowed (reason %u)",
-				assoc_disallow[2]);
-			continue;
-		}
-
-		if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - AP temporarily disallowed");
-			continue;
-		}
-#ifdef CONFIG_TESTING_OPTIONS
-	skip_assoc_disallow:
-#endif /* CONFIG_TESTING_OPTIONS */
-#endif /* CONFIG_MBO */
-
-#ifdef CONFIG_DPP
-		if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
-		    !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
-		    (!ssid->dpp_connector ||
-		     !ssid->dpp_netaccesskey ||
-		     !ssid->dpp_csign)) {
-			if (debug_print)
-				wpa_dbg(wpa_s, MSG_DEBUG,
-					"   skip - no PMKSA entry for DPP");
-			continue;
-		}
-#endif /* CONFIG_DPP */
-
-		/* Matching configuration found */
-		return ssid;
+		if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+				    bss, blacklist_count, debug_print))
+			return ssid;
 	}
 
 	/* No matching configuration found */
@@ -1769,52 +1858,19 @@
 	return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
 }
 
-#endif /* CONFIG_NO_ROAMING */
 
-
-static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
-				       struct wpa_bss *selected,
-				       struct wpa_ssid *ssid)
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+					   struct wpa_bss *current_bss,
+					   struct wpa_bss *selected)
 {
-	struct wpa_bss *current_bss = NULL;
-#ifndef CONFIG_NO_ROAMING
 	int min_diff, diff;
 	int to_5ghz;
 	int cur_level;
 	unsigned int cur_est, sel_est;
 	struct wpa_signal_info si;
 	int cur_snr = 0;
-#endif /* CONFIG_NO_ROAMING */
+	int ret = 0;
 
-	if (wpa_s->reassociate)
-		return 1; /* explicit request to reassociate */
-	if (wpa_s->wpa_state < WPA_ASSOCIATED)
-		return 1; /* we are not associated; continue */
-	if (wpa_s->current_ssid == NULL)
-		return 1; /* unknown current SSID */
-	if (wpa_s->current_ssid != ssid)
-		return 1; /* different network block */
-
-	if (wpas_driver_bss_selection(wpa_s))
-		return 0; /* Driver-based roaming */
-
-	if (wpa_s->current_ssid->ssid)
-		current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
-					  wpa_s->current_ssid->ssid,
-					  wpa_s->current_ssid->ssid_len);
-	if (!current_bss)
-		current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
-
-	if (!current_bss)
-		return 1; /* current BSS not seen in scan results */
-
-	if (current_bss == selected)
-		return 0;
-
-	if (selected->last_update_idx > current_bss->last_update_idx)
-		return 1; /* current BSS not seen in the last scan */
-
-#ifndef CONFIG_NO_ROAMING
 	wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
 	wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
 		" freq=%d level=%d snr=%d est_throughput=%u",
@@ -1933,13 +1989,64 @@
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"Skip roam - too small difference in signal level (%d < %d)",
 			diff, min_diff);
-		return 0;
+		ret = 0;
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Allow reassociation due to difference in signal level (%d >= %d)",
+			diff, min_diff);
+		ret = 1;
 	}
+	wpa_msg_ctrl(wpa_s, MSG_INFO, "%scur_bssid=" MACSTR
+		     " cur_freq=%d cur_level=%d cur_est=%d sel_bssid=" MACSTR
+		     " sel_freq=%d sel_level=%d sel_est=%d",
+		     ret ? WPA_EVENT_DO_ROAM : WPA_EVENT_SKIP_ROAM,
+		     MAC2STR(current_bss->bssid),
+		     current_bss->freq, cur_level, cur_est,
+		     MAC2STR(selected->bssid),
+		     selected->freq, selected->level, sel_est);
+	return ret;
+}
 
-	wpa_dbg(wpa_s, MSG_DEBUG,
-		"Allow reassociation due to difference in signal level (%d >= %d)",
-		diff, min_diff);
-	return 1;
+#endif /* CONFIG_NO_ROAMING */
+
+
+static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
+				       struct wpa_bss *selected,
+				       struct wpa_ssid *ssid)
+{
+	struct wpa_bss *current_bss = NULL;
+
+	if (wpa_s->reassociate)
+		return 1; /* explicit request to reassociate */
+	if (wpa_s->wpa_state < WPA_ASSOCIATED)
+		return 1; /* we are not associated; continue */
+	if (wpa_s->current_ssid == NULL)
+		return 1; /* unknown current SSID */
+	if (wpa_s->current_ssid != ssid)
+		return 1; /* different network block */
+
+	if (wpas_driver_bss_selection(wpa_s))
+		return 0; /* Driver-based roaming */
+
+	if (wpa_s->current_ssid->ssid)
+		current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+					  wpa_s->current_ssid->ssid,
+					  wpa_s->current_ssid->ssid_len);
+	if (!current_bss)
+		current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+
+	if (!current_bss)
+		return 1; /* current BSS not seen in scan results */
+
+	if (current_bss == selected)
+		return 0;
+
+	if (selected->last_update_idx > current_bss->last_update_idx)
+		return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
+	return wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
+						      selected);
 #else /* CONFIG_NO_ROAMING */
 	return 0;
 #endif /* CONFIG_NO_ROAMING */
@@ -2571,11 +2678,11 @@
 {
 	int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
 	const u8 *p;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
 	u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
+	bool bssid_known;
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
+	bssid_known = wpa_drv_get_bssid(wpa_s, bssid) == 0;
 	if (data->assoc_info.req_ies)
 		wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
 			    data->assoc_info.req_ies_len);
@@ -2718,7 +2825,7 @@
 
 #ifdef CONFIG_OWE
 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
-	    (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+	    (!bssid_known ||
 	     owe_process_assoc_resp(wpa_s->wpa, bssid,
 				    data->assoc_info.resp_ies,
 				    data->assoc_info.resp_ies_len) < 0)) {
@@ -2753,7 +2860,7 @@
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_SME
 	if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
-		if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+		if (!bssid_known ||
 		    wpa_ft_validate_reassoc_resp(wpa_s->wpa,
 						 data->assoc_info.resp_ies,
 						 data->assoc_info.resp_ies_len,
@@ -2813,7 +2920,7 @@
 	/* Process FT when SME is in the driver */
 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
 	    wpa_ft_is_completed(wpa_s->wpa)) {
-		if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+		if (!bssid_known ||
 		    wpa_ft_validate_reassoc_resp(wpa_s->wpa,
 						 data->assoc_info.resp_ies,
 						 data->assoc_info.resp_ies_len,
@@ -2831,6 +2938,11 @@
 			     data->assoc_info.resp_ies_len);
 #endif /* CONFIG_IEEE80211R */
 
+	if (bssid_known)
+		wpas_handle_assoc_resp_mscs(wpa_s, bssid,
+					    data->assoc_info.resp_ies,
+					    data->assoc_info.resp_ies_len);
+
 	/* WPA/RSN IE from Beacon/ProbeResp */
 	p = data->assoc_info.beacon_ies;
 	l = data->assoc_info.beacon_ies_len;
@@ -4164,6 +4276,13 @@
 	}
 #endif /* CONFIG_DPP */
 
+	if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
+	    payload[0] == ROBUST_AV_MSCS_RESP) {
+		wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,
+						  payload + 1, plen - 1);
+		return;
+	}
+
 	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
 			   category, payload, plen, freq);
 	if (wpa_s->ifmsh)
@@ -4402,7 +4521,9 @@
 	 * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an
 	 * interoperability workaround with older hostapd implementation. */
 	if (DPP_VERSION > 1 && wpa_s->current_ssid &&
-	    wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+	    (wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP ||
+	     ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+	      wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)) &&
 	    wpa_s->current_ssid->dpp_pfs == 0 &&
 	    (data->assoc_reject.status_code ==
 	     WLAN_STATUS_ASSOC_DENIED_UNSPEC ||
@@ -4865,7 +4986,9 @@
 		}
 #endif /* CONFIG_AP */
 
-		sme_event_ch_switch(wpa_s);
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_ch_switch(wpa_s);
+
 		wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
 		wnm_clear_coloc_intf_reporting(wpa_s);
 		break;
@@ -5376,8 +5499,6 @@
 			return;
 		wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
 		os_free(wpa_i);
-		if (wpa_s)
-			wpa_s->matched = 1;
 	}
 #endif /* CONFIG_MATCH_IFACE */
 
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
index 1883545..8e865f3 100755
--- a/wpa_supplicant/examples/dpp-nfc.py
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -7,6 +7,8 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import binascii
+import errno
 import os
 import struct
 import sys
@@ -29,20 +31,28 @@
 in_raw_mode = False
 prev_tcgetattr = 0
 no_input = False
-srv = None
 continue_loop = True
 terminate_now = False
 summary_file = None
 success_file = None
-my_crn_ready = False
-my_crn = None
-peer_crn = None
-hs_sent = False
+netrole = None
+operation_success = False
 mutex = threading.Lock()
 
-def summary(txt):
+C_NORMAL = '\033[0m'
+C_RED = '\033[91m'
+C_GREEN = '\033[92m'
+C_YELLOW = '\033[93m'
+C_BLUE = '\033[94m'
+C_MAGENTA = '\033[95m'
+C_CYAN = '\033[96m'
+
+def summary(txt, color=None):
     with mutex:
-        print(txt)
+        if color:
+            print(color + txt + C_NORMAL)
+        else:
+            print(txt)
         if summary_file:
             with open(summary_file, 'a') as f:
                 f.write(txt + "\n")
@@ -67,15 +77,18 @@
         return None
 
     for ctrl in ifaces:
-        if ifname:
-            if ifname not in ctrl:
-                continue
+        if ifname and ifname not in ctrl:
+            continue
+        if os.path.basename(ctrl).startswith("p2p-dev-"):
+            # skip P2P management interface
+            continue
         try:
             summary("Trying to use control interface " + ctrl)
             wpas = wpaspy.Ctrl(ctrl)
             return wpas
         except Exception as e:
             pass
+    summary("Could not connect to wpa_supplicant")
     return None
 
 def dpp_nfc_uri_process(uri):
@@ -84,7 +97,7 @@
         return False
     peer_id = wpas.request("DPP_NFC_URI " + uri)
     if "FAIL" in peer_id:
-        summary("Could not parse DPP URI from NFC URI record")
+        summary("Could not parse DPP URI from NFC URI record", color=C_RED)
         return False
     peer_id = int(peer_id)
     summary("peer_id=%d for URI from NFC Tag: %s" % (peer_id, uri))
@@ -99,7 +112,7 @@
     summary("Initiate DPP authentication: " + cmd)
     res = wpas.request(cmd)
     if "OK" not in res:
-        summary("Failed to initiate DPP Authentication")
+        summary("Failed to initiate DPP Authentication", color=C_RED)
         return False
     summary("DPP Authentication initiated")
     return True
@@ -110,20 +123,20 @@
         return False
     summary(record)
     if len(record.data) < 5:
-        summary("Too short DPP HS")
+        summary("Too short DPP HS", color=C_RED)
         return False
     if record.data[0] != 0:
-        summary("Unexpected URI Identifier Code")
+        summary("Unexpected URI Identifier Code", color=C_RED)
         return False
     uribuf = record.data[1:]
     try:
         uri = uribuf.decode()
     except:
-        summary("Invalid URI payload")
+        summary("Invalid URI payload", color=C_RED)
         return False
     summary("URI: " + uri)
     if not uri.startswith("DPP:"):
-        summary("Not a DPP URI")
+        summary("Not a DPP URI", color=C_RED)
         return False
     return dpp_nfc_uri_process(uri)
 
@@ -179,12 +192,43 @@
         raise Exception("Failed to generate bootstrapping info")
     return int(res)
 
-def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
+def dpp_start_listen(wpas, freq):
+    if get_status_field(wpas, "bssid[0]"):
+        summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
+        if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
+            summary("Enable beaconing to have radio ready for RX")
+            wpas.request("DISABLE")
+            wpas.request("SET start_disabled 0")
+            wpas.request("ENABLE")
+    cmd = "DPP_LISTEN %d" % freq
+    global enrollee_only
+    global configurator_only
+    if enrollee_only:
+        cmd += " role=enrollee"
+    elif configurator_only:
+        cmd += " role=configurator"
+    global netrole
+    if netrole:
+        cmd += " netrole=" + netrole
+    summary(cmd)
+    res = wpas.request(cmd)
+    if "OK" not in res:
+        summary("Failed to start DPP listen", color=C_RED)
+        return False
+    return True
+
+def wpas_get_nfc_uri(start_listen=True, pick_channel=False, chan_override=None):
+    listen_freq = 2412
     wpas = wpas_connect()
     if wpas is None:
         return None
     global own_id, chanlist
-    chan = chanlist
+    if chan_override:
+        chan = chan_override
+    else:
+        chan = chanlist
+    if chan and chan.startswith("81/"):
+        listen_freq = int(chan[3:].split(',')[0]) * 5 + 2407
     if chan is None and get_status_field(wpas, "bssid[0]"):
         freq = get_status_field(wpas, "freq")
         if freq:
@@ -192,15 +236,18 @@
             if freq >= 2412 and freq <= 2462:
                 chan = "81/%d" % ((freq - 2407) / 5)
                 summary("Use current AP operating channel (%d MHz) as the URI channel list (%s)" % (freq, chan))
+                listen_freq = freq
     if chan is None and pick_channel:
         chan = "81/6"
         summary("Use channel 2437 MHz since no other preference provided")
+        listen_freq = 2437
     own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chan, mac=True)
     res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
     if "FAIL" in res:
         return None
     if start_listen:
-        wpas.request("DPP_LISTEN 2412 netrole=configurator")
+        if not dpp_start_listen(wpas, listen_freq):
+            raise Exception("Failed to start listen operation on %d MHz" % listen_freq)
     return res
 
 def wpas_report_handover_req(uri):
@@ -219,82 +266,180 @@
     cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
     return wpas.request(cmd)
 
-def dpp_handover_client(llc):
-    uri = wpas_get_nfc_uri(start_listen=False)
+def dpp_handover_client(handover, alt=False):
+    summary("About to start run_dpp_handover_client (alt=%s)" % str(alt))
+    if alt:
+        handover.i_m_selector = False
+    run_dpp_handover_client(handover, alt)
+    summary("Done run_dpp_handover_client (alt=%s)" % str(alt))
+
+def run_client_alt(handover, alt):
+    if handover.start_client_alt and not alt:
+        handover.start_client_alt = False
+        summary("Try to send alternative handover request")
+        dpp_handover_client(handover, alt=True)
+
+class HandoverClient(nfc.handover.HandoverClient):
+    def __init__(self, handover, llc):
+        super(HandoverClient, self).__init__(llc)
+        self.handover = handover
+
+    def recv_records(self, timeout=None):
+        msg = self.recv_octets(timeout)
+        if msg is None:
+            return None
+        records = list(ndef.message_decoder(msg, 'relax'))
+        if records and records[0].type == 'urn:nfc:wkt:Hs':
+            summary("Handover client received message '{0}'".format(records[0].type))
+            return list(ndef.message_decoder(msg, 'relax'))
+        summary("Handover client received invalid message: %s" + binascii.hexlify(msg))
+        return None
+
+    def recv_octets(self, timeout=None):
+        start = time.time()
+        msg = bytearray()
+        while True:
+            poll_timeout = 0.1 if timeout is None or timeout > 0.1 else timeout
+            if not self.socket.poll('recv', poll_timeout):
+                if timeout:
+                    timeout -= time.time() - start
+                    if timeout <= 0:
+                        return None
+                    start = time.time()
+                continue
+            try:
+                r = self.socket.recv()
+                if r is None:
+                    return None
+                msg += r
+            except TypeError:
+                return b''
+            try:
+                list(ndef.message_decoder(msg, 'strict', {}))
+                return bytes(msg)
+            except ndef.DecodeError:
+                if timeout:
+                    timeout -= time.time() - start
+                    if timeout <= 0:
+                        return None
+                    start = time.time()
+                continue
+        return None
+
+def run_dpp_handover_client(handover, alt=False):
+    chan_override = None
+    if alt:
+        chan_override = handover.altchanlist
+        handover.alt_proposal_used = True
+    global test_uri, test_alt_uri
+    if test_uri:
+        summary("TEST MODE: Using specified URI (alt=%s)" % str(alt))
+        uri = test_alt_uri if alt else test_uri
+    else:
+        uri = wpas_get_nfc_uri(start_listen=False, chan_override=chan_override)
     if uri is None:
-        summary("Cannot start handover client - no bootstrap URI available")
+        summary("Cannot start handover client - no bootstrap URI available",
+                color=C_RED)
         return
+    handover.my_uri = uri
     uri = ndef.UriRecord(uri)
     summary("NFC URI record for DPP: " + str(uri))
     carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
-    crn = os.urandom(2)
+    global test_crn
+    if test_crn:
+        prev, = struct.unpack('>H', test_crn)
+        summary("TEST MODE: Use specified crn %d" % prev)
+        crn = test_crn
+        test_crn = struct.pack('>H', prev + 0x10)
+    else:
+        crn = os.urandom(2)
     hr = ndef.HandoverRequestRecord(version="1.4", crn=crn)
     hr.add_alternative_carrier('active', carrier.name)
     message = [hr, carrier]
     summary("NFC Handover Request message for DPP: " + str(message))
 
-    global peer_crn
-    if peer_crn is not None:
+    if handover.peer_crn is not None and not alt:
         summary("NFC handover request from peer was already received - do not send own")
         return
-    client = nfc.handover.HandoverClient(llc)
-    try:
-        summary("Trying to initiate NFC connection handover")
-        client.connect()
-        summary("Connected for handover")
-    except nfc.llcp.ConnectRefused:
-        summary("Handover connection refused")
-        client.close()
-        return
-    except Exception as e:
-        summary("Other exception: " + str(e))
-        client.close()
-        return
+    if handover.client:
+        summary("Use already started handover client")
+        client = handover.client
+    else:
+        summary("Start handover client")
+        client = HandoverClient(handover, handover.llc)
+        try:
+            summary("Trying to initiate NFC connection handover")
+            client.connect()
+            summary("Connected for handover")
+        except nfc.llcp.ConnectRefused:
+            summary("Handover connection refused")
+            client.close()
+            return
+        except Exception as e:
+            summary("Other exception: " + str(e))
+            client.close()
+            return
+        handover.client = client
 
-    if peer_crn is not None:
+    if handover.peer_crn is not None and not alt:
         summary("NFC handover request from peer was already received - do not send own")
-        client.close()
         return
 
     summary("Sending handover request")
 
-    global my_crn, my_crn_ready, hs_sent
-    my_crn_ready = True
+    handover.my_crn_ready = True
 
     if not client.send_records(message):
-        my_crn_ready = False
-        summary("Failed to send handover request")
-        client.close()
+        handover.my_crn_ready = False
+        summary("Failed to send handover request", color=C_RED)
+        run_client_alt(handover, alt)
         return
 
-    my_crn, = struct.unpack('>H', crn)
+    handover.my_crn, = struct.unpack('>H', crn)
 
     summary("Receiving handover response")
     try:
+        start = time.time()
         message = client.recv_records(timeout=3.0)
+        end = time.time()
+        summary("Received {} record(s) in {} seconds".format(len(message) if message is not None else -1, end - start))
     except Exception as e:
         # This is fine if we are the handover selector
-        if hs_sent:
+        if handover.hs_sent:
             summary("Client receive failed as expected since I'm the handover server: %s" % str(e))
+        elif handover.alt_proposal_used and not alt:
+            summary("Client received failed for initial proposal as expected since alternative proposal was also used: %s" % str(e))
         else:
-            summary("Client receive failed: %s" % str(e))
+            summary("Client receive failed: %s" % str(e), color=C_RED)
         message = None
     if message is None:
-        if hs_sent:
+        if handover.hs_sent:
             summary("No response received as expected since I'm the handover server")
+        elif handover.alt_proposal_used and not alt:
+            summary("No response received for initial proposal as expected since alternative proposal was also used")
+        elif handover.try_own and not alt:
+            summary("No response received for initial proposal as expected since alternative proposal will also be sent")
         else:
-            summary("No response received")
-        client.close()
+            summary("No response received", color=C_RED)
+        run_client_alt(handover, alt)
         return
     summary("Received message: " + str(message))
     if len(message) < 1 or \
        not isinstance(message[0], ndef.HandoverSelectRecord):
         summary("Response was not Hs - received: " + message.type)
-        client.close()
         return
 
     summary("Received handover select message")
     summary("alternative carriers: " + str(message[0].alternative_carriers))
+    if handover.i_m_selector:
+        summary("Ignore the received select since I'm the handover selector")
+        run_client_alt(handover, alt)
+        return
+
+    if handover.alt_proposal_used and not alt:
+        summary("Ignore received handover select for the initial proposal since alternative proposal was sent")
+        client.close()
+        return
 
     dpp_found = False
     for carrier in message:
@@ -303,15 +448,19 @@
         summary("Remote carrier type: " + carrier.type)
         if carrier.type == "application/vnd.wfa.dpp":
             if len(carrier.data) == 0 or carrier.data[0] != 0:
-                summary("URI Identifier Code 'None' not seen")
+                summary("URI Identifier Code 'None' not seen", color=C_RED)
                 continue
             summary("DPP carrier type match - send to wpa_supplicant")
             dpp_found = True
             uri = carrier.data[1:].decode("utf-8")
             summary("DPP URI: " + uri)
+            handover.peer_uri = uri
+            if test_uri:
+                summary("TEST MODE: Fake processing")
+                break
             res = wpas_report_handover_sel(uri)
             if res is None or "FAIL" in res:
-                summary("DPP handover report rejected")
+                summary("DPP handover report rejected", color=C_RED)
                 break
 
             success_report("DPP handover reported successfully (initiator)")
@@ -331,7 +480,7 @@
                 # TODO: Single Configurator instance
                 res = wpas.request("DPP_CONFIGURATOR_ADD")
                 if "FAIL" in res:
-                    summary("Failed to initiate Configurator")
+                    summary("Failed to initiate Configurator", color=C_RED)
                     break
                 conf_id = int(res)
                 extra = " conf=sta-dpp configurator=%d" % conf_id
@@ -341,17 +490,23 @@
             cmd += extra
             res = wpas.request(cmd)
             if "FAIL" in res:
-                summary("Failed to initiate DPP authentication")
+                summary("Failed to initiate DPP authentication", color=C_RED)
             break
 
-    if not dpp_found:
+    if not dpp_found and handover.no_alt_proposal:
+        summary("DPP carrier not seen in response - do not allow alternative proposal anymore")
+    elif not dpp_found:
         summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
-        client.close()
+        handover.alt_proposal = True
+        handover.my_crn_ready = False
+        handover.my_crn = None
+        handover.peer_crn = None
+        handover.hs_sent = False
         summary("Returning from dpp_handover_client")
         return
 
     summary("Remove peer")
-    client.close()
+    handover.close()
     summary("Done with handover")
     global only_one
     if only_one:
@@ -360,22 +515,67 @@
         continue_loop = False
 
     global no_wait
-    if no_wait:
-        print("Trying to exit..")
+    if no_wait or only_one:
+        summary("Trying to exit..")
         global terminate_now
         terminate_now = True
 
     summary("Returning from dpp_handover_client")
 
 class HandoverServer(nfc.handover.HandoverServer):
-    def __init__(self, llc):
+    def __init__(self, handover, llc):
         super(HandoverServer, self).__init__(llc)
         self.sent_carrier = None
         self.ho_server_processing = False
         self.success = False
-        self.try_own = False
+        self.llc = llc
+        self.handover = handover
+
+    def serve(self, socket):
+        peer_sap = socket.getpeername()
+        summary("Serving handover client on remote sap {0}".format(peer_sap))
+        send_miu = socket.getsockopt(nfc.llcp.SO_SNDMIU)
+        try:
+            while socket.poll("recv"):
+                req = bytearray()
+                while socket.poll("recv"):
+                    r = socket.recv()
+                    if r is None:
+                        return None
+                    summary("Received %d octets" % len(r))
+                    req += r
+                    if len(req) == 0:
+                        continue
+                    try:
+                        list(ndef.message_decoder(req, 'strict', {}))
+                    except ndef.DecodeError:
+                        continue
+                    summary("Full message received")
+                    resp = self._process_request_data(req)
+                    if resp is None or len(resp) == 0:
+                        summary("No handover select to send out - wait for a possible alternative handover request")
+                        handover.alt_proposal = True
+                        req = bytearray()
+                        continue
+
+                    for offset in range(0, len(resp), send_miu):
+                        if not socket.send(resp[offset:offset + send_miu]):
+                            summary("Failed to send handover select - connection closed")
+                            return
+                    summary("Sent out full handover select")
+                    if handover.terminate_on_hs_send_completion:
+                        handover.delayed_exit()
+
+        except nfc.llcp.Error as e:
+            global terminate_now
+            summary("HandoverServer exception: %s" % e,
+                    color=None if e.errno == errno.EPIPE or terminate_now else C_RED)
+        finally:
+            socket.close()
+            summary("Handover serve thread exiting")
 
     def process_handover_request_message(self, records):
+        handover = self.handover
         self.ho_server_processing = True
         global in_raw_mode
         was_in_raw_mode = in_raw_mode
@@ -384,33 +584,33 @@
             print("\n")
         summary("HandoverServer - request received: " + str(records))
 
-        global my_crn, peer_crn, my_crn_ready
-
         for carrier in records:
             if not isinstance(carrier, ndef.HandoverRequestRecord):
                 continue
             if carrier.collision_resolution_number:
-                peer_crn = carrier.collision_resolution_number
-                summary("peer_crn: %d" % peer_crn)
+                handover.peer_crn = carrier.collision_resolution_number
+                summary("peer_crn: %d" % handover.peer_crn)
 
-        if my_crn is None and my_crn_ready:
+        if handover.my_crn is None and handover.my_crn_ready:
             summary("Still trying to send own handover request - wait a moment to see if that succeeds before checking crn values")
             for i in range(10):
-                if my_crn is not None:
+                if handover.my_crn is not None:
                     break
                 time.sleep(0.01)
-        if my_crn is not None:
-            summary("my_crn: %d" % my_crn)
+        if handover.my_crn is not None:
+            summary("my_crn: %d" % handover.my_crn)
 
-        if my_crn is not None and peer_crn is not None:
-            if my_crn == peer_crn:
+        if handover.my_crn is not None and handover.peer_crn is not None:
+            if handover.my_crn == handover.peer_crn:
                 summary("Same crn used - automatic collision resolution failed")
                 # TODO: Should generate a new Handover Request message
                 return ''
-            if ((my_crn & 1) == (peer_crn & 1) and my_crn > peer_crn) or \
-               ((my_crn & 1) != (peer_crn & 1) and my_crn < peer_crn):
+            if ((handover.my_crn & 1) == (handover.peer_crn & 1) and \
+                handover.my_crn > handover.peer_crn) or \
+               ((handover.my_crn & 1) != (handover.peer_crn & 1) and \
+                handover.my_crn < handover.peer_crn):
                 summary("I'm the Handover Selector Device")
-                pass
+                handover.i_m_selector = True
             else:
                 summary("Peer is the Handover Selector device")
                 summary("Ignore the received request.")
@@ -428,61 +628,73 @@
             if carrier.type == "application/vnd.wfa.dpp":
                 summary("DPP carrier type match - add DPP carrier record")
                 if len(carrier.data) == 0 or carrier.data[0] != 0:
-                    summary("URI Identifier Code 'None' not seen")
+                    summary("URI Identifier Code 'None' not seen", color=C_RED)
                     continue
                 uri = carrier.data[1:].decode("utf-8")
                 summary("Received DPP URI: " + uri)
 
-                data = wpas_get_nfc_uri(start_listen=False, pick_channel=True)
+                global test_uri, test_alt_uri
+                if test_uri:
+                    summary("TEST MODE: Using specified URI")
+                    data = test_sel_uri if test_sel_uri else test_uri
+                elif handover.alt_proposal and handover.altchanlist:
+                    summary("Use alternative channel list while processing alternative proposal from peer")
+                    data = wpas_get_nfc_uri(start_listen=False,
+                                            chan_override=handover.altchanlist,
+                                            pick_channel=True)
+                else:
+                    data = wpas_get_nfc_uri(start_listen=False,
+                                            pick_channel=True)
                 summary("Own URI (pre-processing): %s" % data)
 
-                res = wpas_report_handover_req(uri)
+                if test_uri:
+                    summary("TEST MODE: Fake processing")
+                    res = "OK"
+                    data += " [%s]" % uri
+                else:
+                    res = wpas_report_handover_req(uri)
                 if res is None or "FAIL" in res:
-                    summary("DPP handover request processing failed")
+                    summary("DPP handover request processing failed",
+                            color=C_RED)
+                    if handover.altchanlist:
+                        data = wpas_get_nfc_uri(start_listen=False,
+                                                chan_override=handover.altchanlist)
+                        summary("Own URI (try another channel list): %s" % data)
+                    continue
+
+                if test_alt_uri:
+                    summary("TEST MODE: Reject initial proposal")
                     continue
 
                 found = True
 
-                wpas = wpas_connect()
-                if wpas is None:
-                    continue
-                global own_id
-                data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
-                if "FAIL" in data:
-                    continue
+                if not test_uri:
+                    wpas = wpas_connect()
+                    if wpas is None:
+                        continue
+                    global own_id
+                    data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+                    if "FAIL" in data:
+                        continue
                 summary("Own URI (post-processing): %s" % data)
+                handover.my_uri = data
+                handover.peer_uri = uri
                 uri = ndef.UriRecord(data)
                 summary("Own bootstrapping NFC URI record: " + str(uri))
 
-                info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
-                freq = None
-                for line in info.splitlines():
-                    if line.startswith("use_freq="):
-                        freq = int(line.split('=')[1])
-                if freq is None or freq == 0:
-                    summary("No channel negotiated over NFC - use channel 6")
-                    freq = 2437
-                else:
-                    summary("Negotiated channel: %d MHz" % freq)
-                if get_status_field(wpas, "bssid[0]"):
-                    summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
-                    if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
-                        summary("Enable beaconing to have radio ready for RX")
-                        wpas.request("DISABLE")
-                        wpas.request("SET start_disabled 0")
-                        wpas.request("ENABLE")
-                cmd = "DPP_LISTEN %d" % freq
-                global enrollee_only
-                global configurator_only
-                if enrollee_only:
-                    cmd += " role=enrollee"
-                elif configurator_only:
-                    cmd += " role=configurator"
-                summary(cmd)
-                res = wpas.request(cmd)
-                if "OK" not in res:
-                    summary("Failed to start DPP listen")
-                    break
+                if not test_uri:
+                    info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
+                    freq = None
+                    for line in info.splitlines():
+                        if line.startswith("use_freq="):
+                            freq = int(line.split('=')[1])
+                    if freq is None or freq == 0:
+                        summary("No channel negotiated over NFC - use channel 6")
+                        freq = 2437
+                    else:
+                        summary("Negotiated channel: %d MHz" % freq)
+                    if not dpp_start_listen(wpas, freq):
+                        break
 
                 carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
                 summary("Own DPP carrier record: " + str(carrier))
@@ -492,11 +704,26 @@
 
         summary("Sending handover select: " + str(sel))
         if found:
+            summary("Handover completed successfully")
+            handover.terminate_on_hs_send_completion = True
             self.success = True
+            handover.hs_sent = True
+            handover.i_m_selector = True
+        elif handover.no_alt_proposal:
+            summary("Do not try alternative proposal anymore - handover failed",
+                    color=C_RED)
+            handover.hs_sent = True
         else:
-            self.try_own = True
-        global hs_sent
-        hs_sent = True
+            summary("Try to initiate with alternative parameters")
+            handover.try_own = True
+            handover.hs_sent = False
+            handover.no_alt_proposal = True
+            if handover.client_thread:
+                handover.start_client_alt = True
+            else:
+                handover.client_thread = threading.Thread(target=llcp_worker,
+                                                          args=(self.llc, True))
+                handover.client_thread.start()
         return sel
 
 def clear_raw_mode():
@@ -553,17 +780,25 @@
 
 def rdwr_connected_write_tag(tag):
     summary("Tag found - writing - " + str(tag))
+    if not tag.ndef:
+        summary("Not a formatted NDEF tag", color=C_RED)
+        return
     if not tag.ndef.is_writeable:
-        summary("Not a writable tag")
+        summary("Not a writable tag", color=C_RED)
         return
     global dpp_tag_data
     if tag.ndef.capacity < len(dpp_tag_data):
         summary("Not enough room for the message")
         return
-    tag.ndef.records = dpp_tag_data
+    try:
+        tag.ndef.records = dpp_tag_data
+    except ValueError as e:
+        summary("Writing the tag failed: %s" % str(e), color=C_RED)
+        return
     success_report("Tag write succeeded")
-    summary("Done - remove tag")
-    global only_one
+    summary("Tag writing completed - remove tag", color=C_GREEN)
+    global only_one, operation_success
+    operation_success = True
     if only_one:
         global continue_loop
         continue_loop = False
@@ -574,7 +809,7 @@
     summary("Write NFC URI record")
     data = wpas_get_nfc_uri()
     if data is None:
-        summary("Could not get NFC URI from wpa_supplicant")
+        summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
         return
 
     global dpp_sel_wait_remove
@@ -583,7 +818,7 @@
     uri = ndef.UriRecord(data)
     summary(uri)
 
-    summary("Touch an NFC tag")
+    summary("Touch an NFC tag to write URI record", color=C_CYAN)
     global dpp_tag_data
     dpp_tag_data = [uri]
     clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
@@ -592,7 +827,7 @@
     summary("Write NFC Handover Select record on a tag")
     data = wpas_get_nfc_uri()
     if data is None:
-        summary("Could not get NFC URI from wpa_supplicant")
+        summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
         return
 
     global dpp_sel_wait_remove
@@ -606,7 +841,7 @@
     summary(hs)
     summary(carrier)
 
-    summary("Touch an NFC tag")
+    summary("Touch an NFC tag to write HS record", color=C_CYAN)
     global dpp_tag_data
     dpp_tag_data = [hs, carrier]
     summary(dpp_tag_data)
@@ -624,17 +859,24 @@
             global continue_loop
             continue_loop = False
     else:
-        summary("Not an NDEF tag - remove tag")
+        summary("Not an NDEF tag - remove tag", color=C_RED)
         return True
 
     return not no_wait
 
-def llcp_worker(llc):
+def llcp_worker(llc, try_alt):
+    global handover
+    print("Start of llcp_worker()")
+    if try_alt:
+        summary("Starting handover client (try_alt)")
+        dpp_handover_client(handover, alt=True)
+        summary("Exiting llcp_worker thread (try_alt)")
+        return
     global init_on_touch
     if init_on_touch:
-        summary("Starting handover client")
-        dpp_handover_client(llc)
-        summary("Exiting llcp_worker thread (init_in_touch)")
+        summary("Starting handover client (init_on_touch)")
+        dpp_handover_client(handover)
+        summary("Exiting llcp_worker thread (init_on_touch)")
         return
 
     global no_input
@@ -642,16 +884,18 @@
         summary("Wait for handover to complete")
     else:
         print("Wait for handover to complete - press 'i' to initiate")
-    global srv
-    global wait_connection
-    while not wait_connection and srv.sent_carrier is None:
-        if srv.try_own:
-            srv.try_own = False
+    while not handover.wait_connection and handover.srv.sent_carrier is None:
+        if handover.try_own:
+            handover.try_own = False
             summary("Try to initiate another handover with own parameters")
-            dpp_handover_client(llc)
+            handover.my_crn_ready = False
+            handover.my_crn = None
+            handover.peer_crn = None
+            handover.hs_sent = False
+            dpp_handover_client(handover, alt=True)
             summary("Exiting llcp_worker thread (retry with own parameters)")
             return
-        if srv.ho_server_processing:
+        if handover.srv.ho_server_processing:
             time.sleep(0.025)
         elif no_input:
             time.sleep(0.5)
@@ -661,7 +905,7 @@
                 continue
             clear_raw_mode()
             summary("Starting handover client")
-            dpp_handover_client(llc)
+            dpp_handover_client(handover)
             summary("Exiting llcp_worker thread (manual init)")
             return
 
@@ -672,28 +916,73 @@
         print("\r")
     summary("Exiting llcp_worker thread")
 
+class ConnectionHandover():
+    def __init__(self):
+        self.client = None
+        self.client_thread = None
+        self.reset()
+        self.exit_thread = None
+
+    def reset(self):
+        self.wait_connection = False
+        self.my_crn_ready = False
+        self.my_crn = None
+        self.peer_crn = None
+        self.hs_sent = False
+        self.no_alt_proposal = False
+        self.alt_proposal_used = False
+        self.i_m_selector = False
+        self.start_client_alt = False
+        self.terminate_on_hs_send_completion = False
+        self.try_own = False
+        self.my_uri = None
+        self.peer_uri = None
+        self.connected = False
+        self.alt_proposal = False
+
+    def start_handover_server(self, llc):
+        summary("Start handover server")
+        self.llc = llc
+        self.srv = HandoverServer(self, llc)
+
+    def close(self):
+        if self.client:
+            self.client.close()
+            self.client = None
+
+    def run_delayed_exit(self):
+        summary("Trying to exit (delayed)..")
+        time.sleep(0.25)
+        summary("Trying to exit (after wait)..")
+        global terminate_now
+        terminate_now = True
+
+    def delayed_exit(self):
+        global only_one
+        if only_one:
+            self.exit_thread = threading.Thread(target=self.run_delayed_exit)
+            self.exit_thread.start()
+
 def llcp_startup(llc):
-    summary("Start LLCP server")
-    global srv
-    srv = HandoverServer(llc)
+    global handover
+    handover.start_handover_server(llc)
     return llc
 
 def llcp_connected(llc):
     summary("P2P LLCP connected")
-    global wait_connection, my_crn, peer_crn, my_crn_ready, hs_sent
-    wait_connection = False
-    my_crn_ready = False
-    my_crn = None
-    peer_crn = None
-    hs_sent = False
-    global srv
-    srv.start()
+    global handover
+    handover.connected = True
+    handover.srv.start()
     if init_on_touch or not no_input:
-        threading.Thread(target=llcp_worker, args=(llc,)).start()
+        handover.client_thread = threading.Thread(target=llcp_worker,
+                                                  args=(llc, False))
+        handover.client_thread.start()
     return True
 
 def llcp_release(llc):
     summary("LLCP release")
+    global handover
+    handover.close()
     return True
 
 def terminate_loop():
@@ -737,22 +1026,53 @@
                         help='success file for writing success update')
     parser.add_argument('--device', default='usb', help='NFC device to open')
     parser.add_argument('--chan', default=None, help='channel list')
+    parser.add_argument('--altchan', default=None, help='alternative channel list')
+    parser.add_argument('--netrole', default=None, help='netrole for Enrollee')
+    parser.add_argument('--test-uri', default=None,
+                        help='test mode: initial URI')
+    parser.add_argument('--test-alt-uri', default=None,
+                        help='test mode: alternative URI')
+    parser.add_argument('--test-sel-uri', default=None,
+                        help='test mode: handover select URI')
+    parser.add_argument('--test-crn', default=None,
+                        help='test mode: hardcoded crn')
     parser.add_argument('command', choices=['write-nfc-uri',
                                             'write-nfc-hs'],
                         nargs='?')
     args = parser.parse_args()
     summary(args)
 
+    global handover
+    handover = ConnectionHandover()
+
     global only_one
     only_one = args.only_one
 
     global no_wait
     no_wait = args.no_wait
 
-    global chanlist
+    global chanlist, netrole, test_uri, test_alt_uri, test_sel_uri
+    global test_crn
     chanlist = args.chan
+    handover.altchanlist = args.altchan
+    netrole = args.netrole
+    test_uri = args.test_uri
+    test_alt_uri = args.test_alt_uri
+    test_sel_uri = args.test_sel_uri
+    if args.test_crn:
+        test_crn = struct.pack('>H', int(args.test_crn))
+    else:
+        test_crn = None
 
     logging.basicConfig(level=args.loglevel)
+    for l in ['nfc.clf.rcs380',
+              'nfc.clf.transport',
+              'nfc.clf.device',
+              'nfc.clf.__init__',
+              'nfc.llcp',
+              'nfc.handover']:
+        log = logging.getLogger(l)
+        log.setLevel(args.loglevel)
 
     global init_on_touch
     init_on_touch = args.init_on_touch
@@ -788,19 +1108,22 @@
         no_input = True
 
     clf = nfc.ContactlessFrontend()
-    global wait_connection
 
     try:
         if not clf.open(args.device):
-            summary("Could not open connection with an NFC device")
-            raise SystemExit
+            summary("Could not open connection with an NFC device", color=C_RED)
+            raise SystemExit(1)
 
         if args.command == "write-nfc-uri":
             write_nfc_uri(clf, wait_remove=not args.no_wait)
+            if not operation_success:
+                raise SystemExit(1)
             raise SystemExit
 
         if args.command == "write-nfc-hs":
             write_nfc_hs(clf, wait_remove=not args.no_wait)
+            if not operation_success:
+                raise SystemExit(1)
             raise SystemExit
 
         global continue_loop
@@ -810,8 +1133,14 @@
             clear_raw_mode()
             if was_in_raw_mode:
                 print("\r")
-            summary("Waiting for a tag or peer to be touched")
-            wait_connection = True
+            if args.handover_only:
+                summary("Waiting a peer to be touched", color=C_MAGENTA)
+            elif args.tag_read_only:
+                summary("Waiting for a tag to be touched", color=C_BLUE)
+            else:
+                summary("Waiting for a tag or peer to be touched",
+                        color=C_GREEN)
+            handover.wait_connection = True
             try:
                 if args.tag_read_only:
                     if not clf.connect(rdwr={'on-connect': rdwr_connected}):
@@ -833,9 +1162,18 @@
                 summary("clf.connect failed: " + str(e))
                 break
 
-            global srv
-            if only_one and srv and srv.success:
-                raise SystemExit
+            if only_one and handover.connected:
+                role = "selector" if handover.i_m_selector else "requestor"
+                summary("Connection handover result: I'm the %s" % role,
+                        color=C_YELLOW)
+                if handover.peer_uri:
+                    summary("Peer URI: " + handover.peer_uri, color=C_YELLOW)
+                if handover.my_uri:
+                    summary("My URI: " + handover.my_uri, color=C_YELLOW)
+                if not (handover.peer_uri and handover.my_uri):
+                    summary("Negotiated connection handover failed",
+                            color=C_YELLOW)
+                break
 
     except KeyboardInterrupt:
         raise SystemExit
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 4b3fcfc..e60a8c1 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -694,13 +694,15 @@
 		return;
 	}
 
-	if (!query->maintain_addr &&
-	    wpas_update_random_addr_disassoc(wpa_s) < 0) {
-		wpa_msg(wpa_s, MSG_INFO,
-			"Failed to assign random MAC address for GAS");
-		gas_query_free(query, 1);
-		radio_work_done(work);
-		return;
+	if (!query->maintain_addr && !wpa_s->conf->gas_rand_mac_addr) {
+		if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+			wpa_msg(wpa_s, MSG_INFO,
+				"Failed to assign random MAC address for GAS");
+			gas_query_free(query, 1);
+			radio_work_done(work);
+			return;
+		}
+		os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
 	}
 
 	gas->work = work;
diff --git a/wpa_supplicant/hidl/1.4/sta_iface.cpp b/wpa_supplicant/hidl/1.4/sta_iface.cpp
index 7f476b1..976f176 100644
--- a/wpa_supplicant/hidl/1.4/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_iface.cpp
@@ -952,9 +952,10 @@
 		    static_cast<std::underlying_type<
 			ISupplicantStaIface::Hs20AnqpSubtypes>::type>(type));
 	}
+
 	if (anqp_send_req(
-		wpa_s, mac_address.data(), info_elems_buf, num_info_elems,
-		sub_types_bitmask, false)) {
+		wpa_s, mac_address.data(), 0, info_elems_buf, num_info_elems,
+		sub_types_bitmask, 0)) {
 		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	return {SupplicantStatusCode::SUCCESS, ""};
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index b60f80d..c799b5a 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -959,7 +959,9 @@
 			"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
 	if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
 	    wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
-	    wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
+	    wpa_config_set(ssid, "ieee80211w",
+			   wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_REQUIRED ?
+			   "2" : "1", 0) < 0 ||
 	    wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
 		return -1;
 	return 0;
@@ -2748,27 +2750,27 @@
 }
 
 
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
 		  u16 info_ids[], size_t num_ids, u32 subtypes,
 		  u32 mbo_subtypes)
 {
 	struct wpabuf *buf;
 	struct wpabuf *extra_buf = NULL;
 	int ret = 0;
-	int freq;
 	struct wpa_bss *bss;
 	int res;
 
 	bss = wpa_bss_get_bssid(wpa_s, dst);
-	if (!bss) {
+	if (!bss && !freq) {
 		wpa_printf(MSG_WARNING,
-			   "ANQP: Cannot send query to unknown BSS "
-			   MACSTR, MAC2STR(dst));
+			   "ANQP: Cannot send query without BSS freq info");
 		return -1;
 	}
 
-	wpa_bss_anqp_unshare_alloc(bss);
-	freq = bss->freq;
+	if (bss)
+		wpa_bss_anqp_unshare_alloc(bss);
+	if (bss && !freq)
+		freq = bss->freq;
 
 	wpa_msg(wpa_s, MSG_DEBUG,
 		"ANQP: Query Request to " MACSTR " for %u id(s)",
@@ -2787,6 +2789,13 @@
 	if (mbo_subtypes) {
 		struct wpabuf *mbo;
 
+		if (!bss) {
+			wpa_printf(MSG_WARNING,
+				   "ANQP: Cannot send MBO query to unknown BSS "
+				   MACSTR, MAC2STR(dst));
+			return -1;
+		}
+
 		mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
 		if (mbo) {
 			if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 37ee2e9..77b2c91 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -11,7 +11,7 @@
 
 enum gas_query_result;
 
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
 		  u16 info_ids[], size_t num_ids, u32 subtypes,
 		  u32 mbo_subtypes);
 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index c085466..558d87a 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -333,30 +333,6 @@
 			   frequency);
 		goto out_free;
 	}
-	if (ssid->ht40)
-		conf->secondary_channel = ssid->ht40;
-	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
-		if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
-			conf->vht_oper_chwidth = ssid->max_oper_chwidth;
-		switch (conf->vht_oper_chwidth) {
-		case CHANWIDTH_80MHZ:
-		case CHANWIDTH_80P80MHZ:
-			ieee80211_freq_to_chan(
-				frequency,
-				&conf->vht_oper_centr_freq_seg0_idx);
-			conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
-			break;
-		case CHANWIDTH_160MHZ:
-			ieee80211_freq_to_chan(
-				frequency,
-				&conf->vht_oper_centr_freq_seg0_idx);
-			conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
-			conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
-			break;
-		}
-		ieee80211_freq_to_chan(ssid->vht_center_freq2,
-				       &conf->vht_oper_centr_freq_seg1_idx);
-	}
 
 	if (ssid->mesh_basic_rates == NULL) {
 		/*
@@ -387,6 +363,31 @@
 		conf->basic_rates[rate_len] = -1;
 	}
 
+	/* While it can enhance performance to switch the primary channel, which
+	 * is also the secondary channel of another network at the same time),
+	 * to the other primary channel, problems exist with this in mesh
+	 * networks.
+	 *
+	 * Example with problems:
+	 *     - 3 mesh nodes M1-M3, freq (5200, 5180)
+	 *     - other node O1, e.g. AP mode, freq (5180, 5200),
+	 * Locations: O1 M1      M2      M3
+	 *
+	 * M3 can only send frames to M1 over M2, no direct connection is
+	 * possible
+	 * Start O1, M1 and M3 first, M1 or O1 will switch channels to align
+	 * with* each other. M3 does not swap, because M1 or O1 cannot be
+	 * reached. M2 is started afterwards and can either connect to M3 or M1
+	 * because of this primary secondary channel switch.
+	 *
+	 * Solutions: (1) central coordination -> not always possible
+	 *            (2) disable pri/sec channel switch in mesh networks
+	 *
+	 * In AP mode, when all nodes can work independently, this poses of
+	 * course no problem, therefore disable it only in mesh mode. */
+	conf->no_pri_sec_switch = 1;
+	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
 	if (wpa_drv_init_mesh(wpa_s)) {
 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
 		return -1;
@@ -398,8 +399,6 @@
 		return -1;
 	}
 
-	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
-
 	return 0;
 out_free:
 	wpa_supplicant_mesh_deinit(wpa_s);
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 12aafcb..b6a5e88 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -533,11 +533,14 @@
 	int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
 
 	if (sta) {
+		if (sta->plink_state == PLINK_ESTAB)
+			hapd->num_plinks--;
 		wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
 		mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
 		wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
 			   MAC2STR(sta->addr));
 		eloop_cancel_timeout(plink_timer, wpa_s, sta);
+		eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta);
 		return 0;
 	}
 
@@ -1290,8 +1293,8 @@
 
 			if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
 						 tx_chanwidth, tx_seg1_idx) !=
-			    0) {
-				wpa_printf(MSG_WARNING, "MPM: %s",
+			    OCI_SUCCESS) {
+				wpa_printf(MSG_WARNING, "MPM: OCV failed: %s",
 					   ocv_errorstr);
 				return;
 			}
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index f19bfbf..834c7a1 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -195,7 +195,8 @@
 		wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
 				rsn->igtk, rsn->igtk_len);
 		wpa_drv_set_key(rsn->wpa_s,
-				wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+				wpa_cipher_to_alg(rsn->mgmt_group_cipher),
+				broadcast_ether_addr,
 				rsn->igtk_key_id, 1,
 				seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
 				KEY_FLAG_GROUP_TX_DEFAULT);
@@ -204,7 +205,8 @@
 	/* group privacy / data frames */
 	wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
 			rsn->mgtk, rsn->mgtk_len);
-	wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+	wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher),
+			broadcast_ether_addr,
 			rsn->mgtk_key_id, 1, seq, sizeof(seq),
 			rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
 
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index bd97fee..91e15e7 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -412,9 +412,13 @@
 	}
 
 	*ie_len = wpabuf_len(buf) - 2;
-	if (*ie_len < 2 || wpabuf_len(buf) > len) {
+	if (*ie_len < 2) {
+		wpa_printf(MSG_DEBUG,
+			   "No supported operating classes IE to add");
+		res = 0;
+	} else if (wpabuf_len(buf) > len) {
 		wpa_printf(MSG_ERROR,
-			   "Failed to add supported operating classes IE");
+			   "Supported operating classes IE exceeds maximum buffer length");
 		res = 0;
 	} else {
 		os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index eb7c392..dc5c16d 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -291,6 +291,41 @@
 }
 
 
+static int wpas_p2p_add_scan_freq_list(struct wpa_supplicant *wpa_s,
+				       enum hostapd_hw_mode band,
+				       struct wpa_driver_scan_params *params)
+{
+	struct hostapd_hw_modes *mode;
+	int num_chans = 0;
+	int *freqs, i;
+
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, 0);
+	if (!mode)
+		return -1;
+
+	if (params->freqs) {
+		while (params->freqs[num_chans])
+			num_chans++;
+	}
+
+	freqs = os_realloc(params->freqs,
+			   (num_chans + mode->num_channels + 1) * sizeof(int));
+	if (!freqs)
+		return -1;
+
+	params->freqs = freqs;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		params->freqs[num_chans++] = mode->channels[i].freq;
+	}
+	params->freqs[num_chans] = 0;
+
+	return 0;
+}
+
+
 static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
 {
 	struct wpa_supplicant *wpa_s = work->wpa_s;
@@ -312,6 +347,15 @@
 			   "Request driver to clear scan cache due to local BSS flush");
 		params->only_new_results = 1;
 	}
+
+	if (wpa_s->conf->p2p_6ghz_disable && !params->freqs) {
+		wpa_printf(MSG_DEBUG,
+			   "P2P: 6 GHz disabled - update the scan frequency list");
+		wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+					    params);
+		wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+					    params);
+	}
 	ret = wpa_drv_scan(wpa_s, params);
 	if (ret == 0)
 		wpa_s->curr_scan_cookie = params->scan_cookie;
@@ -522,7 +566,7 @@
 		/*
 		 * The calling wpa_s instance is going to be removed. Do that
 		 * from an eloop callback to keep the instance available until
-		 * the caller has returned. This my be needed, e.g., to provide
+		 * the caller has returned. This may be needed, e.g., to provide
 		 * control interface responses on the per-interface socket.
 		 */
 		if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
@@ -3736,7 +3780,9 @@
 		u8 ch;
 		struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
 
-		if (o->p2p == NO_P2P_SUPP)
+		if (o->p2p == NO_P2P_SUPP ||
+		    (is_6ghz_op_class(o->op_class) &&
+		     wpa_s->conf->p2p_6ghz_disable))
 			continue;
 
 		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
@@ -3747,6 +3793,13 @@
 			wpa_s->global->p2p_24ghz_social_channels = 1;
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
 			enum chan_allowed res;
+
+			/* Check for non-continuous jump in channel index
+			 * incrementation */
+			if ((o->op_class == 128 || o->op_class == 130) &&
+			    ch < 149 && ch + o->inc > 149)
+				ch = 149;
+
 			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
 			if (res == ALLOWED) {
 				if (reg == NULL) {
@@ -3807,7 +3860,9 @@
 		const struct oper_class_map *o = &global_op_class[op];
 		u8 ch;
 
-		if (o->p2p == NO_P2P_SUPP)
+		if (o->p2p == NO_P2P_SUPP ||
+		    (is_6ghz_op_class(o->op_class) &&
+		     wpa_s->conf->p2p_6ghz_disable))
 			continue;
 
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
@@ -3939,6 +3994,10 @@
 			  wpa_s->ifname);
 	if (os_snprintf_error(sizeof(ifname), ret))
 		return -1;
+	/* Cut length at the maximum size. Note that we don't need to ensure
+	 * collision free names here as the created interface is not a netdev.
+	 */
+	ifname[IFNAMSIZ - 1] = '\0';
 	force_name[0] = '\0';
 	wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
 	ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
@@ -4777,6 +4836,7 @@
 	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
 	wpas_p2p_remove_pending_group_interface(wpa_s);
 	eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_p2p_reconsider_moving_go, wpa_s, NULL);
 	wpas_p2p_listen_work_done(wpa_s);
 	if (wpa_s->p2p_send_action_work) {
 		os_free(wpa_s->p2p_send_action_work->ctx);
@@ -5284,6 +5344,13 @@
 	if (freq > 0) {
 		freqs[0] = freq;
 		params.freqs = freqs;
+	} else if (wpa_s->conf->p2p_6ghz_disable) {
+		wpa_printf(MSG_DEBUG,
+			   "P2P: 6 GHz disabled - update the scan frequency list");
+		wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+					    &params);
+		wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+					    &params);
 	}
 
 	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
@@ -5314,6 +5381,8 @@
 	 * the new scan results become available.
 	 */
 	ret = wpa_drv_scan(wpa_s, &params);
+	if (wpa_s->conf->p2p_6ghz_disable && params.freqs != freqs)
+		os_free(params.freqs);
 	if (!ret) {
 		os_get_reltime(&wpa_s->scan_trigger_time);
 		wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
@@ -5654,6 +5723,9 @@
 			return -1;
 	}
 
+	if (is_6ghz_freq(freq) && wpa_s->conf->p2p_6ghz_disable)
+		return -2;
+
 	os_free(wpa_s->global->add_psk);
 	wpa_s->global->add_psk = NULL;
 
@@ -5880,6 +5952,8 @@
 
 	if (os_strcmp(ifname, "*") == 0) {
 		struct wpa_supplicant *prev;
+		bool calling_wpa_s_group_removed = false;
+
 		wpa_s = global->ifaces;
 		while (wpa_s) {
 			prev = wpa_s;
@@ -5887,9 +5961,23 @@
 			if (prev->p2p_group_interface !=
 			    NOT_P2P_GROUP_INTERFACE ||
 			    (prev->current_ssid &&
-			     prev->current_ssid->p2p_group))
+			     prev->current_ssid->p2p_group)) {
 				wpas_p2p_disconnect_safely(prev, calling_wpa_s);
+				if (prev == calling_wpa_s)
+					calling_wpa_s_group_removed = true;
+			}
 		}
+
+		if (!calling_wpa_s_group_removed &&
+		    (calling_wpa_s->p2p_group_interface !=
+		     NOT_P2P_GROUP_INTERFACE ||
+		     (calling_wpa_s->current_ssid &&
+		      calling_wpa_s->current_ssid->p2p_group))) {
+			wpa_printf(MSG_DEBUG, "Remove calling_wpa_s P2P group");
+			wpas_p2p_disconnect_safely(calling_wpa_s,
+						   calling_wpa_s);
+		}
+
 		return 0;
 	}
 
@@ -9406,6 +9494,8 @@
 {
 	struct p2p_go_neg_results params;
 	struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+	void (*ap_configured_cb)(void *ctx, void *data);
+	void *ap_configured_cb_ctx, *ap_configured_cb_data;
 
 	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
 
@@ -9415,12 +9505,13 @@
 	/* Stop the AP functionality */
 	/* TODO: Should do this in a way that does not indicated to possible
 	 * P2P Clients in the group that the group is terminated. */
-	/* If this action occurs before a group is started, the callback should be
-	 * preserved, or GROUP-STARTED event would be lost. If this action occurs after
-	 * a group is started, these poiners are all NULL and harmless. */
-	void (*ap_configured_cb)(void *ctx, void *data) = wpa_s->ap_configured_cb;
-	void *ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;;
-	void *ap_configured_cb_data = wpa_s->ap_configured_cb_data;
+	/* If this action occurs before a group is started, the callback should
+	 * be preserved, or GROUP-STARTED event would be lost. If this action
+	 * occurs after a group is started, these pointers are all NULL and
+	 * harmless. */
+	ap_configured_cb = wpa_s->ap_configured_cb;
+	ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;
+	ap_configured_cb_data = wpa_s->ap_configured_cb_data;
 	wpa_supplicant_ap_deinit(wpa_s);
 
 	/* Reselect the GO frequency */
@@ -9444,9 +9535,11 @@
 		return;
 	}
 
+	/* Restore preserved callback parameters */
 	wpa_s->ap_configured_cb = ap_configured_cb;
 	wpa_s->ap_configured_cb_ctx = ap_configured_cb_ctx;
 	wpa_s->ap_configured_cb_data = ap_configured_cb_data;
+
 	/* Update the frequency */
 	current_ssid->frequency = params.freq;
 	wpa_s->connect_without_scan = current_ssid;
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 4a8f4ff..de49948 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -154,7 +154,8 @@
 				    const u8 *bssid, const u8 *pmkid,
 				    const u8 *fils_cache_id,
 				    const u8 *pmk, size_t pmk_len,
-				    u32 pmk_lifetime, u8 pmk_reauth_threshold)
+				    u32 pmk_lifetime, u8 pmk_reauth_threshold,
+				    int akmp)
 {
 	printf("%s - not implemented\n", __func__);
 	return -1;
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
new file mode 100644
index 0000000..1280f5d
--- /dev/null
+++ b/wpa_supplicant/robust_av.c
@@ -0,0 +1,160 @@
+/*
+ * wpa_supplicant - Robust AV procedures
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+
+
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+				      struct wpabuf *buf)
+{
+	u8 *len, *len1;
+
+	/* MSCS descriptor element */
+	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+	len = wpabuf_put(buf, 1);
+	wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+	wpabuf_put_u8(buf, robust_av->request_type);
+	wpabuf_put_u8(buf, robust_av->up_bitmap);
+	wpabuf_put_u8(buf, robust_av->up_limit);
+	wpabuf_put_le32(buf, robust_av->stream_timeout);
+
+	if (robust_av->request_type != SCS_REQ_REMOVE) {
+		/* TCLAS mask element */
+		wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+		len1 = wpabuf_put(buf, 1);
+		wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK);
+
+		/* Frame classifier */
+		wpabuf_put_data(buf, robust_av->frame_classifier,
+				robust_av->frame_classifier_len);
+		*len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
+	}
+
+	*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *buf;
+	const u8 *ext_capab = NULL;
+	size_t buf_len;
+	int ret;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+		return 0;
+
+	if (wpa_s->current_bss)
+		ext_capab = wpa_bss_get_ie(wpa_s->current_bss,
+					   WLAN_EID_EXT_CAPAB);
+
+	if (!ext_capab || ext_capab[1] < 11 || !(ext_capab[12] & 0x20)) {
+		wpa_dbg(wpa_s, MSG_INFO,
+			"AP does not support MSCS - could not send MSCS Req");
+		return -1;
+	}
+
+	if (!wpa_s->mscs_setup_done &&
+	    wpa_s->robust_av.request_type != SCS_REQ_ADD) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"MSCS: Failed to send MSCS Request: request type invalid");
+		return -1;
+	}
+
+	buf_len = 3 +	/* Action frame header */
+		  3 +	/* MSCS descriptor IE header */
+		  1 +	/* Request type */
+		  2 +	/* User priority control */
+		  4 +	/* Stream timeout */
+		  3 +	/* TCLAS Mask IE header */
+		  wpa_s->robust_av.frame_classifier_len;
+
+	buf = wpabuf_alloc(buf_len);
+	if (!buf) {
+		wpa_printf(MSG_ERROR, "Failed to allocate MSCS req");
+		return -1;
+	}
+
+	wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
+	wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ);
+	wpa_s->robust_av.dialog_token++;
+	wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token);
+
+	/* MSCS descriptor element */
+	wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf);
+
+	wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", buf);
+	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				  wpa_s->own_addr, wpa_s->bssid,
+				  wpabuf_head(buf), wpabuf_len(buf), 0);
+	if (ret < 0)
+		wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request");
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+				       const u8 *src, const u8 *buf, size_t len)
+{
+	u8 dialog_token;
+	u16 status_code;
+
+	if (len < 3)
+		return;
+
+	dialog_token = *buf++;
+	if (dialog_token != wpa_s->robust_av.dialog_token) {
+		wpa_printf(MSG_INFO,
+			   "MSCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
+			   dialog_token, wpa_s->robust_av.dialog_token);
+		return;
+	}
+
+	status_code = *buf;
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+		" status_code=%u", MAC2STR(src), status_code);
+	wpa_s->mscs_setup_done = status_code == WLAN_STATUS_SUCCESS;
+}
+
+
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+				 const u8 *ies, size_t ies_len)
+{
+	const u8 *mscs_desc_ie, *mscs_status;
+	u16 status;
+
+	/* Process optional MSCS Status subelement when MSCS IE is in
+	 * (Re)Association Response frame */
+	if (!ies || ies_len == 0 || !wpa_s->robust_av.valid_config)
+		return;
+
+	mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+	if (!mscs_desc_ie || mscs_desc_ie[1] <= 8)
+		return;
+
+	/* Subelements start after (ie_id(1) + ie_len(1) + ext_id(1) +
+	 * request type(1) + upc(2) + stream timeout(4) =) 10.
+	 */
+	mscs_status = get_ie(&mscs_desc_ie[10], mscs_desc_ie[1] - 8,
+			     MCSC_SUBELEM_STATUS);
+	if (!mscs_status || mscs_status[1] < 2)
+		return;
+
+	status = WPA_GET_LE16(mscs_status + 2);
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+		" status_code=%u", MAC2STR(bssid), status);
+	wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
+}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index b475730..b9e4162 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -237,6 +237,10 @@
 		if (wpa_s->disconnected)
 			retry = 0;
 
+		/* do not retry if operation is not supported */
+		if (ret == -EOPNOTSUPP)
+			retry = 0;
+
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 		wpas_notify_scan_done(wpa_s, 0);
 		if (wpa_s->wpa_state == WPA_SCANNING)
@@ -2187,6 +2191,60 @@
 }
 
 
+/* Minimum SNR required to achieve a certain bitrate. */
+struct minsnr_bitrate_entry {
+	int minsnr;
+	unsigned int bitrate; /* in Mbps */
+};
+
+/* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */
+static const int vht_mcs = 8;
+
+static const struct minsnr_bitrate_entry vht20_table[] = {
+	{ 0, 0 },
+	{ 2, 6500 },   /* HT20 MCS0 */
+	{ 5, 13000 },  /* HT20 MCS1 */
+	{ 9, 19500 },  /* HT20 MCS2 */
+	{ 11, 26000 }, /* HT20 MCS3 */
+	{ 15, 39000 }, /* HT20 MCS4 */
+	{ 18, 52000 }, /* HT20 MCS5 */
+	{ 20, 58500 }, /* HT20 MCS6 */
+	{ 25, 65000 }, /* HT20 MCS7 */
+	{ 29, 78000 }, /* VHT20 MCS8 */
+	{ -1, 78000 }  /* SNR > 29 */
+};
+
+static const struct minsnr_bitrate_entry vht40_table[] = {
+	{ 0, 0 },
+	{ 5, 13500 },   /* HT40 MCS0 */
+	{ 8, 27000 },   /* HT40 MCS1 */
+	{ 12, 40500 },  /* HT40 MCS2 */
+	{ 14, 54000 },  /* HT40 MCS3 */
+	{ 18, 81000 },  /* HT40 MCS4 */
+	{ 21, 108000 }, /* HT40 MCS5 */
+	{ 23, 121500 }, /* HT40 MCS6 */
+	{ 28, 135000 }, /* HT40 MCS7 */
+	{ 32, 162000 }, /* VHT40 MCS8 */
+	{ 34, 180000 }, /* VHT40 MCS9 */
+	{ -1, 180000 }  /* SNR > 34 */
+};
+
+static const struct minsnr_bitrate_entry vht80_table[] = {
+	{ 0, 0 },
+	{ 8, 29300 },   /* VHT80 MCS0 */
+	{ 11, 58500 },  /* VHT80 MCS1 */
+	{ 15, 87800 },  /* VHT80 MCS2 */
+	{ 17, 117000 }, /* VHT80 MCS3 */
+	{ 21, 175500 }, /* VHT80 MCS4 */
+	{ 24, 234000 }, /* VHT80 MCS5 */
+	{ 26, 263300 }, /* VHT80 MCS6 */
+	{ 31, 292500 }, /* VHT80 MCS7 */
+	{ 35, 351000 }, /* VHT80 MCS8 */
+	{ 37, 390000 }, /* VHT80 MCS9 */
+	{ -1, 390000 }  /* SNR > 37 */
+};
+
+
 static unsigned int interpolate_rate(int snr, int snr0, int snr1,
 				     int rate0, int rate1)
 {
@@ -2194,68 +2252,42 @@
 }
 
 
-#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
-	if (snr < (snr1)) \
-		return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
-
-static unsigned int max_ht20_rate(int snr, int vht)
+static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
+			     int snr, bool vht)
 {
-	if (snr < 0)
-		return 0;
-	INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */
-	INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */
-	INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */
-	INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */
-	INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */
-	INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */
-	INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */
-	INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */
-	if (!vht)
-		return 65000;
-	INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */
-	return 78000;
+	const struct minsnr_bitrate_entry *prev, *entry = table;
+
+	while ((entry->minsnr != -1) &&
+	       (snr >= entry->minsnr) &&
+	       (vht || entry - table <= vht_mcs))
+		entry++;
+	if (entry == table)
+		return entry->bitrate;
+	prev = entry - 1;
+	if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs))
+		return prev->bitrate;
+	return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate,
+				entry->bitrate);
 }
 
 
-static unsigned int max_ht40_rate(int snr, int vht)
+static unsigned int max_ht20_rate(int snr, bool vht)
 {
-	if (snr < 0)
-		return 0;
-	INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */
-	INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */
-	INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */
-	INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */
-	INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */
-	INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */
-	INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */
-	INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */
-	if (!vht)
-		return 135000;
-	INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */
-	INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */
-	return 180000;
+	return max_rate(vht20_table, snr, vht);
+}
+
+
+static unsigned int max_ht40_rate(int snr, bool vht)
+{
+	return max_rate(vht40_table, snr, vht);
 }
 
 
 static unsigned int max_vht80_rate(int snr)
 {
-	if (snr < 0)
-		return 0;
-	INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */
-	INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */
-	INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */
-	INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */
-	INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */
-	INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */
-	INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */
-	INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */
-	INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */
-	INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */
-	return 390000;
+	return max_rate(vht80_table, snr, 1);
 }
 
-#undef INTERPOLATE_RATE
-
 
 unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
 			      const u8 *ies, size_t ies_len, int rate,
@@ -2309,7 +2341,7 @@
 	if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
 		ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
 		if (ie) {
-			tmp = max_ht20_rate(snr, 0);
+			tmp = max_ht20_rate(snr, false);
 			if (tmp > est)
 				est = tmp;
 		}
@@ -2319,7 +2351,7 @@
 		ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
 		if (ie && ie[1] >= 2 &&
 		    (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
-			tmp = max_ht40_rate(snr, 0);
+			tmp = max_ht40_rate(snr, false);
 			if (tmp > est)
 				est = tmp;
 		}
@@ -2329,7 +2361,7 @@
 		/* Use +1 to assume VHT is always faster than HT */
 		ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
 		if (ie) {
-			tmp = max_ht20_rate(snr, 1) + 1;
+			tmp = max_ht20_rate(snr, true) + 1;
 			if (tmp > est)
 				est = tmp;
 
@@ -2337,7 +2369,7 @@
 			if (ie && ie[1] >= 2 &&
 			    (ie[3] &
 			     HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
-				tmp = max_ht40_rate(snr, 1) + 1;
+				tmp = max_ht40_rate(snr, true) + 1;
 				if (tmp > est)
 					est = tmp;
 			}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index d06f6e2..7fec1cd 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -85,16 +85,21 @@
 static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
 						 struct wpa_ssid *ssid,
 						 const u8 *bssid, int external,
-						 int reuse, int *ret_use_pt)
+						 int reuse, int *ret_use_pt,
+						 bool *ret_use_pk)
 {
 	struct wpabuf *buf;
 	size_t len;
 	const char *password;
 	struct wpa_bss *bss;
 	int use_pt = 0;
+	bool use_pk = false;
+	u8 rsnxe_capa = 0;
 
 	if (ret_use_pt)
 		*ret_use_pt = 0;
+	if (ret_use_pk)
+		*ret_use_pk = false;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	if (wpa_s->sae_commit_override) {
@@ -123,7 +128,8 @@
 	    os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
 		wpa_printf(MSG_DEBUG,
 			   "SAE: Reuse previously generated PWE on a retry with the same AP");
-		use_pt = wpa_s->sme.sae.tmp->h2e;
+		use_pt = wpa_s->sme.sae.h2e;
+		use_pk = wpa_s->sme.sae.pk;
 		goto reuse_data;
 	}
 	if (sme_set_sae_group(wpa_s) < 0) {
@@ -131,19 +137,37 @@
 		return NULL;
 	}
 
+	bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+	if (bss) {
+		const u8 *rsnxe;
+
+		rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+		if (rsnxe && rsnxe[1] >= 1)
+			rsnxe_capa = rsnxe[2];
+	}
+
 	if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
 		use_pt = 1;
+#ifdef CONFIG_SAE_PK
+	if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+	    ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+	    ((ssid->sae_password &&
+	      sae_pk_valid_password(ssid->sae_password)) ||
+	     (!ssid->sae_password && ssid->passphrase &&
+	      sae_pk_valid_password(ssid->passphrase)))) {
+		use_pt = 1;
+		use_pk = true;
+	}
+
+	if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) {
+		wpa_printf(MSG_DEBUG,
+			   "SAE: Cannot use PK with the selected AP");
+		return NULL;
+	}
+#endif /* CONFIG_SAE_PK */
 
 	if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
-		bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
-		if (bss) {
-			const u8 *rsnxe;
-
-			rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
-			if (rsnxe && rsnxe[1] >= 1)
-				use_pt = !!(rsnxe[2] &
-					    BIT(WLAN_RSNX_CAPAB_SAE_H2E));
-		}
+		use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
 
 		if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
 		    wpa_s->conf->sae_pwe != 3 &&
@@ -157,7 +181,7 @@
 	if (use_pt &&
 	    sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
 				  wpa_s->own_addr, bssid,
-				  wpa_s->sme.sae_rejected_groups) < 0)
+				  wpa_s->sme.sae_rejected_groups, NULL) < 0)
 		return NULL;
 	if (!use_pt &&
 	    sae_prepare_commit(wpa_s->own_addr, bssid,
@@ -167,8 +191,17 @@
 		wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
 		return NULL;
 	}
-	if (wpa_s->sme.sae.tmp)
+	if (wpa_s->sme.sae.tmp) {
 		os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
+		if (use_pt && use_pk)
+			wpa_s->sme.sae.pk = 1;
+#ifdef CONFIG_SAE_PK
+		os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
+			  ETH_ALEN);
+		os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN);
+		sae_pk_set_password(&wpa_s->sme.sae, password);
+#endif /* CONFIG_SAE_PK */
+	}
 
 reuse_data:
 	len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
@@ -179,8 +212,12 @@
 		return NULL;
 	if (!external) {
 		wpabuf_put_le16(buf, 1); /* Transaction seq# */
-		wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
-				WLAN_STATUS_SUCCESS);
+		if (use_pk)
+			wpabuf_put_le16(buf, WLAN_STATUS_SAE_PK);
+		else if (use_pt)
+			wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+		else
+			wpabuf_put_le16(buf,WLAN_STATUS_SUCCESS);
 	}
 	if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
 			     ssid->sae_password_id) < 0) {
@@ -189,6 +226,8 @@
 	}
 	if (ret_use_pt)
 		*ret_use_pt = use_pt;
+	if (ret_use_pk)
+		*ret_use_pk = use_pk;
 
 	return buf;
 }
@@ -716,7 +755,8 @@
 		if (start)
 			resp = sme_auth_build_sae_commit(wpa_s, ssid,
 							 bss->bssid, 0,
-							 start == 2, NULL);
+							 start == 2, NULL,
+							 NULL);
 		else
 			resp = sme_auth_build_sae_confirm(wpa_s, 0);
 		if (resp == NULL) {
@@ -1008,8 +1048,11 @@
 {
 	struct wpabuf *resp, *buf;
 	int use_pt;
+	bool use_pk;
+	u16 status;
 
-	resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt);
+	resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt,
+					 &use_pk);
 	if (!resp) {
 		wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
 		return -1;
@@ -1023,10 +1066,14 @@
 	}
 
 	wpa_s->sme.seq_num++;
+	if (use_pk)
+		status = WLAN_STATUS_SAE_PK;
+	else if (use_pt)
+		status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+	else
+		status = WLAN_STATUS_SUCCESS;
 	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
-				    bssid, 1, wpa_s->sme.seq_num,
-				    use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
-				    WLAN_STATUS_SUCCESS);
+				    bssid, 1, wpa_s->sme.seq_num, status);
 	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
 	wpabuf_free(resp);
 	wpabuf_free(buf);
@@ -1223,8 +1270,7 @@
 		wpabuf_free(wpa_s->sme.sae_token);
 		token_pos = data + sizeof(le16);
 		token_len = len - sizeof(le16);
-		if (wpa_s->sme.sae.tmp)
-			h2e = wpa_s->sme.sae.tmp->h2e;
+		h2e = wpa_s->sme.sae.h2e;
 		if (h2e) {
 			if (token_len < 3) {
 				wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1287,7 +1333,8 @@
 	}
 
 	if (status_code != WLAN_STATUS_SUCCESS &&
-	    status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+	    status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT &&
+	    status_code != WLAN_STATUS_SAE_PK)
 		return -1;
 
 	if (auth_transaction == 1) {
@@ -1304,24 +1351,30 @@
 				   "SAE: Ignore commit message while waiting for confirm");
 			return 0;
 		}
-		if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e &&
-		    status_code == WLAN_STATUS_SUCCESS) {
+		if (wpa_s->sme.sae.h2e && status_code == WLAN_STATUS_SUCCESS) {
 			wpa_printf(MSG_DEBUG,
 				   "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
 			return -1;
 		}
-		if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->h2e &&
+		if ((!wpa_s->sme.sae.h2e || wpa_s->sme.sae.pk) &&
 		    status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
 			wpa_printf(MSG_DEBUG,
 				   "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
 			return -1;
 		}
+		if (!wpa_s->sme.sae.pk &&
+		    status_code == WLAN_STATUS_SAE_PK) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: Unexpected use of status code for PK in SAE commit when PK was not expected");
+			return -1;
+		}
 
 		if (groups && groups[0] <= 0)
 			groups = NULL;
 		res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
 				       groups, status_code ==
-				       WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+				       WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+				       status_code == WLAN_STATUS_SAE_PK);
 		if (res == SAE_SILENTLY_DISCARD) {
 			wpa_printf(MSG_DEBUG,
 				   "SAE: Drop commit message due to reflection attack");
@@ -1827,6 +1880,42 @@
 pfs_fail:
 #endif /* CONFIG_DPP2 */
 
+	wpa_s->mscs_setup_done = false;
+	if (wpa_s->current_bss && wpa_s->robust_av.valid_config) {
+		struct wpabuf *mscs_ie;
+		size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len;
+
+		if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS))
+			goto mscs_fail;
+
+		buf_len = 3 +	/* MSCS descriptor IE header */
+			  1 +	/* Request type */
+			  2 +	/* User priority control */
+			  4 +	/* Stream timeout */
+			  3 +	/* TCLAS Mask IE header */
+			  wpa_s->robust_av.frame_classifier_len;
+		mscs_ie = wpabuf_alloc(buf_len);
+		if (!mscs_ie) {
+			wpa_printf(MSG_INFO,
+				   "MSCS: Failed to allocate MSCS IE");
+			goto mscs_fail;
+		}
+
+		wpa_ie_len = &wpa_s->sme.assoc_req_ie_len;
+		max_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+		wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+		if ((*wpa_ie_len + wpabuf_len(mscs_ie)) <= max_ie_len) {
+			wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
+			mscs_ie_len = wpabuf_len(mscs_ie);
+			os_memcpy(wpa_s->sme.assoc_req_ie + *wpa_ie_len,
+				  wpabuf_head(mscs_ie), mscs_ie_len);
+			*wpa_ie_len += mscs_ie_len;
+		}
+
+		wpabuf_free(mscs_ie);
+	}
+mscs_fail:
+
 	if (ssid && ssid->multi_ap_backhaul_sta) {
 		size_t multi_ap_ie_len;
 
@@ -2573,6 +2662,16 @@
 			return;
 		}
 
+#ifdef CONFIG_TESTING_OPTIONS
+		if (wpa_s->oci_freq_override_saquery_req) {
+			wpa_printf(MSG_INFO,
+				   "TEST: Override SA Query Request OCI frequency %d -> %d MHz",
+				   ci.frequency,
+				   wpa_s->oci_freq_override_saquery_req);
+			ci.frequency = wpa_s->oci_freq_override_saquery_req;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 		if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
 			return;
 
@@ -2727,6 +2826,16 @@
 			return;
 		}
 
+#ifdef CONFIG_TESTING_OPTIONS
+		if (wpa_s->oci_freq_override_saquery_resp) {
+			wpa_printf(MSG_INFO,
+				   "TEST: Override SA Query Response OCI frequency %d -> %d MHz",
+				   ci.frequency,
+				   wpa_s->oci_freq_override_saquery_resp);
+			ci.frequency = wpa_s->oci_freq_override_saquery_resp;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 		if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
 			return;
 
@@ -2806,8 +2915,11 @@
 
 		if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
 					 channel_width_to_int(ci.chanwidth),
-					 ci.seg1_idx) != 0) {
-			wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+					 ci.seg1_idx) != OCI_SUCCESS) {
+			wpa_msg(wpa_s, MSG_INFO, OCV_FAILURE "addr=" MACSTR
+				" frame=saquery%s error=%s",
+				MAC2STR(sa), data[0] == WLAN_SA_QUERY_REQUEST ?
+				"req" : "resp", ocv_errorstr);
 			return;
 		}
 	}
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 2e09102..c706a4e 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -121,6 +121,15 @@
 			os_free(wnmtfs_ie);
 			return -1;
 		}
+#ifdef CONFIG_TESTING_OPTIONS
+		if (wpa_s->oci_freq_override_wnm_sleep) {
+			wpa_printf(MSG_INFO,
+				   "TEST: Override OCI KDE frequency %d -> %d MHz",
+				   ci.frequency,
+				   wpa_s->oci_freq_override_wnm_sleep);
+			ci.frequency = wpa_s->oci_freq_override_wnm_sleep;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 		oci_ie_len = OCV_OCI_EXTENDED_LEN;
 		oci_ie = os_zalloc(oci_ie_len);
@@ -374,8 +383,9 @@
 
 		if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
 					 channel_width_to_int(ci.chanwidth),
-					 ci.seg1_idx) != 0) {
-			wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr);
+					 ci.seg1_idx) != OCI_SUCCESS) {
+			wpa_msg(wpa_s, MSG_WARNING, "WNM: OCV failed: %s",
+				ocv_errorstr);
 			return;
 		}
 	}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6a2d2c3..51c9642 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2994,6 +2994,13 @@
 }
 
 
+static int wpa_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
 				     char *argv[])
 {
@@ -3056,9 +3063,98 @@
 	return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
 }
 
+
+#ifdef CONFIG_DPP2
+
+static int wpa_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
+				 char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
+}
+
+#endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
 
 
+static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd)
+{
+	char buf[512], *pos, *bssid, *freq, *level, *flags, *ssid;
+	size_t len;
+	int ret, id = -1;
+
+	if (!ctrl_conn)
+		return -1;
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+			       wpa_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+
+	buf[len] = '\0';
+	if (os_memcmp(buf, "FAIL", 4) == 0)
+		return -1;
+
+	pos = buf;
+	while (*pos != '\0') {
+		if (str_starts(pos, "id="))
+			id = atoi(pos + 3);
+		if (str_starts(pos, "bssid="))
+			bssid = pos + 6;
+		if (str_starts(pos, "freq="))
+			freq = pos + 5;
+		if (str_starts(pos, "level="))
+			level = pos + 6;
+		if (str_starts(pos, "flags="))
+			flags = pos + 6;
+		if (str_starts(pos, "ssid="))
+			ssid = pos + 5;
+
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		*pos++ = '\0';
+	}
+	if (id != -1)
+		printf("%s\t%s\t%s\t%s\t%s\n", bssid, freq, level, flags, ssid);
+	return id;
+}
+
+
+static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[64];
+	int id = -1;
+	unsigned int mask;
+
+	printf("bssid / frequency / signal level / flags / ssid\n");
+
+	mask = WPA_BSS_MASK_ID | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_FREQ |
+		WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_SSID;
+	do {
+		if (id < 0)
+			os_snprintf(cmd, sizeof(cmd), "BSS FIRST MASK=0x%x",
+				    mask);
+		else
+			os_snprintf(cmd, sizeof(cmd), "BSS NEXT-%d MASK=0x%x",
+				    id, mask);
+		id = wpa_ctrl_command_bss(ctrl, cmd);
+	} while (id >= 0);
+
+	return 0;
+}
+
+
 enum wpa_cli_cmd_flags {
 	cli_cmd_flag_none		= 0x00,
 	cli_cmd_flag_sensitive		= 0x01
@@ -3692,6 +3788,9 @@
 	{ "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL,
 	  cli_cmd_flag_none,
 	  "<id> = show DPP bootstrap information" },
+	{ "dpp_bootstrap_set", wpa_cli_cmd_dpp_bootstrap_set, NULL,
+	  cli_cmd_flag_none,
+	  "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
 	{ "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none,
 	  "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
 	{ "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none,
@@ -3717,7 +3816,17 @@
 	{ "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL,
 	  cli_cmd_flag_none,
 	  "*|<id> = remove DPP pkex information" },
+#ifdef CONFIG_DPP2
+	{ "dpp_chirp", wpa_cli_cmd_dpp_chirp, NULL,
+	  cli_cmd_flag_none,
+	  "own=<BI ID> iter=<count> = start DPP chirp" },
+	{ "dpp_stop_chirp", wpa_cli_cmd_dpp_stop_chirp, NULL,
+	  cli_cmd_flag_none,
+	  "= stop DPP chirp" },
+#endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
+	{ "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
+	  "= list all BSS entries (scan results)" },
 	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/.gitignore b/wpa_supplicant/wpa_gui-qt4/icons/.gitignore
new file mode 100644
index 0000000..8d772cc
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons/.gitignore
@@ -0,0 +1,2 @@
+hicolor
+pixmaps
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index a01a4e5..67fb426 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -804,7 +804,22 @@
 
 #ifdef CONFIG_BGSCAN
 
-static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->bgscan_ssid) {
+		bgscan_deinit(wpa_s);
+		wpa_s->bgscan_ssid = NULL;
+	}
+}
+
+
+/**
+ * wpa_supplicant_reset_bgscan - Reset the bgscan for the current SSID.
+ * @wpa_s: Pointer to the wpa_supplicant data
+ *
+ * Stop, start, or reconfigure the scan parameters depending on the method.
+ */
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s)
 {
 	const char *name;
 
@@ -812,12 +827,12 @@
 		name = wpa_s->current_ssid->bgscan;
 	else
 		name = wpa_s->conf->bgscan;
-	if (name == NULL || name[0] == '\0')
+	if (!name || name[0] == '\0') {
+		wpa_supplicant_stop_bgscan(wpa_s);
 		return;
+	}
 	if (wpas_driver_bss_selection(wpa_s))
 		return;
-	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
-		return;
 #ifdef CONFIG_P2P
 	if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
 		return;
@@ -847,15 +862,6 @@
 		wpa_s->bgscan_ssid = NULL;
 }
 
-
-static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->bgscan_ssid != NULL) {
-		bgscan_deinit(wpa_s);
-		wpa_s->bgscan_ssid = NULL;
-	}
-}
-
 #endif /* CONFIG_BGSCAN */
 
 
@@ -979,8 +985,7 @@
 			fils_hlp_sent ? " FILS_HLP_SENT" : "");
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 		wpas_clear_temp_disabled(wpa_s, ssid, 1);
-		wpa_blacklist_clear(wpa_s);
-		wpa_s->extra_blacklist_count = 0;
+		wpa_s->consecutive_conn_failures = 0;
 		wpa_s->new_connection = 0;
 		wpa_drv_set_operstate(wpa_s, 1);
 #ifndef IEEE8021X_EAPOL
@@ -1012,8 +1017,8 @@
 	wpa_s->wpa_state = state;
 
 #ifdef CONFIG_BGSCAN
-	if (state == WPA_COMPLETED)
-		wpa_supplicant_start_bgscan(wpa_s);
+	if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
+		wpa_supplicant_reset_bgscan(wpa_s);
 	else if (state < WPA_ASSOCIATED)
 		wpa_supplicant_stop_bgscan(wpa_s);
 #endif /* CONFIG_BGSCAN */
@@ -1185,6 +1190,7 @@
 		wpa_s->reassociate = 1;
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 	}
+	wpa_blacklist_clear(wpa_s);
 	wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
 	return 0;
 }
@@ -1640,9 +1646,26 @@
 	if (ssid->sae_password_id && sae_pwe != 3)
 		sae_pwe = 1;
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+#ifdef CONFIG_SAE_PK
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
+			 wpa_key_mgmt_sae(ssid->key_mgmt) &&
+			 ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+			 ((ssid->sae_password &&
+			   sae_pk_valid_password(ssid->sae_password)) ||
+			  (!ssid->sae_password && ssid->passphrase &&
+			   sae_pk_valid_password(ssid->passphrase))));
+#endif /* CONFIG_SAE_PK */
 #ifdef CONFIG_TESTING_OPTIONS
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
 			 wpa_s->ft_rsnxe_used);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
+			 wpa_s->oci_freq_override_eapol);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+			 wpa_s->oci_freq_override_eapol_g2);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+			 wpa_s->oci_freq_override_ft_assoc);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+			 wpa_s->oci_freq_override_fils_assoc);
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	/* Extended Key ID is only supported in infrastructure BSS so far */
@@ -1883,6 +1906,9 @@
 			*pos |= 0x01;
 #endif /* CONFIG_FILS */
 		break;
+	case 10: /* Bits 80-87 */
+		*pos |= 0x20; /* Bit 85 - Mirrored SCS */
+		break;
 	}
 }
 
@@ -1890,7 +1916,7 @@
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
 {
 	u8 *pos = buf;
-	u8 len = 10, i;
+	u8 len = 11, i;
 
 	if (len < wpa_s->extended_capa_len)
 		len = wpa_s->extended_capa_len;
@@ -2060,7 +2086,9 @@
 	if (!password)
 		password = ssid->passphrase;
 
-	if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password ||
+	if (!password ||
+	    (conf->sae_pwe == 0 && !ssid->sae_password_id &&
+	     !sae_pk_valid_password(password)) ||
 	    conf->sae_pwe == 3) {
 		/* PT derivation not needed */
 		sae_deinit_pt(ssid->pt);
@@ -3171,6 +3199,39 @@
 		wpa_ie_len += wpa_s->rsnxe_len;
 	}
 
+	if (bss && wpa_s->robust_av.valid_config) {
+		struct wpabuf *mscs_ie;
+		size_t mscs_ie_len, buf_len;
+
+		if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS))
+			goto mscs_fail;
+
+		buf_len = 3 +	/* MSCS descriptor IE header */
+			  1 +	/* Request type */
+			  2 +	/* User priority control */
+			  4 +	/* Stream timeout */
+			  3 +	/* TCLAS Mask IE header */
+			  wpa_s->robust_av.frame_classifier_len;
+		mscs_ie = wpabuf_alloc(buf_len);
+		if (!mscs_ie) {
+			wpa_printf(MSG_INFO,
+				   "MSCS: Failed to allocate MSCS IE");
+			goto mscs_fail;
+		}
+
+		wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+		if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
+			wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
+			mscs_ie_len = wpabuf_len(mscs_ie);
+			os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
+				  mscs_ie_len);
+			wpa_ie_len += mscs_ie_len;
+		}
+
+		wpabuf_free(mscs_ie);
+	}
+mscs_fail:
+
 	if (ssid->multi_ap_backhaul_sta) {
 		size_t multi_ap_ie_len;
 
@@ -3485,6 +3546,7 @@
 	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
 	wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
 	wpa_s->rsnxe_len = 0;
+	wpa_s->mscs_setup_done = false;
 
 	wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
 	if (!wpa_ie) {
@@ -4062,6 +4124,52 @@
 
 
 /**
+ * wpa_supplicant_remove_all_networks - Remove all configured networks
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: 0 on success (errors are currently ignored)
+ *
+ * This function performs the following operations:
+ * 1. Remove all networks.
+ * 2. Send network removal notifications.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	if (wpa_s->sched_scanning)
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+
+	eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+		wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+		wpa_sm_set_config(wpa_s->wpa, NULL);
+		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+			wpa_s->own_disconnect_req = 1;
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	}
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		struct wpa_ssid *remove_ssid = ssid;
+		int id;
+
+		id = ssid->id;
+		ssid = ssid->next;
+		if (wpa_s->last_ssid == remove_ssid)
+			wpa_s->last_ssid = NULL;
+		wpas_notify_network_removed(wpa_s, remove_ssid);
+		wpa_config_remove_network(wpa_s->conf, id);
+	}
+	return 0;
+}
+
+
+/**
  * wpa_supplicant_enable_network - Mark a configured network as enabled
  * @wpa_s: wpa_supplicant structure for a network interface
  * @ssid: wpa_ssid structure for a configured network or %NULL
@@ -4851,6 +4959,65 @@
 }
 
 
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+					const char *bridge_ifname)
+{
+	if (wpa_s->wpa_state > WPA_SCANNING)
+		return -EBUSY;
+
+	if (bridge_ifname &&
+	    os_strlen(bridge_ifname) >= sizeof(wpa_s->bridge_ifname))
+		return -EINVAL;
+
+	if (!bridge_ifname)
+		bridge_ifname = "";
+
+	if (os_strcmp(wpa_s->bridge_ifname, bridge_ifname) == 0)
+		return 0;
+
+	if (wpa_s->l2_br) {
+		l2_packet_deinit(wpa_s->l2_br);
+		wpa_s->l2_br = NULL;
+	}
+
+	os_strlcpy(wpa_s->bridge_ifname, bridge_ifname,
+		   sizeof(wpa_s->bridge_ifname));
+
+	if (wpa_s->bridge_ifname[0]) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Receiving packets from bridge interface '%s'",
+			wpa_s->bridge_ifname);
+		wpa_s->l2_br = l2_packet_init_bridge(
+			wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+			ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
+		if (!wpa_s->l2_br) {
+			wpa_msg(wpa_s, MSG_ERROR,
+				"Failed to open l2_packet connection for the bridge interface '%s'",
+				wpa_s->bridge_ifname);
+			goto fail;
+		}
+	}
+
+#ifdef CONFIG_TDLS
+	if (!wpa_s->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
+		goto fail;
+#endif /* CONFIG_TDLS */
+
+	return 0;
+fail:
+	wpa_s->bridge_ifname[0] = 0;
+	if (wpa_s->l2_br) {
+		l2_packet_deinit(wpa_s->l2_br);
+		wpa_s->l2_br = NULL;
+	}
+#ifdef CONFIG_TDLS
+	if (!wpa_s->p2p_mgmt)
+		wpa_tdls_init(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+	return -EIO;
+}
+
+
 /**
  * wpa_supplicant_driver_init - Initialize driver interface parameters
  * @wpa_s: Pointer to wpa_supplicant data
@@ -6034,6 +6201,8 @@
 	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
 	if (wpa_s->drv_priv == NULL) {
 		const char *pos;
+		int level = MSG_ERROR;
+
 		pos = driver ? os_strchr(driver, ',') : NULL;
 		if (pos) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
@@ -6041,8 +6210,12 @@
 			driver = pos + 1;
 			goto next_driver;
 		}
-		wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
-			"interface");
+
+#ifdef CONFIG_MATCH_IFACE
+		if (wpa_s->matched == WPA_IFACE_MATCHED_NULL)
+			level = MSG_DEBUG;
+#endif /* CONFIG_MATCH_IFACE */
+		wpa_msg(wpa_s, level, "Failed to initialize driver interface");
 		return -1;
 	}
 	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
@@ -6187,6 +6360,9 @@
 		return -1;
 	}
 	os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+#ifdef CONFIG_MATCH_IFACE
+	wpa_s->matched = iface->matched;
+#endif /* CONFIG_MATCH_IFACE */
 
 	if (iface->bridge_ifname) {
 		if (os_strlen(iface->bridge_ifname) >=
@@ -6578,6 +6754,10 @@
 			if (!iface)
 				return NULL;
 			*iface = *miface;
+			if (!miface->ifname)
+				iface->matched = WPA_IFACE_MATCHED_NULL;
+			else
+				iface->matched = WPA_IFACE_MATCHED;
 			iface->ifname = ifname;
 			return iface;
 		}
@@ -6612,8 +6792,6 @@
 		if (iface) {
 			wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
 			os_free(iface);
-			if (wpa_s)
-				wpa_s->matched = 1;
 		}
 	}
 
@@ -7143,6 +7321,18 @@
 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
 		wpa_supplicant_set_default_scan_ies(wpa_s);
 
+#ifdef CONFIG_BGSCAN
+	/*
+	 * We default to global bgscan parameters only when per-network bgscan
+	 * parameters aren't set. Only bother resetting bgscan parameters if
+	 * this is the case.
+	 */
+	if ((wpa_s->conf->changed_parameters & CFG_CHANGED_BGSCAN) &&
+	    wpa_s->current_ssid && !wpa_s->current_ssid->bgscan &&
+	    wpa_s->wpa_state == WPA_COMPLETED)
+		wpa_supplicant_reset_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
 #ifdef CONFIG_WPS
 	wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
@@ -7183,7 +7373,7 @@
 			continue;
 		if (bss->ssid_len == cbss->ssid_len &&
 		    os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
-		    wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+		    !wpa_blacklist_is_blacklisted(wpa_s, bss->bssid)) {
 			add_freq(freqs, &num_freqs, bss->freq);
 			if (num_freqs == max_freqs)
 				break;
@@ -7237,10 +7427,6 @@
 	/*
 	 * Add the failed BSSID into the blacklist and speed up next scan
 	 * attempt if there could be other APs that could accept association.
-	 * The current blacklist count indicates how many times we have tried
-	 * connecting to this AP and multiple attempts mean that other APs are
-	 * either not available or has already been tried, so that we can start
-	 * increasing the delay here to avoid constant scanning.
 	 */
 	count = wpa_blacklist_add(wpa_s, bssid);
 	if (count == 1 && wpa_s->current_bss) {
@@ -7265,19 +7451,19 @@
 		}
 	}
 
-	/*
-	 * Add previous failure count in case the temporary blacklist was
-	 * cleared due to no other BSSes being available.
-	 */
-	count += wpa_s->extra_blacklist_count;
+	wpa_s->consecutive_conn_failures++;
 
-	if (count > 3 && wpa_s->current_ssid) {
+	if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
 		wpa_printf(MSG_DEBUG, "Continuous association failures - "
 			   "consider temporary network disabling");
 		wpas_auth_failed(wpa_s, "CONN_FAILED");
 	}
-
-	switch (count) {
+	/*
+	 * Multiple consecutive connection failures mean that other APs are
+	 * either not available or have already been tried, so we can start
+	 * increasing the delay here to avoid constant scanning.
+	 */
+	switch (wpa_s->consecutive_conn_failures) {
 	case 1:
 		timeout = 100;
 		break;
@@ -7295,8 +7481,9 @@
 		break;
 	}
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
-		"ms", count, timeout);
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Consecutive connection failures: %d --> request scan in %d ms",
+		wpa_s->consecutive_conn_failures, timeout);
 
 	/*
 	 * TODO: if more than one possible AP is available in scan results,
@@ -7695,7 +7882,6 @@
 	wpa_s->normal_scans = 0;
 	wpa_s->scan_req = NORMAL_SCAN_REQ;
 	wpa_supplicant_reinit_autoscan(wpa_s);
-	wpa_s->extra_blacklist_count = 0;
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
 	wpa_s->last_owe_group = 0;
@@ -7961,7 +8147,7 @@
 			  ETH_ALEN);
 		num_bssid++;
 	}
-	ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+	ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
 	os_free(bssids);
 	return ret;
 }
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 3b90567..c10dd73 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -843,6 +843,16 @@
 # bssid: BSSID (optional); if set, this network block is used only when
 #	associating with the AP using the configured BSSID
 #
+# ignore_broadcast_ssid: SSID broadcast behavior
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+#     broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+#     with some clients that do not support empty SSID) and ignore probe
+#     requests for broadcast SSID
+#
 # priority: priority group (integer)
 # By default, all networks will get same priority group (0). If some of the
 # networks are more desirable, this field can be used to change the order in
@@ -1472,6 +1482,58 @@
 # 2: do not allow PFS to be used
 #dpp_pfs=0
 
+# Whether Beacon protection is enabled
+# This depends on management frame protection (ieee80211w) being enabled.
+#beacon_prot=0
+
+# OWE DH Group
+# 0: use default (19) first and then try all supported groups one by one if AP
+#   rejects the selected group
+# 1-65535: DH Group to use for OWE
+# Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are
+# currently supported.
+#owe_group=0
+
+# OWE-only mode (disable transition mode)
+# 0: enable transition mode (allow connection to either OWE or open BSS)
+# 1 = disable transition mode (allow connection only with OWE)
+#owe_only=0
+
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all
+# OWE groups. This was supposed to change to SHA384 for group 20 and
+# SHA512 for group 21. This parameter can be used to enable older
+# behavior mainly for testing purposes. There is no impact to group 19
+# behavior, but if enabled, this will make group 20 and 21 cases use
+# SHA256-based PTK derivation which will not work with the updated
+# OWE implementation on the AP side.
+#owe_ptk_workaround=0
+
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode
+# in their network profiles when the network has completed transition
+# steps, i.e., once sufficiently large number of APs in the ESS have
+# been updated to support the more secure alternative. When this
+# indication is used, the stations are expected to automatically
+# disable transition mode and less secure security options. This
+# includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK
+#	and only allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require
+#	OWE)
+
+# SAE-PK mode
+# 0: automatic SAE/SAE-PK selection based on password; enable
+#    transition mode (allow SAE authentication without SAE-PK)
+# 1: SAE-PK only (disable transition mode; allow SAE authentication
+#    only with SAE-PK)
+# 2: disable SAE-PK (allow SAE authentication only without SAE-PK)
+#sae_pk=0
+
 # MAC address policy
 # 0 = use permanent MAC address
 # 1 = use random MAC address for each ESS connection
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7c792b3..3fcd95a 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -121,6 +121,18 @@
 	 * interface that is not a network interface.
 	 */
 	int p2p_mgmt;
+
+#ifdef CONFIG_MATCH_IFACE
+	/**
+	 * matched - Interface was matched rather than specified
+	 *
+	 */
+	enum {
+		WPA_IFACE_NOT_MATCHED,
+		WPA_IFACE_MATCHED_NULL,
+		WPA_IFACE_MATCHED
+	} matched;
+#endif /* CONFIG_MATCH_IFACE */
 };
 
 /**
@@ -491,6 +503,17 @@
 	int scan_level;
 };
 
+struct robust_av_data {
+	u8 dialog_token;
+	enum scs_request_type request_type;
+	u8 up_bitmap;
+	u8 up_limit;
+	u32 stream_timeout;
+	u8 frame_classifier[48];
+	size_t frame_classifier_len;
+	bool valid_config;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -643,17 +666,8 @@
 
 	struct wpa_blacklist *blacklist;
 
-	/**
-	 * extra_blacklist_count - Sum of blacklist counts after last connection
-	 *
-	 * This variable is used to maintain a count of temporary blacklisting
-	 * failures (maximum number for any BSS) over blacklist clear
-	 * operations. This is needed for figuring out whether there has been
-	 * failures prior to the last blacklist clear operation which happens
-	 * whenever no other not-blacklisted BSS candidates are available. This
-	 * gets cleared whenever a connection has been established successfully.
-	 */
-	int extra_blacklist_count;
+	/* Number of connection failures since last successful connection */
+	unsigned int consecutive_conn_failures;
 
 	/**
 	 * scan_req - Type of the scan request
@@ -1157,6 +1171,13 @@
 	struct wpabuf *rsnxe_override_assoc;
 	struct wpabuf *rsnxe_override_eapol;
 	struct dl_list drv_signal_override;
+	unsigned int oci_freq_override_eapol;
+	unsigned int oci_freq_override_saquery_req;
+	unsigned int oci_freq_override_saquery_resp;
+	unsigned int oci_freq_override_eapol_g2;
+	unsigned int oci_freq_override_ft_assoc;
+	unsigned int oci_freq_override_fils_assoc;
+	unsigned int oci_freq_override_wnm_sleep;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1282,10 +1303,10 @@
 	unsigned int dpp_resp_retry_time;
 	u8 dpp_last_ssid[SSID_MAX_LEN];
 	size_t dpp_last_ssid_len;
+	bool dpp_conf_backup_received;
 #ifdef CONFIG_DPP2
 	struct dpp_pfs *dpp_pfs;
 	int dpp_pfs_fallback;
-	struct wpabuf *dpp_reconfig_announcement;
 	struct wpabuf *dpp_presence_announcement;
 	struct dpp_bootstrap_info *dpp_chirp_bi;
 	int dpp_chirp_freq;
@@ -1296,6 +1317,7 @@
 	int dpp_chirp_listen;
 	struct wpa_ssid *dpp_reconfig_ssid;
 	int dpp_reconfig_ssid_id;
+	struct dpp_reconfig_id *dpp_reconfig_id;
 #endif /* CONFIG_DPP2 */
 #ifdef CONFIG_TESTING_OPTIONS
 	char *dpp_config_obj_override;
@@ -1315,6 +1337,8 @@
 	unsigned int multi_ap_ie:1;
 	unsigned int multi_ap_backhaul:1;
 	unsigned int multi_ap_fronthaul:1;
+	struct robust_av_data robust_av;
+	bool mscs_setup_done;
 };
 
 
@@ -1338,6 +1362,8 @@
 const char * wpa_supplicant_state_txt(enum wpa_states state);
 int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+					const char *bridge_ifname);
 int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 			      struct wpa_bss *bss, struct wpa_ssid *ssid,
 			      u8 *wpa_ie, size_t *wpa_ie_len);
@@ -1363,6 +1389,7 @@
 
 struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
 				   struct wpa_ssid *ssid);
 void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1450,6 +1477,7 @@
 void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
 void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
 void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx);
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s);
 
 
 /* MBO functions */
@@ -1542,6 +1570,9 @@
 int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
 					struct channel_list_changed *info);
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+					   struct wpa_bss *current_bss,
+					   struct wpa_bss *seleceted);
 
 /* eap_register.c */
 int eap_register_methods(void);
@@ -1633,4 +1664,13 @@
 
 void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
 
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s);
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+				      struct wpabuf *buf);
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+				       const u8 *src, const u8 *buf,
+				       size_t len);
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+				 const u8 *ies, size_t ies_len);
+
 #endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index fce7e5e..7a558f3 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -6,3 +6,4 @@
 pmf=1
 p2p_add_cli_chan=1
 oce=1
+sae_pwe=2
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 6bd271e..a9a66ba 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -575,7 +575,8 @@
 				    const u8 *bssid, const u8 *pmkid,
 				    const u8 *fils_cache_id,
 				    const u8 *pmk, size_t pmk_len,
-				    u32 pmk_lifetime, u8 pmk_reauth_threshold)
+				    u32 pmk_lifetime, u8 pmk_reauth_threshold,
+				    int akmp)
 {
 	struct wpa_supplicant *wpa_s = _wpa_s;
 	struct wpa_ssid *ssid;
@@ -583,9 +584,22 @@
 
 	os_memset(&params, 0, sizeof(params));
 	ssid = wpas_get_network_ctx(wpa_s, network_ctx);
-	if (ssid)
+	if (ssid) {
 		wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
 			MAC2STR(bssid), ssid->id);
+		if ((akmp == WPA_KEY_MGMT_FT_IEEE8021X ||
+		     akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+		    !ssid->ft_eap_pmksa_caching) {
+			/* Since we will not be using PMKSA caching for FT-EAP
+			 * within wpa_supplicant to avoid known interop issues
+			 * with APs, do not add this PMKID to the driver either
+			 * so that we won't be hitting those interop issues
+			 * with driver-based RSNE generation. */
+			wpa_printf(MSG_DEBUG,
+				   "FT: Do not add PMKID entry to the driver since FT-EAP PMKSA caching is not enabled in configuration");
+			return 0;
+		}
+	}
 	if (ssid && fils_cache_id) {
 		params.ssid = ssid->ssid;
 		params.ssid_len = ssid->ssid_len;
@@ -1268,6 +1282,7 @@
 	if (!ssid)
 		return;
 
+#ifdef CONFIG_SAE
 	if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
 	    wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
 	    (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
@@ -1279,6 +1294,24 @@
 		changed = 1;
 	}
 
+	if ((bitmap & TRANSITION_DISABLE_SAE_PK) &&
+	    wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+#ifdef CONFIG_SME
+	    wpa_s->sme.sae.state == SAE_ACCEPTED &&
+	    wpa_s->sme.sae.pk &&
+#endif /* CONFIG_SME */
+	    (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+	    (ssid->sae_pk != SAE_PK_MODE_ONLY ||
+	     ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+	     (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+		wpa_printf(MSG_DEBUG,
+			   "SAE-PK: SAE authentication without PK disabled based on AP notification");
+		disable_wpa_wpa2(ssid);
+		ssid->sae_pk = SAE_PK_MODE_ONLY;
+		changed = 1;
+	}
+#endif /* CONFIG_SAE */
+
 	if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) &&
 	    wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
 	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X |
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index 4e37591..1c136f7 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -59,6 +59,23 @@
 	    wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0)
 		goto fail;
 
+	wpa_blacklist_clear(&wpa_s);
+
+	if (wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
+	    wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
+	    wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0 ||
+	    wpa_blacklist_add(&wpa_s, (u8 *) "444444") < 0 ||
+	    !wpa_blacklist_is_blacklisted(&wpa_s, (u8 *) "111111") ||
+	    wpa_blacklist_del(&wpa_s, (u8 *) "111111") < 0 ||
+	    wpa_blacklist_is_blacklisted(&wpa_s, (u8 *) "111111") ||
+	    wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0)
+		goto fail;
+
+	wpa_blacklist_update(&wpa_s);
+
+	if (!wpa_blacklist_is_blacklisted(&wpa_s, (u8 *) "111111"))
+		goto fail;
+
 	ret = 0;
 fail:
 	wpa_blacklist_clear(&wpa_s);
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 9f68b22..47d85dc 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -720,7 +720,7 @@
 	wpas_notify_wps_event_success(wpa_s);
 	if (wpa_s->current_ssid)
 		wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
-	wpa_s->extra_blacklist_count = 0;
+	wpa_s->consecutive_conn_failures = 0;
 
 	/*
 	 * Enable the networks disabled during wpas_wps_reassoc after 10