[wpa_supplicant] Cumulative patch from commit 59e9794c7

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

BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from Open source

59e9794c7 QCA vendor attribute to configure Punctured Preamble Rx in HE cap
875d7be38 QCA vendor attribute to disable data and management frame Tx
ecb7590f3 QCA vendor attribute to configure RU 242 tone for data Tx
8d2329712 QCA vendor attribute to configure BSS max idle period
dc72854fe Fix handle_auth_cb() message length check regression
f03580e31 Restore permanent MAC address on the FLUSH command
976c3c161 DPP2: Accept Config Result before GAS response TX status
6518c72b0 Multi-AP: Fix backhaul SSID printing condition
1ba8a315c Avoid use of C++ keyword in a header file
10502ad59 radiotap: Fix compiler issues with packed structures
0dee287c8 EAP server: Extend EAP-TLS Commitment Message use to PEAP and EAP-TTLS
fae4eafe4 EAP-TTLS peer: Handle Commitment Message for TLS 1.3
155125b02 EAP-TLS peer: Handle Commitment Message for TLS 1.3
3a457509d EAP: Extend Session-Id derivation with TLS 1.3 to PEAP and EAP-TTLS
647db6a6b EAP-TTLS: Key derivation per draft-ietf-emu-tls-eap-types-00
c74f23020 EAP-PEAP: Key derivation per draft-ietf-emu-tls-eap-types-00
872609c15 EAP-TTLS/PEAP peer: Fix failure when using session tickets under TLS 1.3
8265f8453 nl80211: Unconditionally clear nl_msg
6c7b0a965 PASN: Correctly set RSNXE bits from AP
85eb47e3a PASN: Correctly set RSNXE bits from STA
be5f7f374 wpa_supplicant: Fix potential memleak on an error path
8f248d1ac Check for message truncation in RADIUS client
5cb25307e Set RADIUS message length to reflect RFC 2865
7df089b56 Create RADIUS_MAX_MSG_LEN param in the shared radius.h
98a52b09c Add new attributes in get_sta_info QCA vendor command
8f204f69a Show OCV and beacon protection capabilities in control interface
6f92f81da AP: Check driver's capability to enable OCV when driver SME is used
73ebd58fc STA: Check driver capability to enable OCV when driver SME is used
f3dfe42c7 Clean up RSN parameter setting for PASN
d36d4209f Enable beacon protection only when driver indicates support
9d99814e2 Update sgml to generate reproducible manpages
e680a51e9 ext_password: Implement new file-based backend
e9f449ba5 wpa_supplicant: Move wpa_config_get_line() into utils
b1c23d3f2 HE: Fall back to 20 MHz on 2.4 GHz if 40 MHz is not supported
f1c6c9d3e ACS: Allow downgrading to 20 MHz based on OBSS results
9bb2f7529 Sync with mac80211-next.git include/uapi/linux/nl80211.h
cfc45a98d nl80211: Unsolicited broadcast Probe Response configuration
024b4b2a2 AP: Unsolicited broadcast Probe Response configuration
6fb626412 P2P: Clear unexpected HT40 configuration on 2.4 GHz band
6b59e63f0 Include secondary channel config in no-hw-channel-found message
d76ba2b31 nl80211: Add FILS Discovery frame configuration
9c02a0f5a FILS: Add generation of FILS Discovery frame template
c4c529e9c Add a helper function for determining RSN capabilities field value
272466518 Define FILS Discovery frame subfields
3eb5f7128 Do not include VHT elements in Beacon frames on the 6 GHz band
2c2b6d265 Add Transmit Power Envelope also for 6 GHz HE AP
6c2b729de Use hostapd_get_oper_chwidth() when build Transmit Power Envelope element
5d3c4496f Make VHT Transmit Power Envelope element helper more generic
58bbbb598 nl80211: Ignore 4addr mode enabling error if it was already enabled
1b45b8d3f wpa_supplicant: Don't exit scanning state on config reload
581df2d52 DPP2: Defer chirp scan if other scan is queued up
35756c02e mesh: Assign channel in frequency params in all bands
b1c3e4d07 nl80211: Send HE 6 GHz capability parameters to the driver
8d10831dc wolfSSL: wolfSSL_use_PrivateKey_* correct return codes
7e823d4df DPP: Expose config object PSK/passphrase in wpa_supplicant
1029f16a9 DPP: Expose config object AKM in wpa_supplicant control interface
ad59639ed DPP2: Fix Authentication Request destination in the chirping case
598f67132 SAE: Avoid driver STA entry removal unnecessarily when using H2E/PK
99cd45372 hw_feature: Correctly select mode in case of the 6 GHz band
f728c867e AP: Extend Spatial Reuse Parameter Set
9f9d3d362 Allow HE MCS rate selection for Beacon frames
7f2f262e6 nl80211: Support the 6 GHz band for beacon rate configuration
c3d557b4d hostapd: Add HE 6 GHz band capability configuration
bd8b17030 EAP-AKA: Check that ID message storing succeeds
e781f7c86 Fix compiler warning on CONFIG_AP without CONFIG_P2P builds
4c9b16602 Update Visual Studio projects to match file renaming
48cfb52b7 Rename blacklist.[ch] to bssid_ignore.[ch]
626fc0dcd Rename wpa_blacklist to wpa_bssid_ignore
b58ac90c3 Rename INTERWORKING_BLACKLISTED define
72cd4293f Rename the control interface BLACKLIST command to BSSID_IGNORE
752b1c608 Rename network profiles parameters for ignoring/accepted BSSIDs
e6ac26943 radiotap: Update radiotap parser
136bbf15c wlantest: Add more details about protected FTM frames
f56eec7c1 wlantest: Process Action No Ack frames like Action frames
ef26fc19f DFS: Allow switch to an available channel
f98fe2fd0 hostapd: Report errors ACCEPT_ACL/DENY_ACL control interface commands
15251c658 hostapd: Fix dynamic ACCEPT_ACL management over control interface
871d6648f hostapd: Add multi_ap settings to get_config() output
f95ccc102 WPS: Reconfigure credentials on hostapd config reload
2fd90eb09 WPS: Use helper variables to clean up code
f7bbad576 wpa_supplicant: Configurable fast-associate timer threshold
b829b7003 wpa_supplicant: Notify freq change on CH_SWITCH
3a00a86bb hostapd: Fix dpp_listen in DPP responder scenario
4a7e0ac26 hostapd: Add an option to notify management frames on ctrl_iface
e79febb3f P2P: Adding option to manage device drivers creating random MAC addresses
a579642bc BSD: If route socket overflows, sync drivers to system interfaces
fa859ebb1 RSN+WPA: Fix RSNE removing in EAPOL-Key msg 3/4 when RSNXE is included
dc1977959 RSN: Validate RSNXE match in EAPOL-Key msg 3/4 only when RSN is used
0b7895750 DPP: Silence compiler warning about signed/unsigned comparison
8f557d204 Make wpa_bss_ext_capab() handle NULL bss argument
2cadb60ab robust_av: Use wpa_bss_ext_capab() helper
a287c2078 Disable HE capabilities when using unacceptable security config
56c192c5e nl80211: Skip frame filter config for P2P-Device
2b916c9fd dbus: Fix IEs getter to use wpa_bss_ie_ptr()
9416b5f32 Add HE in ieee80211_freq_to_channel_ext() documentation
2acfd15a2 hostapd: Generalize channel switch methods to incorperated HE mode
2908dc91c hostapd: Enable HE for channel switch commmand
1c3e71d14 P2P: Add a maximum length limit for peer vendor IEs
947272feb P2P: Fix copying of secondary device types for P2P group client
25df656a8 Remove pointless defines for ext capab bits
11355a122 Reset external_scan_running on interface deletion
630b1fdba AP: Add 6 GHz security constraints
df0bfe475 mesh: Fix for leaving mesh
24f0507af WPA: Support deriving KDK based on capabilities (Authenticator)
dccb6cde0 WPA: Support deriving KDK based on capabilities
9e7b980d6 PASN: Include RSNXE in the PASN negotiation
d8cd20e37 RSN: Add RSNXE new definitions
2eb2fb8bd AP: Support PASN with FT key derivation
5c65ad6c0 PASN: Support PASN with FT key derivation
62edb79a0 AP: Support PASN with FILS key derivation
8c6d2e252 PASN: Support PASN with FILS key derivation
da35e1214 AP: Support PASN with SAE key derivation
a93ec28d1 PASN: Support PASN with SAE key derivation
3040c8a2d AP: Add support for PASN processing to the SME
f2f8e4f45 Add PTKSA cache to hostapd
2c963a117 AP: Add support for configuring PASN
ad338cfe5 ctrl_iface: Add support for PASN authentication
363768c8a PASN: Add support for PASN processing to wpa_supplicant
d70060f96 WPA: Add PTKSA cache to wpa_supplicant for PASN
a4e369161 WPA: Add PTKSA cache implementation
a84ba92fa WPA: Add a function to get PMKSA cache entry
6709b4ceb common: Add PASN parsing to ieee802_11_parse_extension()
46bfc3a84 tests: Add module tests for PASN PTK derivation
9ce123cdb PASN: Add common Authentication frame build/validation functions
c6d1a33bb PASN: Add functions to compute PTK, MIC and hash
d87f4aea1 FILS: Extend the fils_pmk_to_ptk() function to also derive KDK
6e834db74 FT: Extend the wpa_pmk_r1_to_ptk() function to also derive KDK
46c232eb7 WPA: Extend the wpa_pmk_to_ptk() function to also derive KDK
019507e10 common: Allow WPA_CIPHER_GTK_NOT_USED as a valid group management cipher
244721221 nl80211: Always register for RX authentication frames with PASN
a728449a0 nl80211: Allow off-channel of PASN authentication frames in send_mlme()
367e79231 PASN: Add some specification definitions
833cdbe97 Add support for new 5 GHz channels 173 and 177
21fdb454d P2P: Fix channel selection for operating class 129
959af4f57 DPP: Abort authentication if no Auth Confirm is received within a second
62657365f Add a configuration to disconnect on deinit if WoWLAN is enabled
8f5897294 dbus: Export new 'suiteb192' capability
9cdcc8823 DBus: Add 'owe' to interface Capabilities
8e8406469 wpa_cli: Add WPS_EVENT_OVERLAP to action scripts
41fae6e0b nl80211: Add missing WPA3-SAE auth_data in auth retry case
71718b628 FT: Update key mgmt properly in RSNE during roaming
ea77568d8 Add user configured vendor IEs to default scan IEs
b6947f01a Android: Pass the vendor events to $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
7b121af26 P2P: Delay P2P scan when an external scan is in progress
f39d6aacb P2P: Recover p2p_find operation in case of failure to fetch scan results
74818ca63 Process QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH after NL80211_CMD_ROAM
b4a41abad nl80211: Do not ignore disconnection event after a connection event
084b3d2f8 Drop unexpected connection event while disconnected
73c7c2da9 Vendor feature capability to notify TWT asynchronous response support
a337c1d7c New TWT operations and attributes to TWT Setup and Nudge
b709bb40f DPP2: Add DPP_CONTROLLER commands to hostapd_cli and wpa_cli
6ead8b897 Use bool for is_6ghz variables and functions
7131fede3 Extend the setband support for 6 GHz and band combinations
2a37cda74 scan: Add a helper function to append supported freqs from a given band
bba926350 Fix gcc-10 build with -Werror=array-bounds and dl_list_for_each()
0225301fd wolfSSL: Client cert loading API fix
297050b46 nl80211: Report invalid signal and noise when info is unavailable
be96f4e8d wlantest: Allow missing RSNE in S1G beacon
d83eaa351 Add option to ignore Probe Request frames when RSSI is too low
f2a010140 wpa_supplicant: Initial connection speedup
4683b7218 DFS: Enter DFS state if no available channel is found
eee0d242b hostapd: Add ability to disable HT/VHT/HE per BSS
89ad24379 mesh: Move mesh frequency setting to its own function
7c2cad969 mesh: Fix DFS deinit/init
0896c442d mesh: Fix for mesh init/deinit
06161d4f1 mesh: Fix mesh_oom test
12ae3e3db mesh: Inform kernel driver about DFS handler in userspace
a27faf2c9 mesh: Fix channel switch error during CAC
872590978 nl80211: Do not set offchanok on DFS channels in non-ETSI for mesh
e3608040c mesh: Update ssid->frequency as pri/sec channels switch
f1df4fbfc mesh: Use setup completion callback to complete mesh join
3c9abc785 QCA vendor attributes to configure TX and RX NSS
ed24bad1d AP: Check driver support while auto-selecting bandwidth for AP/P2P GO
5b782ff62 Add bus failure reason code to vendor indication
1c77f3d3f Indicate whether additional ANQP elements were protected
90ca804e4 Add vendor attributes for TWT nudge request
454ebb504 BSS: Use variable length array for IEs at the end of struct wpa_bss
be7ee264f BSS: Use wrapper function for getting a pointer to the IE buffer
95edd8144 BSS: Add wpa_bss_get_ie_ext() wrapper
dba4f7a54 Mark wpa_bss_get_fils_cache_id() argument const
2a7023ba6 Change list arguments to const where possible
fdf114641 nl80211: Send the sae_pwe value to the driver
2576f27e0 P2P: Disable P2P in the 6 GHz band for now
2ffd3bb4b P2P: Include p2p_6ghz_disable in global configuration
60c902f40 Add connect fail reason code from the driver to assoc reject event
7423fa6e8 Vendor feature capability to support concurrent sessions on Wi-Fi bands
1934ad9b2 Add extra parameters to vendor command GPIO attribute
d0e0d2283 Sync with mac80211-next.git include/uapi/linux/nl80211.h
c2c468622 Set NLA_F_NESTED flag with NL80211_ATTR_VENDOR_DATA conditionally
cd3aa54a3 Add test configuration attr to enable/disable full bandwidth UL MU-MIMO
f4de21a77 BSS/scan: More conversions to for_each_element_id()
aa06444f2 dbus: Check eloop registration failure in add_watch handler
56a1df71e BSS: Convert wpa_bss_get_vendor_ie() to use for_each_element_id()
ec1f4f3c8 Make GTK length validation for RSN Group 1/2 easier to analyze
c42d41bf3 EAP-IKEv2: Try to make transform parser simpler to understand
ec0d99c00 HS 2.0: Clarify OSU Friendly Name length validation
05962099c TDLS: Fix error path for TPK M1 send failure in testing functionality
a9fed5f5b Avoid undefined behavior with memcpy PMK/PSK update
c643c3928 nl80211: Fix filtering of unsupported bands/modes
a86078c87 TDLS: Fix error path handling for TPK M1 send failures
3d490296b DPP2: Fix error path handling in enterprise provisioning
f724dd1bf Remove unused variable update
589bf1f7a DPP2: Fix ppkey parsing
79e3f08d3 6 GHz: Add support for missing 6 GHz operating classes
66bed14b2 6 GHz: Fix opclasses mapping in ieee80211_freq_to_channel_ext()
5e779873e EAP-SIM peer: Send AT_IDENTITY first
0577e8e67 nl80211: Check for proper nlmsg allocation in send_and_recv_msgs_owner()
02289ab53 DPP2: Explicitly check EC_KEY before dereferencing it
c57590476 P2P: Consider BSS entry pending for P2P joining as a known BSS
106d67a93 nl80211: Filter out unsupported bands
9c39c1a6d P2P: Include p2p_add_cli_chan parameter while cloning the configuration
8f0ed71ff Vendor specific feature capability for Adaptive 11r
45ae6ae8e Add additional vendor specific hang reason codes
d2190cdc6 DPP2: Update the default port number for DPP-over-TCP
5d988b4a5 Fix couple more typos
b439b21a2 wpa_supplicant: Fix typos
183e72ae1 SAE-PK: Do not accept SAE-PK status code when no PK is configured
80662accb SAE: Don't use potentially uninitialized keys
b4c7114cf wpa_supplicant: Remove unfeasible conditions in config parsing
ff7e0c1cf wpa_cli: Don't access uninitialized variables
e364a34c6 OpenSSL: Make openssl_debug_dump_certificate() more robust

Change-Id: Ia7e3838712a621fe0341464dd04671f708d8cde4
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index f0e4236..b0d8ec8 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -131,6 +131,7 @@
 	bss->fils_hlp_wait_time = 30;
 	bss->dhcp_server_port = DHCP_SERVER_PORT;
 	bss->dhcp_relay_port = DHCP_SERVER_PORT;
+	bss->fils_discovery_min_int = 20;
 #endif /* CONFIG_FILS */
 
 	bss->broadcast_deauth = 1;
@@ -270,6 +271,10 @@
 	conf->he_op.he_bss_color_disabled = 1;
 	conf->he_op.he_bss_color_partial = 0;
 	conf->he_op.he_bss_color = 1;
+	conf->he_6ghz_max_mpdu = 2;
+	conf->he_6ghz_max_ampdu_len_exp = 7;
+	conf->he_6ghz_rx_ant_pat = 1;
+	conf->he_6ghz_tx_ant_pat = 1;
 #endif /* CONFIG_IEEE80211AX */
 
 	/* The third octet of the country string uses an ASCII space character
@@ -957,6 +962,10 @@
 	}
 #endif /* CONFIG_AIRTIME_POLICY */
 
+#ifdef CONFIG_PASN
+	os_free(conf->pasn_groups);
+#endif /* CONFIG_PASN */
+
 	os_free(conf);
 }
 
@@ -1152,10 +1161,54 @@
 #endif /* CONFIG_SAE_PK */
 
 
+static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
+{
+	if (bss->wpa != WPA_PROTO_RSN) {
+		wpa_printf(MSG_ERROR,
+			   "Pre-RSNA security methods are not allowed in 6 GHz");
+		return false;
+	}
+
+	if (bss->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED) {
+		wpa_printf(MSG_ERROR,
+			   "Management frame protection is required in 6 GHz");
+		return false;
+	}
+
+	if (bss->wpa_key_mgmt & (WPA_KEY_MGMT_PSK |
+				 WPA_KEY_MGMT_FT_PSK |
+				 WPA_KEY_MGMT_PSK_SHA256)) {
+		wpa_printf(MSG_ERROR, "Invalid AKM suite for 6 GHz");
+		return false;
+	}
+
+	if (bss->rsn_pairwise & (WPA_CIPHER_WEP40 |
+				 WPA_CIPHER_WEP104 |
+				 WPA_CIPHER_TKIP)) {
+		wpa_printf(MSG_ERROR,
+			   "Invalid pairwise cipher suite for 6 GHz");
+		return false;
+	}
+
+	if (bss->wpa_group & (WPA_CIPHER_WEP40 |
+			      WPA_CIPHER_WEP104 |
+			      WPA_CIPHER_TKIP)) {
+		wpa_printf(MSG_ERROR, "Invalid group cipher suite for 6 GHz");
+		return false;
+	}
+
+	return true;
+}
+
+
 static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
 				    struct hostapd_config *conf,
 				    int full_config)
 {
+	if (full_config && is_6ghz_op_class(conf->op_class) &&
+	    !hostapd_config_check_bss_6g(bss))
+		return -1;
+
 	if (full_config && bss->ieee802_1x && !bss->eap_server &&
 	    !bss->radius->auth_servers) {
 		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
@@ -1231,7 +1284,7 @@
 
 	if (full_config && conf->ieee80211n &&
 	    conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
-		bss->disable_11n = 1;
+		bss->disable_11n = true;
 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
 			   "allowed, disabling HT capabilities");
 	}
@@ -1239,7 +1292,7 @@
 #ifdef CONFIG_WEP
 	if (full_config && conf->ieee80211n &&
 	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
-		bss->disable_11n = 1;
+		bss->disable_11n = true;
 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
 			   "allowed, disabling HT capabilities");
 	}
@@ -1250,7 +1303,7 @@
 	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
 				   WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
 	{
-		bss->disable_11n = 1;
+		bss->disable_11n = true;
 		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
 			   "requires CCMP/GCMP to be enabled, disabling HT "
 			   "capabilities");
@@ -1260,7 +1313,7 @@
 #ifdef CONFIG_WEP
 	if (full_config && conf->ieee80211ac &&
 	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
-		bss->disable_11ac = 1;
+		bss->disable_11ac = true;
 		wpa_printf(MSG_ERROR,
 			   "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
 	}
@@ -1271,12 +1324,33 @@
 	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
 				   WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
 	{
-		bss->disable_11ac = 1;
+		bss->disable_11ac = true;
 		wpa_printf(MSG_ERROR,
 			   "VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
 	}
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+#ifdef CONFIG_WEP
+	if (full_config && conf->ieee80211ax &&
+	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+		bss->disable_11ax = true;
+		wpa_printf(MSG_ERROR,
+			   "HE (IEEE 802.11ax) with WEP is not allowed, disabling HE capabilities");
+	}
+#endif /* CONFIG_WEP */
+
+	if (full_config && conf->ieee80211ax && bss->wpa &&
+	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+				   WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+	{
+		bss->disable_11ax = true;
+		wpa_printf(MSG_ERROR,
+			   "HE (IEEE 802.11ax) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling HE capabilities");
+	}
+#endif /* CONFIG_IEEE80211AX */
+
 #ifdef CONFIG_WPS
 	if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
 		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 0cb4b52..e1b17f5 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -531,8 +531,9 @@
 #define TDLS_PROHIBIT BIT(0)
 #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
 	int tdls;
-	int disable_11n;
-	int disable_11ac;
+	bool disable_11n;
+	bool disable_11ac;
+	bool disable_11ax;
 
 	/* IEEE 802.11v */
 	int time_advertisement;
@@ -729,12 +730,16 @@
 	unsigned int fils_hlp_wait_time;
 	u16 dhcp_server_port;
 	u16 dhcp_relay_port;
+	u32 fils_discovery_min_int;
+	u32 fils_discovery_max_int;
 #endif /* CONFIG_FILS */
 
 	int multicast_to_unicast;
 
 	int broadcast_deauth;
 
+	int notify_mgmt_frames;
+
 #ifdef CONFIG_DPP
 	char *dpp_name;
 	char *dpp_mud_url;
@@ -861,6 +866,20 @@
 	 */
 	u8 mka_psk_set;
 #endif /* CONFIG_MACSEC */
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	/*
+	 * Normally, KDK should be derived if and only if both sides support
+	 * secure LTF. Allow forcing KDK derivation for testing purposes.
+	 */
+	int force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	int *pasn_groups;
+#endif /* CONFIG_PASN */
+
+	unsigned int unsol_bcast_probe_resp_interval;
 };
 
 /**
@@ -893,8 +912,8 @@
 	u8 non_srg_obss_pd_max_offset;
 	u8 srg_obss_pd_min_offset;
 	u8 srg_obss_pd_max_offset;
-	u8 srg_obss_color_bitmap;
-	u8 srg_obss_color_partial_bitmap;
+	u8 srg_bss_color_bitmap[8];
+	u8 srg_partial_bssid_bitmap[8];
 };
 
 /**
@@ -1031,6 +1050,10 @@
 	u8 he_oper_chwidth;
 	u8 he_oper_centr_freq_seg0_idx;
 	u8 he_oper_centr_freq_seg1_idx;
+	u8 he_6ghz_max_mpdu;
+	u8 he_6ghz_max_ampdu_len_exp;
+	u8 he_6ghz_rx_ant_pat;
+	u8 he_6ghz_tx_ant_pat;
 #endif /* CONFIG_IEEE80211AX */
 
 	/* VHT enable/disable config from CHAN_SWITCH */
@@ -1038,8 +1061,14 @@
 #define CH_SWITCH_VHT_DISABLED BIT(1)
 	unsigned int ch_switch_vht_config;
 
+	/* HE enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_HE_ENABLED BIT(0)
+#define CH_SWITCH_HE_DISABLED BIT(1)
+	unsigned int ch_switch_he_config;
+
 	int rssi_reject_assoc_rssi;
 	int rssi_reject_assoc_timeout;
+	int rssi_ignore_probe_request;
 
 #ifdef CONFIG_AIRTIME_POLICY
 	enum {
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index f157659..d1642d7 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -988,3 +988,11 @@
 	return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
 					  ie, ielen);
 }
+
+
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
+{
+	if (!hapd->driver || !hapd->driver->dpp_listen || !hapd->drv_priv)
+		return 0;
+	return hapd->driver->dpp_listen(hapd->drv_priv, enable);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 5738c1c..582ab61 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -134,6 +134,7 @@
 int hostapd_drv_do_acs(struct hostapd_data *hapd);
 int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
 			     u16 reason_code, const u8 *ie, size_t ielen);
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
 
 
 #include "drivers/driver.h"
@@ -350,12 +351,13 @@
 static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
 					 int vendor_id, int subcmd,
 					 const u8 *data, size_t data_len,
+					 enum nested_attr nested_attr_flag,
 					 struct wpabuf *buf)
 {
 	if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
 		return -1;
 	return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
-					data_len, buf);
+					data_len, nested_attr_flag, buf);
 }
 
 static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
@@ -384,11 +386,11 @@
 }
 
 static inline int
-hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
+hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask)
 {
 	if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
 		return -1;
-	return hapd->driver->set_band(hapd->drv_priv, band);
+	return hapd->driver->set_band(hapd->drv_priv, band_mask);
 }
 
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index b3b33b7..7d9e8b9 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -266,7 +266,7 @@
 }
 
 
-static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
 {
 	const u8 *ies;
 	size_t ies_len;
@@ -458,7 +458,7 @@
 	}
 
 #ifdef CONFIG_IEEE80211AX
-	if (hapd->iconf->ieee80211ax) {
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
 		buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
 			3 + sizeof(struct ieee80211_he_operation) +
 			3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
@@ -563,15 +563,21 @@
 	}
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+	    is_6ghz_op_class(hapd->iconf->op_class))
+		pos = hostapd_eid_txpower_envelope(hapd, pos);
+#endif /* CONFIG_IEEE80211AX */
+
 	if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
-	    hapd->iconf->ieee80211ax)
+	    (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
 		pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
 
 	pos = hostapd_eid_fils_indic(hapd, pos, 0);
 	pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
 
 #ifdef CONFIG_IEEE80211AX
-	if (hapd->iconf->ieee80211ax) {
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
 		pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
 		pos = hostapd_eid_he_operation(hapd, pos);
 		pos = hostapd_eid_spatial_reuse(hapd, pos);
@@ -818,6 +824,10 @@
 	size_t csa_offs_len;
 	struct radius_sta rad_info;
 
+	if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
+	    ssi_signal < hapd->iconf->rssi_ignore_probe_request)
+		return;
+
 	if (len < IEEE80211_HDRLEN)
 		return;
 	ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
@@ -1114,6 +1124,23 @@
 #endif /* NEED_AP_MLME */
 
 
+#ifdef CONFIG_IEEE80211AX
+/* Unsolicited broadcast Probe Response transmission, 6 GHz only */
+static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+					   struct wpa_driver_ap_params *params)
+{
+	if (!is_6ghz_op_class(hapd->iconf->op_class))
+		return NULL;
+
+	params->unsol_bcast_probe_resp_interval =
+		hapd->conf->unsol_bcast_probe_resp_interval;
+
+	return hostapd_gen_probe_resp(hapd, NULL, 0,
+				      &params->unsol_bcast_probe_resp_tmpl_len);
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
 void sta_track_del(struct hostapd_sta_info *info)
 {
 #ifdef CONFIG_TAXONOMY
@@ -1124,6 +1151,243 @@
 }
 
 
+#ifdef CONFIG_FILS
+
+static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
+{
+	u16 cap_info, phy_index = 0;
+	u8 chwidth = FD_CAP_BSS_CHWIDTH_20, mcs_nss_size = 4;
+	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+
+	cap_info = FD_CAP_ESS;
+	if (hapd->conf->wpa)
+		cap_info |= FD_CAP_PRIVACY;
+
+	if (is_6ghz_op_class(hapd->iconf->op_class)) {
+		phy_index = FD_CAP_PHY_INDEX_HE;
+
+		switch (hapd->iconf->op_class) {
+		case 135:
+			mcs_nss_size += 4;
+			/* fallthrough */
+		case 134:
+			mcs_nss_size += 4;
+			chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+			break;
+		case 133:
+			chwidth = FD_CAP_BSS_CHWIDTH_80;
+			break;
+		case 132:
+			chwidth = FD_CAP_BSS_CHWIDTH_40;
+			break;
+		}
+	} else {
+		switch (hostapd_get_oper_chwidth(hapd->iconf)) {
+		case CHANWIDTH_80P80MHZ:
+			mcs_nss_size += 4;
+			/* fallthrough */
+		case CHANWIDTH_160MHZ:
+			mcs_nss_size += 4;
+			chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+			break;
+		case CHANWIDTH_80MHZ:
+			chwidth = FD_CAP_BSS_CHWIDTH_80;
+			break;
+		case CHANWIDTH_USE_HT:
+			if (hapd->iconf->secondary_channel)
+				chwidth = FD_CAP_BSS_CHWIDTH_40;
+			else
+				chwidth = FD_CAP_BSS_CHWIDTH_20;
+			break;
+		}
+
+#ifdef CONFIG_IEEE80211AX
+		if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
+			phy_index = FD_CAP_PHY_INDEX_HE;
+#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211AC
+		if (!phy_index &&
+		    hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
+			phy_index = FD_CAP_PHY_INDEX_VHT;
+#endif /* CONFIG_IEEE80211AC */
+		if (!phy_index &&
+		    hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
+			phy_index = FD_CAP_PHY_INDEX_HT;
+	}
+
+	cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
+	cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
+
+	if (mode) {
+		u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs;
+		int i;
+		u16 nss = 0;
+
+		for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
+			u16 nss_mask = 0x3 << (i * 2);
+
+			if (mcs_nss_size == 4 &&
+			    (((mcs[0] & nss_mask) == nss_mask) ||
+			     ((mcs[1] & nss_mask) == nss_mask)))
+				continue;
+
+			if (mcs_nss_size == 8 &&
+			    (((mcs[2] & nss_mask) == nss_mask) ||
+			     ((mcs[3] & nss_mask) == nss_mask)))
+				continue;
+
+			if (mcs_nss_size == 12 &&
+			    (((mcs[4] & nss_mask) == nss_mask) ||
+			     ((mcs[5] & nss_mask) == nss_mask)))
+				continue;
+
+			nss++;
+		}
+
+		if (nss > 4)
+			cap_info |= FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
+		else if (nss)
+			cap_info |= (nss - 1) << FD_CAP_NSS_SHIFT;
+	}
+
+	return cap_info;
+}
+
+
+static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
+{
+	struct ieee80211_mgmt *head;
+	const u8 *mobility_domain;
+	u8 *pos, *length_pos, buf[200];
+	u16 ctl = 0;
+	u8 fd_rsn_info[5];
+	size_t total_len, buf_len;
+
+	total_len = 24 + 2 + 12;
+
+	/* FILS Discovery Frame Control */
+	ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
+		FD_FRAME_CTL_SHORT_SSID_PRESENT |
+		FD_FRAME_CTL_LENGTH_PRESENT |
+		FD_FRAME_CTL_CAP_PRESENT;
+	total_len += 4 + 1 + 2;
+
+	/* Check for optional subfields and calculate length */
+	if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
+		ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
+		total_len += sizeof(fd_rsn_info);
+	}
+
+	mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+	if (mobility_domain) {
+		ctl |= FD_FRAME_CTL_MD_PRESENT;
+		total_len += 3;
+	}
+
+	pos = hostapd_eid_fils_indic(hapd, buf, 0);
+	buf_len = pos - buf;
+	total_len += buf_len;
+
+	head = os_zalloc(total_len);
+	if (!head)
+		return NULL;
+
+	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memset(head->da, 0xff, ETH_ALEN);
+	os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+
+	head->u.action.category = WLAN_ACTION_PUBLIC;
+	head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
+
+	pos = &head->u.action.u.public_action.variable[0];
+
+	/* FILS Discovery Information field */
+
+	/* FILS Discovery Frame Control */
+	WPA_PUT_LE16(pos, ctl);
+	pos += 2;
+
+	/* Hardware or low-level driver will fill in the Timestamp value */
+	pos += 8;
+
+	/* Beacon Interval */
+	WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
+	pos += 2;
+
+	/* Short SSID */
+	WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
+	pos += sizeof(hapd->conf->ssid.short_ssid);
+
+	/* Store position of FILS discovery information element Length field */
+	length_pos = pos++;
+
+	/* FD Capability */
+	WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
+	pos += 2;
+
+	/* Operating Class - not present */
+
+	/* Primary Channel - not present */
+
+	/* AP Configuration Sequence Number - not present */
+
+	/* Access Network Options - not present */
+
+	/* FD RSN Information */
+	if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
+		os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
+		pos += sizeof(fd_rsn_info);
+	}
+
+	/* Channel Center Frequency Segment 1 - not present */
+
+	/* Mobility Domain */
+	if (ctl & FD_FRAME_CTL_MD_PRESENT) {
+		os_memcpy(pos, &mobility_domain[2], 3);
+		pos += 3;
+	}
+
+	/* Fill in the Length field value */
+	*length_pos = pos - (length_pos + 1);
+
+	/* FILS Indication element */
+	if (buf_len) {
+		os_memcpy(pos, buf, buf_len);
+		pos += buf_len;
+	}
+
+	*len = pos - (u8 *) head;
+	wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
+		    head, pos - (u8 *) head);
+	return (u8 *) head;
+}
+
+
+/* Configure FILS Discovery frame transmission parameters */
+static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+				   struct wpa_driver_ap_params *params)
+{
+	params->fd_max_int = hapd->conf->fils_discovery_max_int;
+	if (is_6ghz_op_class(hapd->iconf->op_class) &&
+	    params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
+		params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
+
+	params->fd_min_int = hapd->conf->fils_discovery_min_int;
+	if (params->fd_min_int > params->fd_max_int)
+		params->fd_min_int = params->fd_max_int;
+
+	if (params->fd_max_int)
+		return hostapd_gen_fils_discovery(hapd,
+						  &params->fd_frame_tmpl_len);
+
+	return NULL;
+}
+
+#endif /* CONFIG_FILS */
+
+
 int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 			       struct wpa_driver_ap_params *params)
 {
@@ -1163,7 +1427,7 @@
 #endif /* CONFIG_IEEE80211AC */
 
 #ifdef CONFIG_IEEE80211AX
-	if (hapd->iconf->ieee80211ax) {
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
 		tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
 			3 + sizeof(struct ieee80211_he_operation) +
 			3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
@@ -1280,22 +1544,29 @@
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_IEEE80211AC
-	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+	    !is_6ghz_op_class(hapd->iconf->op_class)) {
 		tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
 		tailpos = hostapd_eid_vht_operation(hapd, tailpos);
 		tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
 	}
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+	    is_6ghz_op_class(hapd->iconf->op_class))
+		tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AX */
+
 	if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
-	     hapd->iconf->ieee80211ax)
+	    (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
 		tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
 
 	tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
 	tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
 
 #ifdef CONFIG_IEEE80211AX
-	if (hapd->iconf->ieee80211ax) {
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
 		tailpos = hostapd_eid_he_capab(hapd, tailpos,
 					       IEEE80211_MODE_AP);
 		tailpos = hostapd_eid_he_operation(hapd, tailpos);
@@ -1461,6 +1732,14 @@
 	params->head = NULL;
 	os_free(params->proberesp);
 	params->proberesp = NULL;
+#ifdef CONFIG_FILS
+	os_free(params->fd_frame_tmpl);
+	params->fd_frame_tmpl = NULL;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+	os_free(params->unsol_bcast_probe_resp_tmpl);
+	params->unsol_bcast_probe_resp_tmpl = NULL;
+#endif /* CONFIG_IEEE80211AX */
 }
 
 
@@ -1493,11 +1772,17 @@
 	params.assocresp_ies = assocresp;
 	params.reenable = hapd->reenable_beacon;
 #ifdef CONFIG_IEEE80211AX
-	params.he_spr = !!hapd->iface->conf->spr.sr_control;
+	params.he_spr_ctrl = hapd->iface->conf->spr.sr_control;
+	params.he_spr_non_srg_obss_pd_max_offset =
+		hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
 	params.he_spr_srg_obss_pd_min_offset =
 		hapd->iface->conf->spr.srg_obss_pd_min_offset;
 	params.he_spr_srg_obss_pd_max_offset =
 		hapd->iface->conf->spr.srg_obss_pd_max_offset;
+	os_memcpy(params.he_spr_bss_color_bitmap,
+		  hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+	os_memcpy(params.he_spr_partial_bssid_bitmap,
+		  hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
 	params.he_bss_color_disabled =
 		hapd->iface->conf->he_op.he_bss_color_disabled;
 	params.he_bss_color_partial =
@@ -1505,8 +1790,17 @@
 	params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
 	params.twt_responder = hostapd_get_he_twt_responder(hapd,
 							    IEEE80211_MODE_AP);
+	params.unsol_bcast_probe_resp_tmpl =
+		hostapd_unsol_bcast_probe_resp(hapd, &params);
 #endif /* CONFIG_IEEE80211AX */
 	hapd->reenable_beacon = 0;
+#ifdef CONFIG_SAE
+	params.sae_pwe = hapd->conf->sae_pwe;
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+	params.fd_frame_tmpl = hostapd_fils_discovery(hapd, &params);
+#endif /* CONFIG_FILS */
 
 	if (cmode &&
 	    hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index a26e308..c320825 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -30,4 +30,6 @@
 void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
 				   struct wpabuf **probe_ie_taxonomy);
 
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
+
 #endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ef53a82..28e40ba 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -748,7 +748,8 @@
 			  iface->conf->ieee80211n && !hapd->conf->disable_11n,
 			  iface->conf->ieee80211ac &&
 			  !hapd->conf->disable_11ac,
-			  iface->conf->ieee80211ax,
+			  iface->conf->ieee80211ax &&
+			  !hapd->conf->disable_11ax,
 			  iface->conf->beacon_int,
 			  hapd->conf->dtim_period);
 	if (os_snprintf_error(buflen - len, ret))
@@ -756,7 +757,7 @@
 	len += ret;
 
 #ifdef CONFIG_IEEE80211AX
-	if (iface->conf->ieee80211ax) {
+	if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
 		ret = os_snprintf(buf + len, buflen - len,
 				  "he_oper_chwidth=%d\n"
 				  "he_oper_centr_freq_seg0_idx=%d\n"
@@ -908,6 +909,7 @@
 	SET_CSA_SETTING(sec_channel_offset);
 	settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
 	settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+	settings->freq_params.he_enabled = !!os_strstr(pos, " he");
 	settings->block_tx = !!os_strstr(pos, " blocktx");
 #undef SET_CSA_SETTING
 
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index f04a00a..b990fb3 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -81,17 +81,17 @@
 	 * We will also choose this first channel as the control one.
 	 */
 	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
-			     184, 192 };
+			     165, 173, 184, 192 };
 	/*
 	 * VHT80, valid channels based on center frequency:
-	 * 42, 58, 106, 122, 138, 155
+	 * 42, 58, 106, 122, 138, 155, 171
 	 */
-	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+	int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
 	/*
 	 * VHT160 valid channels based on center frequency:
-	 * 50, 114
+	 * 50, 114, 163
 	 */
-	int allowed_160[] = { 36, 100 };
+	int allowed_160[] = { 36, 100, 149 };
 	int *allowed = allowed_40;
 	unsigned int i, allowed_no = 0;
 
@@ -1032,6 +1032,7 @@
 	int err = 1;
 	struct hostapd_hw_modes *cmode = iface->current_mode;
 	u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+	int ieee80211_mode = IEEE80211_MODE_AP;
 
 	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
 		   __func__, iface->cac_started ? "yes" : "no",
@@ -1069,8 +1070,16 @@
 						  &oper_centr_freq_seg0_idx,
 						  &oper_centr_freq_seg1_idx,
 						  &skip_radar);
-		if (!channel)
-			return err;
+		if (!channel) {
+			/*
+			 * Toggle interface state to enter DFS state
+			 * until NOP is finished.
+			 */
+			hostapd_disable_iface(iface);
+			hostapd_enable_iface(iface);
+			return 0;
+		}
+
 		if (!skip_radar) {
 			iface->freq = channel->freq;
 			iface->conf->channel = channel->chan;
@@ -1099,6 +1108,10 @@
 	os_memset(&csa_settings, 0, sizeof(csa_settings));
 	csa_settings.cs_count = 5;
 	csa_settings.block_tx = 1;
+#ifdef CONFIG_MESH
+	if (iface->mconf)
+		ieee80211_mode = IEEE80211_MODE_MESH;
+#endif /* CONFIG_MESH */
 	err = hostapd_set_freq_params(&csa_settings.freq_params,
 				      iface->conf->hw_mode,
 				      channel->freq,
@@ -1113,7 +1126,7 @@
 				      oper_centr_freq_seg0_idx,
 				      oper_centr_freq_seg1_idx,
 				      cmode->vht_capab,
-				      &cmode->he_capab[IEEE80211_MODE_AP]);
+				      &cmode->he_capab[ieee80211_mode]);
 
 	if (err) {
 		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@@ -1335,12 +1348,16 @@
 		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
 			continue;
 
+		if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+		    HOSTAPD_CHAN_DFS_AVAILABLE)
+			continue;
+
 		if (center_freq - chan->freq < half_width &&
 		    chan->freq - center_freq < half_width)
 			res++;
 	}
 
-	wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
+	wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
 		   center_freq - half_width, center_freq + half_width,
 		   res ? "yes" : "no");
 
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 6772a87..e1e5a3a 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -23,6 +23,8 @@
 
 
 static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+					       void *timeout_ctx);
 static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
 static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
 static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
@@ -246,6 +248,8 @@
 		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
 		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
 				     hapd, NULL);
+		eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+				     hapd, NULL);
 		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
 				     NULL);
 #ifdef CONFIG_DPP2
@@ -277,6 +281,17 @@
 		}
 	}
 
+	if (auth->waiting_auth_conf &&
+	    auth->auth_resp_status == DPP_STATUS_OK) {
+		/* Make sure we do not get stuck waiting for Auth Confirm
+		 * indefinitely after successfully transmitted Auth Response to
+		 * allow new authentication exchanges to be started. */
+		eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd,
+				     NULL);
+		eloop_register_timeout(1, 0, hostapd_dpp_auth_conf_wait_timeout,
+				       hapd, NULL);
+	}
+
 	if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
 		/* Allow timeout handling to stop iteration if no response is
 		 * received from a peer that has ACKed a request. */
@@ -377,6 +392,25 @@
 }
 
 
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+					       void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct dpp_authentication *auth = hapd->dpp_auth;
+
+	if (!auth || !auth->waiting_auth_conf)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "DPP: Terminate authentication exchange due to Auth Confirm timeout");
+	wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+		"No Auth Confirm received");
+	hostapd_drv_send_action_cancel_wait(hapd);
+	dpp_auth_deinit(auth);
+	hapd->dpp_auth = NULL;
+}
+
+
 static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
 					    struct dpp_authentication *auth)
 {
@@ -461,7 +495,9 @@
 	freq = auth->freq[auth->freq_idx++];
 	auth->curr_freq = freq;
 
-	if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+	if (!is_zero_ether_addr(auth->peer_mac_addr))
+		dst = auth->peer_mac_addr;
+	else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
 		dst = broadcast;
 	else
 		dst = auth->peer_bi->mac_addr;
@@ -594,6 +630,8 @@
 		eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
 		eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
 				     hapd, NULL);
+		eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+				     hapd, NULL);
 		eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
 				     NULL);
 #ifdef CONFIG_DPP2
@@ -661,12 +699,14 @@
 		return -1;
 	}
 
+	hostapd_drv_dpp_listen(hapd, true);
 	return 0;
 }
 
 
 void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
 {
+	hostapd_drv_dpp_listen(hapd, false);
 	/* TODO: Stop listen operation on non-operating channel */
 }
 
@@ -1261,8 +1301,9 @@
 
 	auth->neg_freq = freq;
 
-	if (!is_zero_ether_addr(peer_bi->mac_addr))
-		os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+	/* The source address of the Presence Announcement frame overrides any
+	 * MAC address information from the bootstrapping information. */
+	os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
 
 	hapd->dpp_auth = auth;
 	if (hostapd_dpp_auth_init_next(hapd) < 0) {
@@ -1962,6 +2003,7 @@
 	wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
 		   ok);
 	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+	eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
 	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
 #ifdef CONFIG_DPP2
 		eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
@@ -2207,6 +2249,7 @@
 	if (!hapd->dpp_init_done)
 		return;
 	eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+	eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
 	eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
 	eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
 #ifdef CONFIG_DPP2
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 9af5445..53082f5 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -870,9 +870,10 @@
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO,
-		       "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+		       "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
 		       finished ? "had" : "starting",
-		       freq, ht, hapd->iconf->ch_switch_vht_config, offset,
+		       freq, ht, hapd->iconf->ch_switch_vht_config,
+		       hapd->iconf->ch_switch_he_config, offset,
 		       width, channel_width_to_string(width), cf1, cf2);
 
 	if (!hapd->iface->current_mode) {
@@ -944,8 +945,17 @@
 		else if (hapd->iconf->ch_switch_vht_config &
 			 CH_SWITCH_VHT_DISABLED)
 			hapd->iconf->ieee80211ac = 0;
+	} else if (hapd->iconf->ch_switch_he_config) {
+		/* CHAN_SWITCH HE config */
+		if (hapd->iconf->ch_switch_he_config &
+		    CH_SWITCH_HE_ENABLED)
+			hapd->iconf->ieee80211ax = 1;
+		else if (hapd->iconf->ch_switch_he_config &
+			 CH_SWITCH_HE_DISABLED)
+			hapd->iconf->ieee80211ax = 0;
 	}
 	hapd->iconf->ch_switch_vht_config = 0;
+	hapd->iconf->ch_switch_he_config = 0;
 
 	hapd->iconf->secondary_channel = offset;
 	hostapd_set_oper_chwidth(hapd->iconf, chwidth);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index b37f49f..e257174 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -354,7 +354,7 @@
 #endif /* CONFIG_WEP */
 
 
-static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+void hostapd_free_hapd_data(struct hostapd_data *hapd)
 {
 	os_free(hapd->probereq_cb);
 	hapd->probereq_cb = NULL;
@@ -434,6 +434,8 @@
 #ifdef CONFIG_MESH
 	wpabuf_free(hapd->mesh_pending_auth);
 	hapd->mesh_pending_auth = NULL;
+	/* handling setup failure is already done */
+	hapd->setup_complete_cb = NULL;
 #endif /* CONFIG_MESH */
 
 	hostapd_clean_rrm(hapd);
@@ -496,7 +498,7 @@
 }
 
 
-static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 {
 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 #ifdef NEED_AP_MLME
@@ -624,7 +626,7 @@
 }
 
 
-static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
 {
 	hostapd_free_stas(hapd);
 	hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
@@ -1701,6 +1703,9 @@
 		ret = hostapd_check_edmg_capab(iface);
 		if (ret < 0)
 			goto fail;
+		ret = hostapd_check_he_6ghz_capab(iface);
+		if (ret < 0)
+			goto fail;
 		ret = hostapd_check_ht_capab(iface);
 		if (ret < 0)
 			goto fail;
@@ -2156,6 +2161,13 @@
 	if (hapd->setup_complete_cb)
 		hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
 
+#ifdef CONFIG_MESH
+	if (delay_apply_cfg && !iface->mconf) {
+		wpa_printf(MSG_ERROR, "Error while completing mesh init");
+		goto fail;
+	}
+#endif /* CONFIG_MESH */
+
 	wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
 		   iface->bss[0]->conf->iface);
 	if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
@@ -2299,7 +2311,7 @@
 	ret = setup_interface(iface);
 	if (ret) {
 		wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
-			   iface->bss[0]->conf->iface);
+			   iface->conf ? iface->conf->bss[0]->iface : "N/A");
 		return -1;
 	}
 
@@ -2681,6 +2693,12 @@
 {
 	size_t j;
 
+	if (!hapd_iface)
+		return -1;
+
+	if (hapd_iface->enable_iface_cb)
+		return hapd_iface->enable_iface_cb(hapd_iface);
+
 	if (hapd_iface->bss[0]->drv_priv != NULL) {
 		wpa_printf(MSG_ERROR, "Interface %s already enabled",
 			   hapd_iface->conf->bss[0]->iface);
@@ -2742,6 +2760,9 @@
 	if (hapd_iface == NULL)
 		return -1;
 
+	if (hapd_iface->disable_iface_cb)
+		return hapd_iface->disable_iface_cb(hapd_iface);
+
 	if (hapd_iface->bss[0]->drv_priv == NULL) {
 		wpa_printf(MSG_INFO, "Interface %s already disabled",
 			   hapd_iface->conf->bss[0]->iface);
@@ -3539,15 +3560,23 @@
 }
 
 
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+				struct hostapd_freq_params *freq_params)
 {
-	if (vht_enabled)
+	if (freq_params->he_enabled)
+		hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
+	else
+		hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED;
+
+	if (freq_params->vht_enabled)
 		hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
 	else
 		hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
+		       HOSTAPD_LEVEL_INFO,
+		       "CHAN_SWITCH HE config 0x%x VHT config 0x%x",
+		       hapd->iconf->ch_switch_he_config,
 		       hapd->iconf->ch_switch_vht_config);
 }
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 9d3c85d..591996a 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -370,6 +370,8 @@
 
 	int dhcp_sock; /* UDP socket used with the DHCP server */
 
+	struct ptksa_cache *ptksa;
+
 #ifdef CONFIG_DPP
 	int dpp_init_done;
 	struct dpp_authentication *dpp_auth;
@@ -590,6 +592,9 @@
 
 	/* Previous WMM element information */
 	struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
+
+	int (*enable_iface_cb)(struct hostapd_iface *iface);
+	int (*disable_iface_cb)(struct hostapd_iface *iface);
 };
 
 /* hostapd.c */
@@ -618,13 +623,17 @@
 int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
 int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
+void hostapd_free_hapd_data(struct hostapd_data *hapd);
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
 int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
 int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
 void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
 void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
 const char * hostapd_state_text(enum hostapd_iface_state s);
 int hostapd_csa_in_progress(struct hostapd_iface *iface);
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+				struct hostapd_freq_params *freq_params);
 int hostapd_switch_channel(struct hostapd_data *hapd,
 			   struct csa_settings *settings);
 void
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 543fa33..05e9b9d 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -86,7 +86,9 @@
 			capab |= WPA_CAPABILITY_MFPR;
 	}
 #ifdef CONFIG_OCV
-	if (hapd->conf->ocv)
+	if (hapd->conf->ocv &&
+	    (hapd->iface->drv_flags2 &
+	     (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
 		capab |= WPA_CAPABILITY_OCVC;
 #endif /* CONFIG_OCV */
 	WPA_PUT_LE16(eid, capab);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index f6e6903..7849be1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -313,7 +313,7 @@
 {
 	struct wpa_scan_results *scan_res;
 	int oper40;
-	int res;
+	int res = 0;
 
 	/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
 	 * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
@@ -349,7 +349,24 @@
 		}
 	}
 
-	res = ieee80211n_allowed_ht40_channel_pair(iface);
+#ifdef CONFIG_IEEE80211AX
+	if (iface->conf->secondary_channel &&
+	    iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+	    iface->conf->ieee80211ax) {
+		struct he_capabilities *he_cap;
+
+		he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+		if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+		      HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
+			wpa_printf(MSG_DEBUG,
+				   "HE: 40 MHz channel width is not supported in 2.4 GHz; clear secondary channel configuration");
+			iface->conf->secondary_channel = 0;
+		}
+	}
+#endif /* CONFIG_IEEE80211AX */
+
+	if (iface->conf->secondary_channel)
+		res = ieee80211n_allowed_ht40_channel_pair(iface);
 	if (!res) {
 		iface->conf->secondary_channel = 0;
 		hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
@@ -732,6 +749,51 @@
 }
 
 
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_IEEE80211AX
+	struct he_capabilities *he_cap;
+	u16 hw;
+
+	if (!iface->current_mode || !is_6ghz_freq(iface->freq))
+		return 0;
+
+	he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+	hw = he_cap->he_6ghz_capa;
+	if (iface->conf->he_6ghz_max_mpdu >
+	    ((hw & HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK) >>
+	     HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT)) {
+		wpa_printf(MSG_ERROR,
+			   "The driver does not support the configured HE 6 GHz Max MPDU length");
+		return -1;
+	}
+
+	if (iface->conf->he_6ghz_max_ampdu_len_exp >
+	    ((hw & HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
+	     HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT)) {
+		wpa_printf(MSG_ERROR,
+			   "The driver does not support the configured HE 6 GHz Max AMPDU Length Exponent");
+		return -1;
+	}
+
+	if (iface->conf->he_6ghz_rx_ant_pat &&
+	    !(hw & HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS)) {
+		wpa_printf(MSG_ERROR,
+			   "The driver does not support the configured HE 6 GHz Rx Antenna Pattern");
+		return -1;
+	}
+
+	if (iface->conf->he_6ghz_tx_ant_pat &&
+	    !(hw & HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS)) {
+		wpa_printf(MSG_ERROR,
+			   "The driver does not support the configured HE 6 GHz Tx Antenna Pattern");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211AX */
+	return 0;
+}
+
+
 static int hostapd_is_usable_chan(struct hostapd_iface *iface,
 				  int frequency, int primary)
 {
@@ -949,9 +1011,9 @@
 	hostapd_logger(iface->bss[0], NULL,
 		       HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_WARNING,
-		       "Configured channel (%d) or frequency (%d) not found from the channel list of the current mode (%d) %s",
+		       "Configured channel (%d) or frequency (%d) (secondary_channel=%d) not found from the channel list of the current mode (%d) %s",
 		       iface->conf->channel,
-		       iface->freq,
+		       iface->freq, iface->conf->secondary_channel,
 		       iface->current_mode->mode,
 		       hostapd_hw_mode_txt(iface->current_mode->mode));
 	hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@@ -1029,12 +1091,13 @@
 	iface->current_mode = NULL;
 	for (i = 0; i < iface->num_hw_features; i++) {
 		struct hostapd_hw_modes *mode = &iface->hw_features[i];
+		int chan;
+
 		if (mode->mode == iface->conf->hw_mode) {
 			if (iface->freq > 0 &&
-			    !hw_get_chan(mode->mode, iface->freq,
-					 iface->hw_features,
-					 iface->num_hw_features))
+			    !hw_mode_get_channel(mode, iface->freq, &chan))
 				continue;
+
 			iface->current_mode = mode;
 			break;
 		}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index dd24f95..ad0ddf7 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -22,6 +22,7 @@
 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
 int hostapd_check_ht_capab(struct hostapd_iface *iface);
 int hostapd_check_edmg_capab(struct hostapd_iface *iface);
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface);
 int hostapd_prepare_rates(struct hostapd_iface *iface,
 			  struct hostapd_hw_modes *mode);
 void hostapd_stop_setup_timers(struct hostapd_iface *iface);
@@ -85,6 +86,11 @@
 	return 0;
 }
 
+static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+	return 0;
+}
+
 #endif /* NEED_AP_MLME */
 
 #endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index a872893..40d4a33 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -25,6 +25,7 @@
 #include "common/ocv.h"
 #include "common/wpa_common.h"
 #include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "p2p/p2p.h"
@@ -65,6 +66,23 @@
 		       const u8 *msk, size_t msk_len,
 		       int *is_pub);
 #endif /* CONFIG_FILS */
+
+#ifdef CONFIG_PASN
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+				 struct sta_info *sta,
+				 struct rsn_pmksa_cache_entry *pmksa,
+				 u16 status);
+#ifdef CONFIG_FILS
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+				struct sta_info *sta, u16 status,
+				struct wpabuf *erp_resp,
+				const u8 *msk, size_t msk_len);
+
+#endif /* CONFIG_FILS */
+#endif /* CONFIG_PASN */
+
 static void handle_auth(struct hostapd_data *hapd,
 			const struct ieee80211_mgmt *mgmt, size_t len,
 			int rssi, int from_queue);
@@ -469,6 +487,49 @@
 }
 
 
+static const char * sae_get_password(struct hostapd_data *hapd,
+				     struct sta_info *sta,
+				     const char *rx_id,
+				     struct sae_password_entry **pw_entry,
+				     struct sae_pt **s_pt,
+				     const struct sae_pk **s_pk)
+{
+	const char *password = NULL;
+	struct sae_password_entry *pw;
+	struct sae_pt *pt = NULL;
+	const struct sae_pk *pk = NULL;
+
+	for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+		if (!is_broadcast_ether_addr(pw->peer_addr) &&
+		    os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+			continue;
+		if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
+			continue;
+		if (rx_id && pw->identifier &&
+		    os_strcmp(rx_id, pw->identifier) != 0)
+			continue;
+		password = pw->password;
+		pt = pw->pt;
+		if (!(hapd->conf->mesh & MESH_ENABLED))
+			pk = pw->pk;
+		break;
+	}
+	if (!password) {
+		password = hapd->conf->ssid.wpa_passphrase;
+		pt = hapd->conf->ssid.pt;
+	}
+
+	if (pw_entry)
+		*pw_entry = pw;
+	if (s_pt)
+		*s_pt = pt;
+	if (s_pk)
+		*s_pk = pk;
+
+	return password;
+}
+
+
 static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
 					     struct sta_info *sta, int update,
 					     int status_code)
@@ -498,25 +559,7 @@
 		 status_code == WLAN_STATUS_SAE_PK)
 		use_pt = 1;
 
-	for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
-		if (!is_broadcast_ether_addr(pw->peer_addr) &&
-		    os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
-			continue;
-		if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
-			continue;
-		if (rx_id && pw->identifier &&
-		    os_strcmp(rx_id, pw->identifier) != 0)
-			continue;
-		password = pw->password;
-		pt = pw->pt;
-		if (!(hapd->conf->mesh & MESH_ENABLED))
-			pk = pw->pk;
-		break;
-	}
-	if (!password) {
-		password = hapd->conf->ssid.wpa_passphrase;
-		pt = hapd->conf->ssid.pt;
-	}
+	password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
 	if (!password || (use_pt && !pt)) {
 		wpa_printf(MSG_DEBUG, "SAE: No password available");
 		return NULL;
@@ -1149,6 +1192,7 @@
 {
 	int sae_pwe = hapd->conf->sae_pwe;
 	int id_in_use;
+	bool sae_pk = false;
 
 	id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
 	if (id_in_use == 2 && sae_pwe != 3)
@@ -1156,7 +1200,8 @@
 	else if (id_in_use == 1 && sae_pwe == 0)
 		sae_pwe = 2;
 #ifdef CONFIG_SAE_PK
-	if (sae_pwe == 0 && hostapd_sae_pk_in_use(hapd->conf))
+	sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+	if (sae_pwe == 0 && sae_pk)
 		sae_pwe = 2;
 #endif /* CONFIG_SAE_PK */
 
@@ -1164,11 +1209,11 @@
 		status_code == WLAN_STATUS_SUCCESS) ||
 		(sae_pwe == 1 &&
 		 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
-		  status_code == WLAN_STATUS_SAE_PK)) ||
+		  (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
 		(sae_pwe == 2 &&
 		 (status_code == WLAN_STATUS_SUCCESS ||
 		  status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
-		  status_code == WLAN_STATUS_SAE_PK));
+		  (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
 }
 
 
@@ -1232,6 +1277,7 @@
 	int default_groups[] = { 19, 0 };
 	const u8 *pos, *end;
 	int sta_removed = 0;
+	bool success_status;
 
 	if (!groups)
 		groups = default_groups;
@@ -1517,9 +1563,12 @@
 	}
 
 remove_sta:
+	if (auth_transaction == 1)
+		success_status = sae_status_success(hapd, status_code);
+	else
+		success_status = status_code == WLAN_STATUS_SUCCESS;
 	if (!sta_removed && sta->added_unassoc &&
-	    (resp != WLAN_STATUS_SUCCESS ||
-	     status_code != WLAN_STATUS_SUCCESS)) {
+	    (resp != WLAN_STATUS_SUCCESS || !success_status)) {
 		hostapd_drv_sta_remove(hapd, sta->addr);
 		sta->added_unassoc = 0;
 	}
@@ -2183,23 +2232,35 @@
 				 struct wpabuf *erp_resp,
 				 const u8 *msk, size_t msk_len)
 {
-	struct wpabuf *data;
-	int pub = 0;
 	u16 resp;
+	u32 flags = sta->flags;
 
-	sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+	sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
+			WLAN_STA_PENDING_PASN_FILS_ERP);
 
-	if (!sta->fils_pending_cb)
-		return;
 	resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
-	data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
-				      msk, msk_len, &pub);
-	if (!data) {
-		wpa_printf(MSG_DEBUG,
-			   "%s: prepare_auth_resp_fils() returned failure",
-			   __func__);
+
+	if (flags & WLAN_STA_PENDING_FILS_ERP) {
+		struct wpabuf *data;
+		int pub = 0;
+
+		if (!sta->fils_pending_cb)
+			return;
+
+		data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
+					      msk, msk_len, &pub);
+		if (!data) {
+			wpa_printf(MSG_DEBUG,
+				   "%s: prepare_auth_resp_fils() failure",
+				   __func__);
+		}
+		sta->fils_pending_cb(hapd, sta, resp, data, pub);
+#ifdef CONFIG_PASN
+	} else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
+		pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
+				    msk, msk_len);
+#endif /* CONFIG_PASN */
 	}
-	sta->fils_pending_cb(hapd, sta, resp, data, pub);
 }
 
 #endif /* CONFIG_FILS */
@@ -2294,6 +2355,1065 @@
 }
 
 
+#ifdef CONFIG_PASN
+#ifdef CONFIG_SAE
+
+static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
+				     struct sta_info *sta,
+				     struct wpabuf *wd)
+{
+	struct pasn_data *pasn = sta->pasn;
+	const char *password = NULL;
+	const u8 *data;
+	size_t buf_len;
+	u16 res, alg, seq, status;
+	int groups[] = { pasn->group, 0 };
+	int ret;
+
+	if (!wd)
+		return -1;
+
+	data = wpabuf_head_u8(wd);
+	buf_len = wpabuf_len(wd);
+
+	if (buf_len < 6) {
+		wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+			   buf_len);
+		return -1;
+	}
+
+	alg = WPA_GET_LE16(data);
+	seq = WPA_GET_LE16(data + 2);
+	status = WPA_GET_LE16(data + 4);
+
+	wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
+		   alg, seq, status);
+
+	/* TODO: SAE H2E */
+	if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
+		return -1;
+	}
+
+	sae_clear_data(&pasn->sae);
+	pasn->sae.state = SAE_NOTHING;
+
+	ret = sae_set_group(&pasn->sae, pasn->group);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
+		return -1;
+	}
+
+	password = sae_get_password(hapd, sta, NULL, NULL, NULL, NULL);
+	if (!password) {
+		wpa_printf(MSG_DEBUG, "PASN: No SAE password found");
+		return -1;
+	}
+
+	ret = sae_prepare_commit(hapd->own_addr, sta->addr,
+				 (const u8 *) password, os_strlen(password), 0,
+				 &pasn->sae);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
+		return -1;
+	}
+
+	res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
+			       groups, 0);
+	if (res != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
+		return -1;
+	}
+
+	/* Process the commit message and derive the PMK */
+	ret = sae_process_commit(&pasn->sae);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
+		return -1;
+	}
+
+	pasn->sae.state = SAE_COMMITTED;
+
+	return 0;
+}
+
+
+static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
+				      struct sta_info *sta,
+				      struct wpabuf *wd)
+{
+	struct pasn_data *pasn = sta->pasn;
+	const u8 *data;
+	size_t buf_len;
+	u16 res, alg, seq, status;
+
+	if (!wd)
+		return -1;
+
+	data = wpabuf_head_u8(wd);
+	buf_len = wpabuf_len(wd);
+
+	if (buf_len < 6) {
+		wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+			   buf_len);
+		return -1;
+	}
+
+	alg = WPA_GET_LE16(data);
+	seq = WPA_GET_LE16(data + 2);
+	status = WPA_GET_LE16(data + 4);
+
+	wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
+		   alg, seq, status);
+
+	if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
+		return -1;
+	}
+
+	res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6);
+	if (res != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
+		return -1;
+	}
+
+	pasn->sae.state = SAE_ACCEPTED;
+
+	/*
+	 * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
+	 * PASN/SAE should only be allowed with future PASN only. For now do not
+	 * restrict this only for PASN.
+	 */
+	wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+			       pasn->sae.pmk, pasn->sae.pmkid);
+	return 0;
+}
+
+
+static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+	struct pasn_data *pasn = sta->pasn;
+	struct wpabuf *buf = NULL;
+	u8 *len_ptr;
+	size_t len;
+
+	/* Need to add the entire Authentication frame body */
+	buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
+	if (!buf) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+		return NULL;
+	}
+
+	/* Need to add the entire authentication frame body for the commit */
+	len_ptr = wpabuf_put(buf, 2);
+	wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+	wpabuf_put_le16(buf, 1);
+	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+	/* Write the actual commit and update the length accordingly */
+	sae_write_commit(&pasn->sae, buf, NULL, 0);
+	len = wpabuf_len(buf);
+	WPA_PUT_LE16(len_ptr, len - 2);
+
+	/* Need to add the entire Authentication frame body for the confirm */
+	len_ptr = wpabuf_put(buf, 2);
+	wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+	wpabuf_put_le16(buf, 2);
+	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+	sae_write_confirm(&pasn->sae, buf);
+	WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
+
+	pasn->sae.state = SAE_CONFIRMED;
+
+	return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+
+static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
+					struct sta_info *sta)
+{
+	struct pasn_data *pasn = sta->pasn;
+	struct pasn_fils_data *fils = &pasn->fils;
+	struct wpabuf *buf = NULL;
+
+	if (!fils->erp_resp) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
+		return NULL;
+	}
+
+	buf = wpabuf_alloc(1500);
+	if (!buf)
+		return NULL;
+
+	/* Add the authentication algorithm */
+	wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
+
+	/* Authentication Transaction seq# */
+	wpabuf_put_le16(buf, 2);
+
+	/* Status Code */
+	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+	/* Own RSNE */
+	wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+
+	/* FILS Nonce */
+	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+	wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
+	wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+	wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
+
+	/* FILS Session */
+	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+	wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
+	wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+	wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
+
+	/* Wrapped Data */
+	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+	wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
+	wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+	wpabuf_put_buf(buf, fils->erp_resp);
+
+	return buf;
+}
+
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+				struct sta_info *sta, u16 status,
+				struct wpabuf *erp_resp,
+				const u8 *msk, size_t msk_len)
+{
+	struct pasn_data *pasn = sta->pasn;
+	struct pasn_fils_data *fils = &pasn->fils;
+	u8 pmk[PMK_LEN_MAX];
+	size_t pmk_len;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
+		   status);
+
+	if (status != WLAN_STATUS_SUCCESS)
+		goto fail;
+
+	if (!pasn->secret) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
+		goto fail;
+	}
+
+	if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
+		goto fail;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
+		    fils->anonce, FILS_NONCE_LEN);
+
+	ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
+			       fils->anonce, NULL, 0, pmk, &pmk_len);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
+		goto fail;
+	}
+
+	ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+			      wpabuf_head(pasn->secret),
+			      wpabuf_len(pasn->secret),
+			      &sta->pasn->ptk, sta->pasn->akmp,
+			      sta->pasn->cipher, WPA_KDK_MAX_LEN);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
+		goto fail;
+	}
+
+	wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+
+	wpabuf_free(pasn->secret);
+	pasn->secret = NULL;
+
+	fils->erp_resp = erp_resp;
+	ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
+	fils->erp_resp = NULL;
+
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
+		goto fail;
+	}
+
+	fils->state = PASN_FILS_STATE_COMPLETE;
+	return;
+fail:
+	ap_free_sta(hapd, sta);
+}
+
+
+static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
+			       struct wpabuf *wd)
+{
+	struct pasn_data *pasn = sta->pasn;
+	struct pasn_fils_data *fils = &pasn->fils;
+	struct ieee802_11_elems elems;
+	struct wpa_ie_data rsne_data;
+	struct wpabuf *fils_wd;
+	const u8 *data;
+	size_t buf_len;
+	u16 alg, seq, status;
+	int ret;
+
+	if (fils->state != PASN_FILS_STATE_NONE) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
+		return -1;
+	}
+
+	if (!wd) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
+		return -1;
+	}
+
+	data = wpabuf_head_u8(wd);
+	buf_len = wpabuf_len(wd);
+
+	if (buf_len < 6) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%lu",
+			   buf_len);
+		return -1;
+	}
+
+	alg = WPA_GET_LE16(data);
+	seq = WPA_GET_LE16(data + 2);
+	status = WPA_GET_LE16(data + 4);
+
+	wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
+		   alg, seq, status);
+
+	if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
+	    status != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: FILS: Dropping peer authentication");
+		return -1;
+	}
+
+	data += 6;
+	buf_len -= 6;
+
+	if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
+		return -1;
+	}
+
+	if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
+	    !elems.wrapped_data) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
+		return -1;
+	}
+
+	ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+				   &rsne_data);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
+		return -1;
+	}
+
+	ret = wpa_pasn_validate_rsne(&rsne_data);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
+		return -1;
+	}
+
+	if (rsne_data.num_pmkid) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: FILS: Not expecting PMKID in RSNE");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
+		    FILS_NONCE_LEN);
+	os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+	wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
+		    FILS_SESSION_LEN);
+	os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
+
+#ifdef CONFIG_NO_RADIUS
+	wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
+	return -1;
+#endif /* CONFIG_NO_RADIUS */
+
+	fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
+				    WLAN_EID_EXT_WRAPPED_DATA);
+
+	if (!fils_wd) {
+		wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
+		return -1;
+	}
+
+	if (!sta->eapol_sm)
+		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+
+	wpa_printf(MSG_DEBUG,
+		   "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
+
+	ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
+				      wpabuf_len(fils_wd));
+
+	sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
+
+	fils->state = PASN_FILS_STATE_PENDING_AS;
+
+	/*
+	 * Calculate pending PMKID here so that we do not need to maintain a
+	 * copy of the EAP-Initiate/Reautt message.
+	 */
+	fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
+		       fils->erp_pmkid);
+
+	wpabuf_free(fils_wd);
+	return 0;
+}
+
+#endif /* CONFIG_FILS */
+
+
+static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
+					     struct sta_info *sta)
+{
+	switch (sta->pasn->akmp) {
+	case WPA_KEY_MGMT_PASN:
+		/* no wrapped data */
+		return NULL;
+	case WPA_KEY_MGMT_SAE:
+#ifdef CONFIG_SAE
+		return pasn_get_sae_wd(hapd, sta);
+#else /* CONFIG_SAE */
+		wpa_printf(MSG_ERROR,
+			   "PASN: SAE: Cannot derive wrapped data");
+		return NULL;
+#endif /* CONFIG_SAE */
+	case WPA_KEY_MGMT_FILS_SHA256:
+	case WPA_KEY_MGMT_FILS_SHA384:
+#ifdef CONFIG_FILS
+		return pasn_get_fils_wd(hapd, sta);
+#endif /* CONFIG_FILS */
+		/* fall through */
+	case WPA_KEY_MGMT_FT_PSK:
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+	default:
+		wpa_printf(MSG_ERROR,
+			   "PASN: TODO: Wrapped data for akmp=0x%x",
+			   sta->pasn->akmp);
+		return NULL;
+	}
+}
+
+
+static int
+pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
+		 const u8 *cached_pmk, size_t cached_pmk_len,
+		 struct wpa_pasn_params_data *pasn_data,
+		 struct wpabuf *wrapped_data,
+		 struct wpabuf *secret)
+{
+	static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
+	u8 pmk[PMK_LEN_MAX];
+	u8 pmk_len;
+	int ret;
+
+	os_memset(pmk, 0, sizeof(pmk));
+	pmk_len = 0;
+
+	if (!cached_pmk || !cached_pmk_len)
+		wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
+
+	if (sta->pasn->akmp == WPA_KEY_MGMT_PASN) {
+		wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
+
+		pmk_len = WPA_PASN_PMK_LEN;
+		os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
+	} else if (cached_pmk && cached_pmk_len) {
+		wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
+
+		pmk_len = cached_pmk_len;
+		os_memcpy(pmk, cached_pmk, cached_pmk_len);
+	} else {
+		switch (sta->pasn->akmp) {
+#ifdef CONFIG_SAE
+		case WPA_KEY_MGMT_SAE:
+			if (sta->pasn->sae.state == SAE_COMMITTED) {
+				pmk_len = PMK_LEN;
+				os_memcpy(pmk, sta->pasn->sae.pmk, PMK_LEN);
+				break;
+			}
+#endif /* CONFIG_SAE */
+			/* fall through */
+		default:
+			/* TODO: Derive PMK based on wrapped data */
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Missing PMK derivation");
+			return -1;
+		}
+	}
+
+	ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+			      wpabuf_head(secret), wpabuf_len(secret),
+			      &sta->pasn->ptk, sta->pasn->akmp,
+			      sta->pasn->cipher, WPA_KDK_MAX_LEN);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+	return 0;
+}
+
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+				 struct sta_info *sta,
+				 struct rsn_pmksa_cache_entry *pmksa,
+				 u16 status)
+{
+	struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
+	u8 mic[WPA_PASN_MAX_MIC_LEN];
+	u8 mic_len, frame_len, data_len;
+	u8 *ptr;
+	const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
+	u8 *data_buf = NULL;
+	size_t rsn_ie_len;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
+
+	buf = wpabuf_alloc(1500);
+	if (!buf)
+		goto fail;
+
+	wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+				   sta->addr, 2, status);
+
+	if (status != WLAN_STATUS_SUCCESS)
+		goto done;
+
+	if (wpa_pasn_add_rsne(buf, pmksa ? pmksa->pmkid : NULL,
+			      sta->pasn->akmp, sta->pasn->cipher) < 0)
+		goto fail;
+
+	/* No need to derive PMK if PMKSA is given */
+	if (!pmksa)
+		wrapped_data_buf = pasn_get_wrapped_data(hapd, sta);
+	else
+		sta->pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
+
+	/* Get public key */
+	pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0);
+	pubkey = wpabuf_zeropad(pubkey,
+				crypto_ecdh_prime_len(sta->pasn->ecdh));
+	if (!pubkey) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
+		goto fail;
+	}
+
+	wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
+				  sta->pasn->wrapped_data_format,
+				  pubkey, NULL, 0);
+
+	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+		goto fail;
+
+	wpabuf_free(wrapped_data_buf);
+	wrapped_data_buf = NULL;
+	wpabuf_free(pubkey);
+	pubkey = NULL;
+
+	/* Add RSNXE if needed */
+	rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+	if (rsnxe_ie)
+		wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
+
+	/* Add the mic */
+	mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+	wpabuf_put_u8(buf, WLAN_EID_MIC);
+	wpabuf_put_u8(buf, mic_len);
+	ptr = wpabuf_put(buf, mic_len);
+
+	os_memset(ptr, 0, mic_len);
+
+	frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
+	frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
+
+	rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
+	if (!rsn_ie || !rsn_ie_len)
+		goto fail;
+
+	/*
+	 * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
+	 * MDE, etc. Thus, do not use the returned length but instead use the
+	 * length specified in the IE header.
+	 */
+	data_len = rsn_ie[1] + 2;
+	if (rsnxe_ie) {
+		data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
+		if (!data_buf)
+			goto fail;
+
+		os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
+		os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
+		data_len += rsnxe_ie[1] + 2;
+		data = data_buf;
+	} else {
+		data = rsn_ie;
+	}
+
+	ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+		       hapd->own_addr, sta->addr, data, data_len,
+		       frame, frame_len, mic);
+	os_free(data_buf);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
+		goto fail;
+	}
+
+	os_memcpy(ptr, mic, mic_len);
+
+done:
+	wpa_printf(MSG_DEBUG,
+		   "PASN: Building frame 2: success; resp STA=" MACSTR,
+		   MAC2STR(sta->addr));
+
+	ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+				    NULL, 0, 0);
+	if (ret)
+		wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
+
+	wpabuf_free(buf);
+	return ret;
+fail:
+	wpabuf_free(wrapped_data_buf);
+	wpabuf_free(pubkey);
+	wpabuf_free(buf);
+	return -1;
+}
+
+
+static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
+			       const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct ieee802_11_elems elems;
+	struct wpa_ie_data rsn_data;
+	struct wpa_pasn_params_data pasn_params;
+	struct rsn_pmksa_cache_entry *pmksa = NULL;
+	const u8 *cached_pmk = NULL;
+	size_t cached_pmk_len = 0;
+#ifdef CONFIG_IEEE80211R_AP
+	u8 pmk_r1[PMK_LEN_MAX];
+	size_t pmk_r1_len;
+#endif /* CONFIG_IEEE80211R_AP */
+	struct wpabuf *wrapped_data = NULL, *secret = NULL;
+	const int *groups = hapd->conf->pasn_groups;
+	static const int default_groups[] = { 19, 0 };
+	u16 status = WLAN_STATUS_SUCCESS;
+	int ret;
+	bool derive_keys;
+	u32 i;
+
+	if (!groups)
+		groups = default_groups;
+
+	if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+				   len - offsetof(struct ieee80211_mgmt,
+						  u.auth.variable),
+				   &elems, 0) == ParseFailed) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed parsing Authentication frame");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+				   &rsn_data);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
+		status = WLAN_STATUS_INVALID_RSNIE;
+		goto send_resp;
+	}
+
+	ret = wpa_pasn_validate_rsne(&rsn_data);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
+		status = WLAN_STATUS_INVALID_RSNIE;
+		goto send_resp;
+	}
+
+	if (!(rsn_data.key_mgmt & hapd->conf->wpa_key_mgmt) ||
+	    !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) {
+		wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
+		status = WLAN_STATUS_INVALID_RSNIE;
+		goto send_resp;
+	}
+
+	sta->pasn->akmp = rsn_data.key_mgmt;
+	sta->pasn->cipher = rsn_data.pairwise_cipher;
+
+	if (!elems.pasn_params || !elems.pasn_params_len) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: No PASN Parameters element found");
+		status = WLAN_STATUS_INVALID_PARAMETERS;
+		goto send_resp;
+	}
+
+	ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+					  elems.pasn_params_len + 3,
+					  false, &pasn_params);
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed validation of PASN Parameters IE");
+		status = WLAN_STATUS_INVALID_PARAMETERS;
+		goto send_resp;
+	}
+
+	for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
+		;
+
+	if (!pasn_params.group || groups[i] != pasn_params.group) {
+		wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
+			   pasn_params.group);
+		status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+		goto send_resp;
+	}
+
+	if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
+		wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
+	if (!sta->pasn->ecdh) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	sta->pasn->group = pasn_params.group;
+
+	secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, 0,
+					 pasn_params.pubkey,
+					 pasn_params.pubkey_len);
+	if (!secret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	derive_keys = true;
+	if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+		wrapped_data = ieee802_11_defrag(&elems,
+						 WLAN_EID_EXTENSION,
+						 WLAN_EID_EXT_WRAPPED_DATA);
+		if (!wrapped_data) {
+			wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto send_resp;
+		}
+
+#ifdef CONFIG_SAE
+		if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+			ret = pasn_wd_handle_sae_commit(hapd, sta,
+							wrapped_data);
+			if (ret) {
+				wpa_printf(MSG_DEBUG,
+					   "PASN: Failed processing SAE commit");
+				status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto send_resp;
+			}
+		}
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+		if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+		    sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+			ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
+			if (ret) {
+				wpa_printf(MSG_DEBUG,
+					   "PASN: Failed processing FILS wrapped data");
+				status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto send_resp;
+			}
+
+			wpa_printf(MSG_DEBUG,
+				   "PASN: FILS: Pending AS response");
+
+			/*
+			 * With PASN/FILS, keys can be derived only after a
+			 * response from the AS is processed.
+			 */
+			derive_keys = false;
+		}
+#endif /* CONFIG_FILS */
+	}
+
+	sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
+
+	ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+				   ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+				   len - IEEE80211_HDRLEN, sta->pasn->hash);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	if (!derive_keys) {
+		wpa_printf(MSG_DEBUG, "PASN: Storing secret");
+		sta->pasn->secret = secret;
+		wpabuf_free(wrapped_data);
+		return;
+	}
+
+	if (rsn_data.num_pmkid) {
+		if (wpa_key_mgmt_ft(sta->pasn->akmp)) {
+#ifdef CONFIG_IEEE80211R_AP
+			wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
+
+			ret = wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
+						  rsn_data.pmkid,
+						  pmk_r1, &pmk_r1_len, NULL,
+						  NULL, NULL, NULL,
+						  NULL, NULL, NULL);
+			if (ret) {
+				wpa_printf(MSG_DEBUG,
+					   "PASN: FT: Failed getting PMK-R1");
+				status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto send_resp;
+			}
+			cached_pmk = pmk_r1;
+			cached_pmk_len = pmk_r1_len;
+#else /* CONFIG_IEEE80211R_AP */
+			wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto send_resp;
+#endif /* CONFIG_IEEE80211R_AP */
+		} else {
+			wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
+
+			pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
+						   rsn_data.pmkid);
+			if (pmksa) {
+				cached_pmk = pmksa->pmk;
+				cached_pmk_len = pmksa->pmk_len;
+			}
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
+	}
+
+	ret = pasn_derive_keys(hapd, sta, cached_pmk, cached_pmk_len,
+			       &pasn_params, wrapped_data, secret);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+				   ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+				   len - IEEE80211_HDRLEN, sta->pasn->hash);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+send_resp:
+	ret = handle_auth_pasn_resp(hapd, sta, pmksa, status);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Success handling transaction == 1");
+	}
+
+	wpabuf_free(secret);
+	wpabuf_free(wrapped_data);
+
+	if (status != WLAN_STATUS_SUCCESS)
+		ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta,
+			       const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct ieee802_11_elems elems;
+	struct wpa_pasn_params_data pasn_params;
+	struct wpabuf *wrapped_data = NULL;
+	u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
+	u8 mic_len;
+	int ret;
+
+	if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+				   len - offsetof(struct ieee80211_mgmt,
+						  u.auth.variable),
+				   &elems, 0) == ParseFailed) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed parsing Authentication frame");
+		goto fail;
+	}
+
+	/* Check that the MIC IE exists. Save it and zero out the memory. */
+	mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+	if (!elems.mic || elems.mic_len != mic_len) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Invalid MIC. Expecting len=%u", mic_len);
+		goto fail;
+	} else {
+		os_memcpy(mic, elems.mic, mic_len);
+		/* TODO: Clean this up.. Should not modify received frame
+		 * buffer. */
+		os_memset((u8 *) elems.mic, 0, mic_len);
+	}
+
+	if (!elems.pasn_params || !elems.pasn_params_len) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: No PASN Parameters element found");
+		goto fail;
+	}
+
+	ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+					  elems.pasn_params_len + 3,
+					  false, &pasn_params);
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed validation of PASN Parameters IE");
+		goto fail;
+	}
+
+	if (pasn_params.pubkey || pasn_params.pubkey_len) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Public key should not be included");
+		goto fail;
+	}
+
+	/* Verify the MIC */
+	ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+		       sta->addr, hapd->own_addr,
+		       sta->pasn->hash, mic_len * 2,
+		       (u8 *) &mgmt->u.auth,
+		       len - offsetof(struct ieee80211_mgmt, u.auth),
+		       out_mic);
+
+	wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
+	if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
+		goto fail;
+	}
+
+	if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+		wrapped_data = ieee802_11_defrag(&elems,
+						 WLAN_EID_EXTENSION,
+						 WLAN_EID_EXT_WRAPPED_DATA);
+
+		if (!wrapped_data) {
+			wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+			goto fail;
+		}
+
+#ifdef CONFIG_SAE
+		if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+			ret = pasn_wd_handle_sae_confirm(hapd, sta,
+							 wrapped_data);
+			if (ret) {
+				wpa_printf(MSG_DEBUG,
+					   "PASN: Failed processing SAE confirm");
+				wpabuf_free(wrapped_data);
+				goto fail;
+			}
+		}
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+		if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+		    sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+			if (wrapped_data) {
+				wpa_printf(MSG_DEBUG,
+					   "PASN: FILS: Ignore wrapped data");
+			}
+		}
+#endif /* CONFIG_FILS */
+		wpabuf_free(wrapped_data);
+	}
+
+	wpa_printf(MSG_INFO,
+		   "PASN: Success handling transaction == 3. Store PTK");
+
+	ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200,
+			&sta->pasn->ptk);
+fail:
+	ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
+			     const struct ieee80211_mgmt *mgmt, size_t len,
+			     u16 trans_seq, u16 status)
+{
+	if (hapd->conf->wpa != WPA_PROTO_RSN) {
+		wpa_printf(MSG_INFO, "PASN: RSN is not configured");
+		return;
+	}
+
+	wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
+		   MAC2STR(sta->addr));
+
+	if (trans_seq == 1) {
+		if (sta->pasn) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Not expecting transaction == 1");
+			return;
+		}
+
+		if (status != WLAN_STATUS_SUCCESS) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Failure status in transaction == 1");
+			return;
+		}
+
+		sta->pasn = os_zalloc(sizeof(*sta->pasn));
+		if (!sta->pasn) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Failed to allocate PASN context");
+			return;
+		}
+
+		handle_auth_pasn_1(hapd, sta, mgmt, len);
+	} else if (trans_seq == 3) {
+		if (!sta->pasn) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Not expecting transaction == 3");
+			return;
+		}
+
+		if (status != WLAN_STATUS_SUCCESS) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Failure status in transaction == 3");
+			ap_free_sta_pasn(hapd, sta);
+			return;
+		}
+
+		handle_auth_pasn_3(hapd, sta, mgmt, len);
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Invalid transaction %u - ignore", trans_seq);
+	}
+}
+
+#endif /* CONFIG_PASN */
+
+
 static void handle_auth(struct hostapd_data *hapd,
 			const struct ieee80211_mgmt *mgmt, size_t len,
 			int rssi, int from_queue)
@@ -2380,6 +3500,11 @@
 	       hapd->conf->fils_dh_group &&
 	       auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
 #endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+	      (hapd->conf->wpa &&
+	       (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
+	       auth_alg == WLAN_AUTH_PASN) ||
+#endif /* CONFIG_PASN */
 	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
 	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
 		wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
@@ -2389,6 +3514,9 @@
 	}
 
 	if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
+#ifdef CONFIG_PASN
+	      (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
+#endif /* CONFIG_PASN */
 	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
 		wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
 			   auth_transaction);
@@ -2510,6 +3638,15 @@
 			return;
 		}
 #endif /* CONFIG_MESH */
+#ifdef CONFIG_PASN
+		if (auth_alg == WLAN_AUTH_PASN &&
+		    (sta->flags & WLAN_STA_ASSOC)) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: auth: Existing station: " MACSTR,
+				   MAC2STR(sta->addr));
+			return;
+		}
+#endif /* CONFIG_PASN */
 	} else {
 #ifdef CONFIG_MESH
 		if (hapd->conf->mesh & MESH_ENABLED) {
@@ -2570,11 +3707,14 @@
 	 * to allow the original connection work until the attempt can complete
 	 * (re)association, so that unprotected Authentication frame cannot be
 	 * used to bypass PMF protection.
+	 *
+	 * PASN authentication does not require adding/removing station to the
+	 * driver so skip this flow in case of PASN authentication.
 	 */
 	if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
 	    (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
 	    !(hapd->conf->mesh & MESH_ENABLED) &&
-	    !(sta->added_unassoc)) {
+	    !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
 		if (ap_sta_re_add(hapd, sta) < 0) {
 			resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 			goto fail;
@@ -2661,6 +3801,12 @@
 				 handle_auth_fils_finish);
 		return;
 #endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+	case WLAN_AUTH_PASN:
+		handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
+				 status_code);
+		return;
+#endif /* CONFIG_PASN */
 	}
 
  fail:
@@ -3252,7 +4398,7 @@
 	}
 #endif /* CONFIG_IEEE80211AC */
 #ifdef CONFIG_IEEE80211AX
-	if (hapd->iconf->ieee80211ax) {
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
 		resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
 					 elems.he_capabilities,
 					 elems.he_capabilities_len);
@@ -3868,7 +5014,7 @@
 #endif /* CONFIG_IEEE80211AC */
 
 #ifdef CONFIG_IEEE80211AX
-	if (hapd->iconf->ieee80211ax) {
+	if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
 		p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
 		p = hostapd_eid_he_operation(hapd, p);
 		p = hostapd_eid_spatial_reuse(hapd, p);
@@ -4882,6 +6028,31 @@
 
 
 /**
+ * notify_mgmt_frame - Notify of Management frames on the control interface
+ * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
+ * sent to)
+ * @buf: Management frame data (starting from the IEEE 802.11 header)
+ * @len: Length of frame data in octets
+ *
+ * Notify the control interface of any received Management frame.
+ */
+static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
+			      size_t len)
+{
+
+	int hex_len = len * 2 + 1;
+	char *hex = os_malloc(hex_len);
+
+	if (hex) {
+		wpa_snprintf_hex(hex, hex_len, buf, len);
+		wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
+			     AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
+		os_free(hex);
+	}
+}
+
+
+/**
  * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
  * @hapd: hostapd BSS data structure (the BSS to which the management frame was
  * sent to)
@@ -4971,6 +6142,9 @@
 	if (hapd->iconf->track_sta_max_num)
 		sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
 
+	if (hapd->conf->notify_mgmt_frames)
+		notify_mgmt_frame(hapd, buf, len);
+
 	switch (stype) {
 	case WLAN_FC_STYPE_AUTH:
 		wpa_printf(MSG_DEBUG, "mgmt::auth");
@@ -5018,18 +6192,7 @@
 {
 	u16 auth_alg, auth_transaction, status_code;
 	struct sta_info *sta;
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
-			   (unsigned long) len);
-
-		/*
-		 * Initialize status_code here because we are not able to read
-		 * it from the short payload.
-		 */
-		status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
-		goto fail;
-	}
+	bool success_status;
 
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
@@ -5039,6 +6202,15 @@
 		return;
 	}
 
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+		wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+			   (unsigned long) len);
+		auth_alg = 0;
+		auth_transaction = 0;
+		status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
 	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
 	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
 	status_code = le_to_host16(mgmt->u.auth.status_code);
@@ -5062,7 +6234,12 @@
 	}
 
 fail:
-	if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+	success_status = status_code == WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_SAE
+	if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
+		success_status = sae_status_success(hapd, status_code);
+#endif /* CONFIG_SAE */
+	if (!success_status && sta->added_unassoc) {
 		hostapd_drv_sta_remove(hapd, sta->addr);
 		sta->added_unassoc = 0;
 	}
@@ -5592,6 +6769,118 @@
 }
 
 
+u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	struct hostapd_config *iconf = iface->conf;
+	struct hostapd_hw_modes *mode = iface->current_mode;
+	struct hostapd_channel_data *chan;
+	int dfs, i;
+	u8 channel, tx_pwr_count, local_pwr_constraint;
+	int max_tx_power;
+	u8 tx_pwr;
+
+	if (!mode)
+		return eid;
+
+	if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
+		return eid;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		if (mode->channels[i].freq == iface->freq)
+			break;
+	}
+	if (i == mode->num_channels)
+		return eid;
+
+	switch (hostapd_get_oper_chwidth(iconf)) {
+	case CHANWIDTH_USE_HT:
+		if (iconf->secondary_channel == 0) {
+			/* Max Transmit Power count = 0 (20 MHz) */
+			tx_pwr_count = 0;
+		} else {
+			/* Max Transmit Power count = 1 (20, 40 MHz) */
+			tx_pwr_count = 1;
+		}
+		break;
+	case CHANWIDTH_80MHZ:
+		/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
+		tx_pwr_count = 2;
+		break;
+	case CHANWIDTH_80P80MHZ:
+	case CHANWIDTH_160MHZ:
+		/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
+		tx_pwr_count = 3;
+		break;
+	default:
+		return eid;
+	}
+
+	/*
+	 * Below local_pwr_constraint logic is referred from
+	 * hostapd_eid_pwr_constraint.
+	 *
+	 * Check if DFS is required by regulatory.
+	 */
+	dfs = hostapd_is_dfs_required(hapd->iface);
+	if (dfs < 0)
+		dfs = 0;
+
+	/*
+	 * In order to meet regulations when TPC is not implemented using
+	 * a transmit power that is below the legal maximum (including any
+	 * mitigation factor) should help. In this case, indicate 3 dB below
+	 * maximum allowed transmit power.
+	 */
+	if (hapd->iconf->local_pwr_constraint == -1)
+		local_pwr_constraint = (dfs == 0) ? 0 : 3;
+	else
+		local_pwr_constraint = hapd->iconf->local_pwr_constraint;
+
+	/*
+	 * A STA that is not an AP shall use a transmit power less than or
+	 * equal to the local maximum transmit power level for the channel.
+	 * The local maximum transmit power can be calculated from the formula:
+	 * local max TX pwr = max TX pwr - local pwr constraint
+	 * Where max TX pwr is maximum transmit power level specified for
+	 * channel in Country element and local pwr constraint is specified
+	 * for channel in this Power Constraint element.
+	 */
+	chan = &mode->channels[i];
+	max_tx_power = chan->max_tx_power - local_pwr_constraint;
+
+	/*
+	 * Local Maximum Transmit power is encoded as two's complement
+	 * with a 0.5 dB step.
+	 */
+	max_tx_power *= 2; /* in 0.5 dB steps */
+	if (max_tx_power > 127) {
+		/* 63.5 has special meaning of 63.5 dBm or higher */
+		max_tx_power = 127;
+	}
+	if (max_tx_power < -128)
+		max_tx_power = -128;
+	if (max_tx_power < 0)
+		tx_pwr = 0x80 + max_tx_power + 128;
+	else
+		tx_pwr = max_tx_power;
+
+	*eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE;
+	*eid++ = 2 + tx_pwr_count;
+
+	/*
+	 * Max Transmit Power count and
+	 * Max Transmit Power units = 0 (EIRP)
+	 */
+	*eid++ = tx_pwr_count;
+
+	for (i = 0; i <= tx_pwr_count; i++)
+		*eid++ = tx_pwr;
+
+	return eid;
+}
+
+
 u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
 {
 	u8 bw, chan1, chan2 = 0;
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 85b7140..c27bb1f 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -304,6 +304,11 @@
 	if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
 		*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
 		*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
+		os_memcpy(spr_param,
+			  hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+		spr_param += 8;
+		os_memcpy(spr_param,
+			  hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
 		pos += 18;
 	}
 
@@ -313,6 +318,7 @@
 
 u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
 {
+	struct hostapd_config *conf = hapd->iface->conf;
 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
 	struct he_capabilities *he_cap;
 	struct ieee80211_he_6ghz_band_cap *cap;
@@ -324,8 +330,18 @@
 		return eid;
 
 	he_cap = &mode->he_capab[IEEE80211_MODE_AP];
-	capab = he_cap->he_6ghz_capa;
+	capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START;
+	capab |= (conf->he_6ghz_max_ampdu_len_exp <<
+		  HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) &
+		HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK;
+	capab |= (conf->he_6ghz_max_mpdu <<
+		  HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) &
+		HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK;
 	capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
+	if (conf->he_6ghz_rx_ant_pat)
+		capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS;
+	if (conf->he_6ghz_tx_ant_pat)
+		capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS;
 
 	pos = eid;
 	*pos++ = WLAN_EID_EXTENSION;
@@ -419,6 +435,7 @@
 		      size_t he_capab_len)
 {
 	if (!he_capab || !hapd->iconf->ieee80211ax ||
+	    hapd->conf->disable_11ax ||
 	    !check_valid_he_mcs(hapd, he_capab, opmode) ||
 	    ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
 	    he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
@@ -448,6 +465,7 @@
 			   const u8 *he_6ghz_capab)
 {
 	if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
+	    hapd->conf->disable_11ax ||
 	    !is_6ghz_op_class(hapd->iconf->op_class)) {
 		sta->flags &= ~WLAN_STA_6GHZ;
 		os_free(sta->he_6ghz_capab);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 17003d5..a429b5d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -425,7 +425,9 @@
 					       * Identifiers Used Exclusively */
 		}
 #endif /* CONFIG_SAE */
-		if (hapd->conf->beacon_prot)
+		if (hapd->conf->beacon_prot &&
+		    (hapd->iface->drv_flags &
+		     WPA_DRIVER_FLAGS_BEACON_PROTECTION))
 			*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
 		break;
 	case 11: /* Bits 88-95 */
@@ -494,7 +496,8 @@
 	    hostapd_sae_pw_id_in_use(hapd->conf))
 		len = 11;
 #endif /* CONFIG_SAE */
-	if (len < 11 && hapd->conf->beacon_prot)
+	if (len < 11 && hapd->conf->beacon_prot &&
+	    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
 		len = 11;
 #ifdef CONFIG_SAE_PK
 	if (len < 12 && hapd->conf->wpa &&
@@ -1097,29 +1100,45 @@
 {
 	u8 *pos = eid;
 	bool sae_pk = false;
+	u16 capab = 0;
+	size_t flen;
+
+	if (!(hapd->conf->wpa & WPA_PROTO_RSN))
+		return eid;
 
 #ifdef CONFIG_SAE_PK
 	sae_pk = hostapd_sae_pk_in_use(hapd->conf);
 #endif /* CONFIG_SAE_PK */
 
-	if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
-	    !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
-	    (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
-	     !hostapd_sae_pw_id_in_use(hapd->conf) && !sae_pk) ||
-	    hapd->conf->sae_pwe == 3 ||
-	    len < 3)
-		return pos;
+	if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+	    (hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
+	     hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
+	    hapd->conf->sae_pwe != 3) {
+		capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+		if (sae_pk)
+			capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+	}
+
+	if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+	if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+	if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+		capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+	flen = (capab & 0xff00) ? 2 : 1;
+	if (len < 2 + flen || !capab)
+		return eid; /* no supported extended RSN capabilities */
+	capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
 
 	*pos++ = WLAN_EID_RSNX;
-	*pos++ = 1;
-	/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
-	 * used for now */
-	*pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
-#ifdef CONFIG_SAE_PK
-	if (sae_pk)
-		*pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
-#endif /* CONFIG_SAE_PK */
-	pos++;
+	*pos++ = flen;
+	*pos++ = capab & 0x00ff;
+	capab >>= 8;
+	if (capab)
+		*pos++ = capab;
 
 	return pos;
 }
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index c925bf1..d037022 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -167,118 +167,6 @@
 }
 
 
-u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
-{
-	struct hostapd_iface *iface = hapd->iface;
-	struct hostapd_config *iconf = iface->conf;
-	struct hostapd_hw_modes *mode = iface->current_mode;
-	struct hostapd_channel_data *chan;
-	int dfs, i;
-	u8 channel, tx_pwr_count, local_pwr_constraint;
-	int max_tx_power;
-	u8 tx_pwr;
-
-	if (!mode)
-		return eid;
-
-	if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
-		return eid;
-
-	for (i = 0; i < mode->num_channels; i++) {
-		if (mode->channels[i].freq == iface->freq)
-			break;
-	}
-	if (i == mode->num_channels)
-		return eid;
-
-	switch (iface->conf->vht_oper_chwidth) {
-	case CHANWIDTH_USE_HT:
-		if (iconf->secondary_channel == 0) {
-			/* Max Transmit Power count = 0 (20 MHz) */
-			tx_pwr_count = 0;
-		} else {
-			/* Max Transmit Power count = 1 (20, 40 MHz) */
-			tx_pwr_count = 1;
-		}
-		break;
-	case CHANWIDTH_80MHZ:
-		/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
-		tx_pwr_count = 2;
-		break;
-	case CHANWIDTH_80P80MHZ:
-	case CHANWIDTH_160MHZ:
-		/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
-		tx_pwr_count = 3;
-		break;
-	default:
-		return eid;
-	}
-
-	/*
-	 * Below local_pwr_constraint logic is referred from
-	 * hostapd_eid_pwr_constraint.
-	 *
-	 * Check if DFS is required by regulatory.
-	 */
-	dfs = hostapd_is_dfs_required(hapd->iface);
-	if (dfs < 0)
-		dfs = 0;
-
-	/*
-	 * In order to meet regulations when TPC is not implemented using
-	 * a transmit power that is below the legal maximum (including any
-	 * mitigation factor) should help. In this case, indicate 3 dB below
-	 * maximum allowed transmit power.
-	 */
-	if (hapd->iconf->local_pwr_constraint == -1)
-		local_pwr_constraint = (dfs == 0) ? 0 : 3;
-	else
-		local_pwr_constraint = hapd->iconf->local_pwr_constraint;
-
-	/*
-	 * A STA that is not an AP shall use a transmit power less than or
-	 * equal to the local maximum transmit power level for the channel.
-	 * The local maximum transmit power can be calculated from the formula:
-	 * local max TX pwr = max TX pwr - local pwr constraint
-	 * Where max TX pwr is maximum transmit power level specified for
-	 * channel in Country element and local pwr constraint is specified
-	 * for channel in this Power Constraint element.
-	 */
-	chan = &mode->channels[i];
-	max_tx_power = chan->max_tx_power - local_pwr_constraint;
-
-	/*
-	 * Local Maximum Transmit power is encoded as two's complement
-	 * with a 0.5 dB step.
-	 */
-	max_tx_power *= 2; /* in 0.5 dB steps */
-	if (max_tx_power > 127) {
-		/* 63.5 has special meaning of 63.5 dBm or higher */
-		max_tx_power = 127;
-	}
-	if (max_tx_power < -128)
-		max_tx_power = -128;
-	if (max_tx_power < 0)
-		tx_pwr = 0x80 + max_tx_power + 128;
-	else
-		tx_pwr = max_tx_power;
-
-	*eid++ = WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE;
-	*eid++ = 2 + tx_pwr_count;
-
-	/*
-	 * Max Transmit Power count and
-	 * Max Transmit Power units = 0 (EIRP)
-	 */
-	*eid++ = tx_pwr_count;
-
-	for (i = 0; i <= tx_pwr_count; i++)
-		*eid++ = tx_pwr;
-
-	return eid;
-}
-
-
 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *vht_capab)
 {
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index ee095f6..753c883 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2067,7 +2067,8 @@
 
 #ifdef CONFIG_FILS
 #ifdef NEED_AP_MLME
-	if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
+	if (sta->flags &
+	    (WLAN_STA_PENDING_FILS_ERP | WLAN_STA_PENDING_PASN_FILS_ERP)) {
 		/* TODO: Add a PMKSA entry on success? */
 		ieee802_11_finish_fils_auth(
 			hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 01bf886..2bbe318 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -220,7 +220,7 @@
 	u16 capab = hostapd_own_capab_info(hapd);
 	int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
 	int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
-	int he = hapd->iconf->ieee80211ax;
+	int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
 	struct wpa_ssid_value ssid;
 	u8 channel, op_class;
 	u8 center_freq1_idx = 0, center_freq2_idx = 0;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 67b5e98..ccd1ed9 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -156,6 +156,37 @@
 }
 
 
+#ifdef CONFIG_PASN
+
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (sta->pasn) {
+		wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR,
+			   MAC2STR(sta->addr));
+
+		if (sta->pasn->ecdh)
+			crypto_ecdh_deinit(sta->pasn->ecdh);
+
+		wpabuf_free(sta->pasn->secret);
+		sta->pasn->secret = NULL;
+
+#ifdef CONFIG_SAE
+		sae_clear_data(&sta->pasn->sae);
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+		/* In practice this pointer should be NULL */
+		wpabuf_free(sta->pasn->fils.erp_resp);
+		sta->pasn->fils.erp_resp = NULL;
+#endif /* CONFIG_FILS */
+
+		bin_clear_free(sta->pasn, sizeof(*sta->pasn));
+		sta->pasn = NULL;
+	}
+}
+
+#endif /* CONFIG_PASN */
+
 void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	int set_beacon = 0;
@@ -371,6 +402,10 @@
 	eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
 #endif /* CONFIG_WNM_AP */
 
+#ifdef CONFIG_PASN
+	ap_free_sta_pasn(hapd, sta);
+#endif /* CONFIG_PASN */
+
 	os_free(sta->ifname_wds);
 
 #ifdef CONFIG_TESTING_OPTIONS
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index ef48561..efa48e7 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -14,6 +14,8 @@
 #include "vlan.h"
 #include "common/wpa_common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/sae.h"
+#include "crypto/sha384.h"
 
 /* STA flags */
 #define WLAN_STA_AUTH BIT(0)
@@ -39,6 +41,7 @@
 #define WLAN_STA_MULTI_AP BIT(23)
 #define WLAN_STA_HE BIT(24)
 #define WLAN_STA_6GHZ BIT(25)
+#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
@@ -63,6 +66,42 @@
 	struct os_reltime rx_time;
 };
 
+enum pasn_fils_state {
+	PASN_FILS_STATE_NONE = 0,
+	PASN_FILS_STATE_PENDING_AS,
+	PASN_FILS_STATE_COMPLETE
+};
+
+struct pasn_fils_data {
+	u8 state;
+	u8 nonce[FILS_NONCE_LEN];
+	u8 anonce[FILS_NONCE_LEN];
+	u8 session[FILS_SESSION_LEN];
+	u8 erp_pmkid[PMKID_LEN];
+
+	struct wpabuf *erp_resp;
+};
+
+struct pasn_data {
+	int akmp;
+	int cipher;
+	u16 group;
+	u8 trans_seq;
+	u8 wrapped_data_format;
+
+	u8 hash[SHA384_MAC_LEN];
+	struct wpa_ptk ptk;
+	struct crypto_ecdh *ecdh;
+
+	struct wpabuf *secret;
+#ifdef CONFIG_SAE
+	struct sae_data sae;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+	struct pasn_fils_data fils;
+#endif /* CONFIG_FILS */
+};
+
 struct sta_info {
 	struct sta_info *next; /* next entry in sta list */
 	struct sta_info *hnext; /* next entry in hash table list */
@@ -286,6 +325,10 @@
 	unsigned int airtime_weight;
 	struct os_reltime backlogged_until;
 #endif /* CONFIG_AIRTIME_POLICY */
+
+#ifdef CONFIG_PASN
+	struct pasn_data *pasn;
+#endif /* CONFIG_PASN */
 };
 
 
@@ -363,4 +406,6 @@
 						   struct sta_info *sta);
 int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
 
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
+
 #endif /* STA_INFO_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index be81797..d32967e 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -169,7 +169,9 @@
 		pos += igtk_elem_len;
 		wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
 			   (int) igtk_elem_len);
-		if (hapd->conf->beacon_prot) {
+		if (hapd->conf->beacon_prot &&
+		    (hapd->iface->drv_flags &
+		     WPA_DRIVER_FLAGS_BEACON_PROTECTION)) {
 			res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
 			if (res < 0)
 				goto fail;
@@ -537,7 +539,8 @@
 {
 	struct sta_info *sta;
 
-	if (!hapd->conf->beacon_prot)
+	if (!hapd->conf->beacon_prot ||
+	    !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
 		return;
 
 	sta = ap_get_sta(hapd, addr);
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index e48894f..e2e6e1f 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -228,6 +228,23 @@
 }
 
 
+void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth,
+			  const u8 *addr, int cipher,
+			  u32 life_time, const struct wpa_ptk *ptk)
+{
+	if (wpa_auth->cb->store_ptksa)
+		wpa_auth->cb->store_ptksa(wpa_auth->cb_ctx, addr, cipher,
+					  life_time, ptk);
+}
+
+
+void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth,
+			   const u8 *addr, int cipher)
+{
+	if (wpa_auth->cb->clear_ptksa)
+		wpa_auth->cb->clear_ptksa(wpa_auth->cb_ctx, addr, cipher);
+}
+
 void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
 		     logger_level level, const char *txt)
 {
@@ -1748,6 +1765,9 @@
 {
 	sm->PTK_valid = false;
 	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+	wpa_auth_remove_ptksa(sm->wpa_auth, sm->addr, sm->pairwise);
+
 	if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
 			     0, KEY_FLAG_PAIRWISE))
 		wpa_printf(MSG_DEBUG,
@@ -2267,9 +2287,17 @@
 			  struct wpa_ptk *ptk, int force_sha256)
 {
 	const u8 *z = NULL;
-	size_t z_len = 0;
+	size_t z_len = 0, kdk_len;
 	int akmp;
 
+	if (sm->wpa_auth->conf.force_kdk_derivation ||
+	    (sm->wpa_auth->conf.secure_ltf &&
+	     sm->rsnxe && sm->rsnxe_len >= 4 &&
+	     sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+		kdk_len = WPA_KDK_MAX_LEN;
+	else
+		kdk_len = 0;
+
 #ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
 		if (sm->ft_completed) {
@@ -2281,7 +2309,8 @@
 						 sm->pmk_r1_name,
 						 ptk, ptk_name,
 						 sm->wpa_key_mgmt,
-						 sm->pairwise);
+						 sm->pairwise,
+						 kdk_len);
 		}
 		return wpa_auth_derive_ptk_ft(sm, ptk);
 	}
@@ -2299,7 +2328,7 @@
 		akmp |= WPA_KEY_MGMT_PSK_SHA256;
 	return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
 			      sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
-			      ptk, akmp, sm->pairwise, z, z_len);
+			      ptk, akmp, sm->pairwise, z, z_len, kdk_len);
 }
 
 
@@ -2314,13 +2343,21 @@
 	size_t ick_len;
 	int res;
 	u8 fils_ft[FILS_FT_MAX_LEN];
-	size_t fils_ft_len = 0;
+	size_t fils_ft_len = 0, kdk_len;
+
+	if (sm->wpa_auth->conf.force_kdk_derivation ||
+	    (sm->wpa_auth->conf.secure_ltf &&
+	     sm->rsnxe && sm->rsnxe_len >= 4 &&
+	     sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+		kdk_len = WPA_KDK_MAX_LEN;
+	else
+		kdk_len = 0;
 
 	res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
 			      snonce, anonce, dhss, dhss_len,
 			      &sm->PTK, ick, &ick_len,
 			      sm->wpa_key_mgmt, sm->pairwise,
-			      fils_ft, &fils_ft_len);
+			      fils_ft, &fils_ft_len, kdk_len);
 	if (res < 0)
 		return res;
 	sm->PTK_valid = true;
@@ -2828,6 +2865,9 @@
 	}
 	sm->tk_already_set = true;
 
+	wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+			     dot11RSNAConfigPMKLifetime, &sm->PTK);
+
 	return 0;
 }
 
@@ -3154,7 +3194,7 @@
 	sm->pending_1_of_4_timeout = 0;
 	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 
-	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && sm->PMK != pmk) {
 		/* PSK may have changed from the previous choice, so update
 		 * state machine data based on whatever PSK was selected here.
 		 */
@@ -3362,6 +3402,8 @@
 	    wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
 		/* WPA-only STA, remove RSN IE and possible MDIE */
 		wpa_ie = wpa_ie + wpa_ie[1] + 2;
+		if (wpa_ie[0] == WLAN_EID_RSNX)
+			wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
 			wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		wpa_ie_len = wpa_ie[1] + 2;
@@ -3616,6 +3658,8 @@
 		sm->pairwise_set = true;
 
 		wpa_auth_set_ptk_rekey_timer(sm);
+		wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+				     dot11RSNAConfigPMKLifetime, &sm->PTK);
 
 		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
 		    sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
@@ -5364,6 +5408,8 @@
 	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
 		/* WPA-only STA, remove RSN IE and possible MDIE */
 		wpa_ie = wpa_ie + wpa_ie[1] + 2;
+		if (wpa_ie[0] == WLAN_EID_RSNX)
+			wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
 			wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		wpa_ie_len = wpa_ie[1] + 2;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index ff90464..70c13f6 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -259,11 +259,22 @@
 #endif /* CONFIG_FILS */
 	int sae_pwe;
 	bool sae_pk;
+
+	unsigned int secure_ltf:1;
+	unsigned int secure_rtt:1;
+	unsigned int prot_range_neg:1;
+
 	int owe_ptk_workaround;
 	u8 transition_disable;
 #ifdef CONFIG_DPP2
 	int dpp_pfs;
 #endif /* CONFIG_DPP2 */
+
+	/*
+	 * If set Key Derivation Key should be derived as part of PMK to
+	 * PTK derivation regardless of advertised capabilities.
+	 */
+	bool force_kdk_derivation;
 };
 
 typedef enum {
@@ -308,6 +319,9 @@
 	int (*get_sta_tx_params)(void *ctx, const u8 *addr,
 				 int ap_max_chanwidth, int ap_seg1_idx,
 				 int *bandwidth, int *seg1_idx);
+	void (*store_ptksa)(void *ctx, const u8 *addr, int cipher,
+			    u32 life_time, const struct wpa_ptk *ptk);
+	void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher);
 #ifdef CONFIG_IEEE80211R_AP
 	struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
 	int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
@@ -461,6 +475,14 @@
 void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
 void wpa_ft_deinit(struct wpa_authenticator *wpa_auth);
 void wpa_ft_sta_deinit(struct wpa_state_machine *sm);
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+			const u8 *spa, const u8 *pmk_r1_name,
+			u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+			struct vlan_description *vlan,
+			const u8 **identity, size_t *identity_len,
+			const u8 **radius_cui, size_t *radius_cui_len,
+			int *session_timeout);
+
 #endif /* CONFIG_IEEE80211R_AP */
 
 void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
@@ -517,6 +539,8 @@
 u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
 				    u8 *pos, size_t max_len,
 				    const u8 *req_ies, size_t req_ies_len);
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+				u8 *fd_rsn_info);
 void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
 void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
 void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 5aa363e..32b7456 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1473,13 +1473,13 @@
 }
 
 
-static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
-			       const u8 *spa, const u8 *pmk_r1_name,
-			       u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
-			       struct vlan_description *vlan,
-			       const u8 **identity, size_t *identity_len,
-			       const u8 **radius_cui, size_t *radius_cui_len,
-			       int *session_timeout)
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+			const u8 *spa, const u8 *pmk_r1_name,
+			u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+			struct vlan_description *vlan,
+			const u8 **identity, size_t *identity_len,
+			const u8 **radius_cui, size_t *radius_cui_len,
+			int *session_timeout)
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r1_sa *r1;
@@ -2147,7 +2147,8 @@
 
 	return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
 				 sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
-				 ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
+				 ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise,
+				 0);
 }
 
 
@@ -3065,7 +3066,7 @@
 	const u8 *identity, *radius_cui;
 	size_t identity_len = 0, radius_cui_len = 0;
 	int use_sha384;
-	size_t pmk_r1_len;
+	size_t pmk_r1_len, kdk_len;
 
 	*resp_ies = NULL;
 	*resp_ies_len = 0;
@@ -3195,10 +3196,18 @@
 	wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
 		    sm->ANonce, WPA_NONCE_LEN);
 
+	if (sm->wpa_auth->conf.force_kdk_derivation ||
+	    (sm->wpa_auth->conf.secure_ltf &&
+	     sm->rsnxe && sm->rsnxe_len >= 4 &&
+	     sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+		kdk_len = WPA_KDK_MAX_LEN;
+	else
+		kdk_len = 0;
+
 	if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
 			      sm->addr, sm->wpa_auth->addr, pmk_r1_name,
 			      &sm->PTK, ptk_name, sm->wpa_key_mgmt,
-			      pairwise) < 0)
+			      pairwise, kdk_len) < 0)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
 	sm->pairwise = pairwise;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index bb44c7a..e755018 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -14,6 +14,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/sae.h"
 #include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
 #include "crypto/sha1.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
@@ -210,6 +211,11 @@
 #ifdef CONFIG_DPP2
 	wconf->dpp_pfs = conf->dpp_pfs;
 #endif /* CONFIG_DPP2 */
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+	wconf->force_kdk_derivation = conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
 }
 
 
@@ -914,6 +920,27 @@
 }
 
 
+#ifdef CONFIG_PASN
+
+static void hostapd_store_ptksa(void *ctx, const u8 *addr,int cipher,
+				u32 life_time, const struct wpa_ptk *ptk)
+{
+	struct hostapd_data *hapd = ctx;
+
+	ptksa_cache_add(hapd->ptksa, addr, cipher, life_time, ptk);
+}
+
+
+static void hostapd_clear_ptksa(void *ctx, const u8 *addr, int cipher)
+{
+	struct hostapd_data *hapd = ctx;
+
+	ptksa_cache_flush(hapd->ptksa, addr, cipher);
+}
+
+#endif /* CONFIG_PASN */
+
+
 static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
 {
 #ifndef CONFIG_NO_VLAN
@@ -1439,6 +1466,11 @@
 		.send_oui = hostapd_wpa_auth_send_oui,
 		.channel_info = hostapd_channel_info,
 		.update_vlan = hostapd_wpa_auth_update_vlan,
+#ifdef CONFIG_PASN
+		.store_ptksa = hostapd_store_ptksa,
+		.clear_ptksa = hostapd_clear_ptksa,
+#endif /* CONFIG_PASN */
+
 #ifdef CONFIG_OCV
 		.get_sta_tx_params = hostapd_get_sta_tx_params,
 #endif /* CONFIG_OCV */
@@ -1482,6 +1514,22 @@
 	else
 		_conf.extended_key_id = 0;
 
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
+		_conf.beacon_prot = 0;
+
+#ifdef CONFIG_OCV
+	if (!(hapd->iface->drv_flags2 &
+	      (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
+		_conf.ocv = 0;
+#endif /* CONFIG_OCV */
+
+	_conf.secure_ltf =
+		!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF);
+	_conf.secure_rtt =
+		!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT);
+	_conf.prot_range_neg =
+		!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG);
+
 	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
 	if (hapd->wpa_auth == NULL) {
 		wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1507,6 +1555,12 @@
 		return -1;
 	}
 
+	hapd->ptksa = ptksa_cache_init();
+	if (!hapd->ptksa) {
+		wpa_printf(MSG_ERROR, "Failed to allocate PTKSA cache");
+		return -1;
+	}
+
 #ifdef CONFIG_IEEE80211R_AP
 	if (!hostapd_drv_none(hapd) &&
 	    wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
@@ -1546,6 +1600,9 @@
 void hostapd_deinit_wpa(struct hostapd_data *hapd)
 {
 	ieee80211_tkip_countermeasures_deinit(hapd);
+	ptksa_cache_deinit(hapd->ptksa);
+	hapd->ptksa = NULL;
+
 	rsn_preauth_iface_deinit(hapd);
 	if (hapd->wpa_auth) {
 		wpa_deinit(hapd->wpa_auth);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 3704fc0..d471031 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -88,13 +88,42 @@
 }
 
 
+static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
+{
+	u16 capab = 0;
+
+	if (conf->rsn_preauth)
+		capab |= WPA_CAPABILITY_PREAUTH;
+	if (conf->wmm_enabled) {
+		/* 4 PTKSA replay counters when using WMM */
+		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+	}
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		capab |= WPA_CAPABILITY_MFPC;
+		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+			capab |= WPA_CAPABILITY_MFPR;
+	}
+#ifdef CONFIG_OCV
+	if (conf->ocv)
+		capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing)
+		capab |= BIT(8) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
+	if (conf->extended_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+	return capab;
+}
+
+
 int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
 		     const u8 *pmkid)
 {
 	struct rsn_ie_hdr *hdr;
 	int num_suites, res;
 	u8 *pos, *count;
-	u16 capab;
 	u32 suite;
 
 	hdr = (struct rsn_ie_hdr *) buf;
@@ -260,6 +289,13 @@
 		num_suites++;
 	}
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_PASN
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_PASN */
 
 #ifdef CONFIG_RSN_TESTING
 	if (rsn_testing) {
@@ -277,29 +313,7 @@
 	WPA_PUT_LE16(count, num_suites);
 
 	/* RSN Capabilities */
-	capab = 0;
-	if (conf->rsn_preauth)
-		capab |= WPA_CAPABILITY_PREAUTH;
-	if (conf->wmm_enabled) {
-		/* 4 PTKSA replay counters when using WMM */
-		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
-	}
-	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-		capab |= WPA_CAPABILITY_MFPC;
-		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
-			capab |= WPA_CAPABILITY_MFPR;
-	}
-#ifdef CONFIG_OCV
-	if (conf->ocv)
-		capab |= WPA_CAPABILITY_OCVC;
-#endif /* CONFIG_OCV */
-#ifdef CONFIG_RSN_TESTING
-	if (rsn_testing)
-		capab |= BIT(8) | BIT(15);
-#endif /* CONFIG_RSN_TESTING */
-	if (conf->extended_key_id)
-		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
-	WPA_PUT_LE16(pos, capab);
+	WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
 	pos += 2;
 
 	if (pmkid) {
@@ -377,23 +391,38 @@
 int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
 {
 	u8 *pos = buf;
+	u16 capab = 0;
+	size_t flen;
 
-	if (conf->sae_pwe != 1 && conf->sae_pwe != 2 && !conf->sae_pk)
+	if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
+	    (conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk)) {
+		capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+		if (conf->sae_pk)
+			capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+	}
+
+	if (conf->secure_ltf)
+		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+	if (conf->secure_rtt)
+		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+	if (conf->prot_range_neg)
+		capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+	flen = (capab & 0xff00) ? 2 : 1;
+	if (!capab)
 		return 0; /* no supported extended RSN capabilities */
-
-	if (len < 3)
+	if (len < 2 + flen)
 		return -1;
+	capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
 
 	*pos++ = WLAN_EID_RSNX;
-	*pos++ = 1;
-	/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
-	 * used for now */
-	*pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
-#ifdef CONFIG_SAE_PK
-	if (conf->sae_pk)
-		*pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
-#endif /* CONFIG_SAE_PK */
-	pos++;
+	*pos++ = flen;
+	*pos++ = capab & 0x00ff;
+	capab >>= 8;
+	if (capab)
+		*pos++ = capab;
 
 	return pos - buf;
 }
@@ -1096,6 +1125,7 @@
 
 
 #ifdef CONFIG_FILS
+
 u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
 				    u8 *pos, size_t max_len,
 				    const u8 *req_ies, size_t req_ies_len)
@@ -1112,4 +1142,91 @@
 		return pos;
 	return pos + res;
 }
+
+
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+				u8 *fd_rsn_info)
+{
+	struct wpa_auth_config *conf;
+	u32 selectors = 0;
+	u8 *pos = fd_rsn_info;
+	int i, res;
+	u32 cipher, suite, selector, mask;
+	u8 tmp[10 * RSN_SELECTOR_LEN];
+
+	if (!wpa_auth)
+		return false;
+	conf = &wpa_auth->conf;
+
+	if (!(conf->wpa & WPA_PROTO_RSN))
+		return false;
+
+	/* RSN Capability (B0..B15) */
+	WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
+	pos += 2;
+
+	/* Group Data Cipher Suite Selector (B16..B21) */
+	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+	if (suite == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
+		cipher = 63; /* No cipher suite selected */
+	if ((suite >> 8) == 0x000fac && ((suite & 0xff) <= 13))
+		cipher = suite & 0xff;
+	else
+		cipher = 62; /* vendor specific */
+	selectors |= cipher;
+
+	/* Group Management Cipher Suite Selector (B22..B27) */
+	cipher = 63; /* Default to no cipher suite selected */
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		switch (conf->group_mgmt_cipher) {
+		case WPA_CIPHER_AES_128_CMAC:
+			cipher = RSN_CIPHER_SUITE_AES_128_CMAC & 0xff;
+			break;
+		case WPA_CIPHER_BIP_GMAC_128:
+			cipher = RSN_CIPHER_SUITE_BIP_GMAC_128 & 0xff;
+			break;
+		case WPA_CIPHER_BIP_GMAC_256:
+			cipher = RSN_CIPHER_SUITE_BIP_GMAC_256 & 0xff;
+			break;
+		case WPA_CIPHER_BIP_CMAC_256:
+			cipher = RSN_CIPHER_SUITE_BIP_CMAC_256 & 0xff;
+			break;
+		}
+	}
+	selectors |= cipher << 6;
+
+	/* Pairwise Cipher Suite Selector (B28..B33) */
+	cipher = 63; /* Default to no cipher suite selected */
+	res = rsn_cipher_put_suites(tmp, conf->rsn_pairwise);
+	if (res == 1 && tmp[0] == 0x00 && tmp[1] == 0x0f && tmp[2] == 0xac &&
+	    tmp[3] <= 13)
+		cipher = tmp[3];
+	selectors |= cipher << 12;
+
+	/* AKM Suite Selector (B34..B39) */
+	selector = 0; /* default to AKM from RSNE in Beacon/Probe Response */
+	mask = WPA_KEY_MGMT_FILS_SHA256 | WPA_KEY_MGMT_FILS_SHA384 |
+		WPA_KEY_MGMT_FT_FILS_SHA384;
+	if ((conf->wpa_key_mgmt & mask) && (conf->wpa_key_mgmt & ~mask) == 0) {
+		suite = conf->wpa_key_mgmt & mask;
+		if (suite == WPA_KEY_MGMT_FILS_SHA256)
+			selector = 1; /* 00-0f-ac:14 */
+		else if (suite == WPA_KEY_MGMT_FILS_SHA384)
+			selector = 2; /* 00-0f-ac:15 */
+		else if (suite == (WPA_KEY_MGMT_FILS_SHA256 |
+				   WPA_KEY_MGMT_FILS_SHA384))
+			selector = 3; /* 00-0f-ac:14 or 00-0f-ac:15 */
+		else if (suite == WPA_KEY_MGMT_FT_FILS_SHA384)
+			selector = 4; /* 00-0f-ac:17 */
+	}
+	selectors |= selector << 18;
+
+	for (i = 0; i < 3; i++) {
+		*pos++ = selectors & 0xff;
+		selectors >>= 8;
+	}
+
+	return true;
+}
+
 #endif /* CONFIG_FILS */
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index dc8aa8f..e97dbf9 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1376,6 +1376,48 @@
 }
 
 
+static int hostapd_wps_update_multi_ap(struct hostapd_data *hapd,
+				       struct wps_registrar *reg)
+{
+	struct hostapd_bss_config *conf = hapd->conf;
+	u8 *multi_ap_backhaul_network_key = NULL;
+	size_t multi_ap_backhaul_network_key_len = 0;
+	int ret;
+
+	if (!(conf->multi_ap & FRONTHAUL_BSS) ||
+	    !conf->multi_ap_backhaul_ssid.ssid_len)
+		return 0;
+
+	if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+		multi_ap_backhaul_network_key =
+			(u8 *) os_strdup(
+				conf->multi_ap_backhaul_ssid.wpa_passphrase);
+		if (!multi_ap_backhaul_network_key)
+			return -1;
+		multi_ap_backhaul_network_key_len =
+			os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+	} else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+		multi_ap_backhaul_network_key = os_malloc(2 * PMK_LEN + 1);
+		if (!multi_ap_backhaul_network_key)
+			return -1;
+		wpa_snprintf_hex((char *) multi_ap_backhaul_network_key,
+				 2 * PMK_LEN + 1,
+				 conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+				 PMK_LEN);
+		multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+	}
+
+	ret = wps_registrar_update_multi_ap(
+		reg, conf->multi_ap_backhaul_ssid.ssid,
+		conf->multi_ap_backhaul_ssid.ssid_len,
+		multi_ap_backhaul_network_key,
+		multi_ap_backhaul_network_key_len);
+	os_free(multi_ap_backhaul_network_key);
+
+	return ret;
+}
+
+
 void hostapd_deinit_wps(struct hostapd_data *hapd)
 {
 	eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1398,22 +1440,65 @@
 
 void hostapd_update_wps(struct hostapd_data *hapd)
 {
-	if (hapd->wps == NULL)
+	struct wps_context *wps = hapd->wps;
+	struct hostapd_bss_config *conf = hapd->conf;
+
+	if (!wps)
 		return;
 
 #ifdef CONFIG_WPS_UPNP
-	hapd->wps->friendly_name = hapd->conf->friendly_name;
-	hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
-	hapd->wps->model_description = hapd->conf->model_description;
-	hapd->wps->model_url = hapd->conf->model_url;
-	hapd->wps->upc = hapd->conf->upc;
+	wps->friendly_name = conf->friendly_name;
+	wps->manufacturer_url = conf->manufacturer_url;
+	wps->model_description = conf->model_description;
+	wps->model_url = conf->model_url;
+	wps->upc = conf->upc;
 #endif /* CONFIG_WPS_UPNP */
 
-	hostapd_wps_set_vendor_ext(hapd, hapd->wps);
-	hostapd_wps_set_application_ext(hapd, hapd->wps);
+	os_memcpy(wps->ssid, conf->ssid.ssid, conf->ssid.ssid_len);
+	wps->ssid_len = conf->ssid.ssid_len;
 
-	if (hapd->conf->wps_state)
-		wps_registrar_update_ie(hapd->wps->registrar);
+	/* Clear WPS settings, then fill them again */
+	os_free(wps->network_key);
+	wps->network_key = NULL;
+	wps->network_key_len = 0;
+	wps->psk_set = 0;
+	if (conf->ssid.wpa_psk_file) {
+		/* Use per-device PSKs */
+	} else if (conf->ssid.wpa_passphrase) {
+		wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+		if (!wps->network_key)
+			return;
+		wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+	} else if (conf->ssid.wpa_psk) {
+		wps->network_key = os_malloc(2 * PMK_LEN + 1);
+		if (!wps->network_key)
+			return;
+		wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+				 conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
+	} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+		wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+		if (!wps->network_key)
+			return;
+		os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+			  conf->ssid.wep.len[0]);
+		wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
+	}
+
+	if (conf->ssid.wpa_psk) {
+		os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->psk_set = 1;
+	}
+
+	hostapd_wps_update_multi_ap(hapd, wps->registrar);
+
+	hostapd_wps_set_vendor_ext(hapd, wps);
+	hostapd_wps_set_application_ext(hapd, wps);
+
+	if (conf->wps_state)
+		wps_registrar_update_ie(wps->registrar);
 	else
 		hostapd_deinit_wps(hapd);
 }