Merge "Merge Android 14 QPR1" into main
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index b313e54..a036540 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -373,23 +373,46 @@
 				WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
 			return "";
 		}
-		encryption_config_as_string = StringPrintf(
-			"wpa=2\n"
-			"rsn_pairwise=%s\n"
-			"wpa_key_mgmt=%s\n"
-			"ieee80211w=1\n"
-			"sae_require_mfp=1\n"
-			"wpa_passphrase=%s\n"
-			"sae_password=%s",
-			is_60Ghz_band_only ? "GCMP" : "CCMP",
+		// WPA3 transition mode or SAE+WPA_PSK key management(AKM) is not allowed in 6GHz.
+		// Auto-convert any such configurations to SAE.
+		if ((band & band6Ghz) != 0) {
+			wpa_printf(MSG_INFO, "WPA3_SAE_TRANSITION configured in 6GHz band."
+				   "Enable only SAE in key_mgmt");
+			encryption_config_as_string = StringPrintf(
+				"wpa=2\n"
+				"rsn_pairwise=CCMP\n"
+				"wpa_key_mgmt=%s\n"
+				"ieee80211w=2\n"
+				"sae_require_mfp=2\n"
+				"sae_pwe=%d\n"
+				"sae_password=%s",
 #ifdef CONFIG_IEEE80211BE
-			iface_params.hwModeParams.enable80211BE ?
-			    "WPA-PSK SAE SAE-EXT-KEY" : "WPA-PSK SAE",
+				iface_params.hwModeParams.enable80211BE ?
+					"SAE SAE-EXT-KEY" : "SAE",
 #else
-			"WPA-PSK SAE",
+					"SAE",
 #endif
-			nw_params.passphrase.c_str(),
-			nw_params.passphrase.c_str());
+				is_6Ghz_band_only ? 1 : 2,
+				nw_params.passphrase.c_str());
+		} else {
+			encryption_config_as_string = StringPrintf(
+				"wpa=2\n"
+				"rsn_pairwise=%s\n"
+				"wpa_key_mgmt=%s\n"
+				"ieee80211w=1\n"
+				"sae_require_mfp=1\n"
+				"wpa_passphrase=%s\n"
+				"sae_password=%s",
+				is_60Ghz_band_only ? "GCMP" : "CCMP",
+#ifdef CONFIG_IEEE80211BE
+				iface_params.hwModeParams.enable80211BE ?
+					"WPA-PSK SAE SAE-EXT-KEY" : "WPA-PSK SAE",
+#else
+					"WPA-PSK SAE",
+#endif
+				nw_params.passphrase.c_str(),
+				nw_params.passphrase.c_str());
+                }
 		break;
 	case EncryptionType::WPA3_SAE:
 		if (!validatePassphrase(nw_params.passphrase.size(), 1, -1)) {
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 17b1b4a..580e41c 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4738,6 +4738,8 @@
 		}
 	} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
 		bss->pasn_comeback_after = atoi(pos);
+	} else if (os_strcmp(buf, "pasn_noauth") == 0) {
+		bss->pasn_noauth = atoi(pos);
 #endif /* CONFIG_PASN */
 	} else if (os_strcmp(buf, "ext_capa_mask") == 0) {
 		if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN,
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index ea9c444..b46d921 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2550,6 +2550,36 @@
 			return -1;
 		}
 		break;
+	case 320:
+		if (!params->center_freq1 || params->center_freq2 ||
+		    !params->sec_channel_offset)
+			return -1;
+
+		switch (params->sec_channel_offset) {
+		case 1:
+			if (params->freq + 150 != params->center_freq1 &&
+			    params->freq + 110 != params->center_freq1 &&
+			    params->freq + 70 != params->center_freq1 &&
+			    params->freq + 30 != params->center_freq1 &&
+			    params->freq - 10 != params->center_freq1 &&
+			    params->freq - 50 != params->center_freq1 &&
+			    params->freq - 90 != params->center_freq1 &&
+			    params->freq - 130 != params->center_freq1)
+				return -1;
+			break;
+		case -1:
+			if (params->freq + 130 != params->center_freq1 &&
+			    params->freq + 90 != params->center_freq1 &&
+			    params->freq + 50 != params->center_freq1 &&
+			    params->freq + 10 != params->center_freq1 &&
+			    params->freq - 30 != params->center_freq1 &&
+			    params->freq - 70 != params->center_freq1 &&
+			    params->freq - 110 != params->center_freq1 &&
+			    params->freq - 150 != params->center_freq1)
+				return -1;
+			break;
+		}
+		break;
 	default:
 		return -1;
 	}
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index bc4a0f6..5868bfd 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2170,6 +2170,11 @@
 # (default: 10 TUs)
 #pasn_comeback_after=10
 
+# Unauthenticated PASN activated (dot11NoAuthPASNActivated)
+# This indicates whether PASN without mutual authentication is allowed.
+# (default: 1 = activated)
+#pasn_noauth=1
+
 ##### IEEE 802.11r configuration ##############################################
 
 # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 95edea8..646dfc5 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1529,7 +1529,7 @@
 static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc,
 					   char *argv[])
 {
-	return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 1, argc, argv);
+	return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv);
 }
 #endif /* CONFIG_DPP3 */
 #endif /* CONFIG_DPP */
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index b5fcc38..c3ee506 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -169,6 +169,7 @@
 #ifdef CONFIG_PASN
 	/* comeback after 10 TUs */
 	bss->pasn_comeback_after = 10;
+	bss->pasn_noauth = 1;
 #endif /* CONFIG_PASN */
 }
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 07ee31c..def5fd5 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -906,6 +906,9 @@
 #endif /* CONFIG_MACSEC */
 
 #ifdef CONFIG_PASN
+	/* Whether to allow PASN-UNAUTH */
+	int pasn_noauth;
+
 #ifdef CONFIG_TESTING_OPTIONS
 	/*
 	 * Normally, KDK should be derived if and only if both sides support
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index f77f738..aa4dbe9 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -883,10 +883,10 @@
 }
 
 
-static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
-					     struct hostapd_hw_modes *mode,
-					     int acs_ch_list_all,
-					     int **freq_list)
+void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
+				      struct hostapd_hw_modes *mode,
+				      int acs_ch_list_all, bool allow_disabled,
+				      int **freq_list)
 {
 	int i;
 
@@ -912,7 +912,7 @@
 		     (!hapd->iface->conf->ieee80211ax &&
 		      !hapd->iface->conf->ieee80211be)))
 			continue;
-		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+		if ((!(chan->flag & HOSTAPD_CHAN_DISABLED) || allow_disabled) &&
 		    !(hapd->iface->conf->acs_exclude_dfs &&
 		      (chan->flag & HOSTAPD_CHAN_RADAR)) &&
 		    !(chan->max_tx_power < hapd->iface->conf->min_tx_power))
@@ -969,7 +969,7 @@
 		    selected_mode != mode->mode)
 			continue;
 		hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
-						 &freq_list);
+						 false, &freq_list);
 	}
 
 	params.freq_list = freq_list;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 93b2244..023cbf1 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -156,6 +156,11 @@
 
 void hostapd_get_ext_capa(struct hostapd_iface *iface);
 
+void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
+				      struct hostapd_hw_modes *mode,
+				      int acs_ch_list_all, bool allow_disabled,
+				      int **freq_list);
+
 static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
 						  int enabled)
 {
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index c25a5bb..de944fe 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -468,8 +468,9 @@
 {
 	struct hostapd_iface *iface = hapd->iface;
 	struct hostapd_data *tx_bss;
-	size_t len;
+	size_t len, rnr_len = 0;
 	u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end;
+	u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL;
 
 	if (!iface->mbssid_max_interfaces ||
 	    iface->num_bss > iface->mbssid_max_interfaces ||
@@ -479,7 +480,7 @@
 
 	tx_bss = hostapd_mbssid_get_tx_bss(hapd);
 	len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count,
-				     NULL, 0);
+				     NULL, 0, &rnr_len);
 	if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
 		     elem_count > iface->ema_max_periodicity))
 		goto fail;
@@ -492,8 +493,19 @@
 	if (!elem_offset)
 		goto fail;
 
+	if (rnr_len) {
+		rnr_elem = os_zalloc(rnr_len);
+		if (!rnr_elem)
+			goto fail;
+
+		rnr_elem_offset = os_calloc(elem_count + 1, sizeof(u8 *));
+		if (!rnr_elem_offset)
+			goto fail;
+	}
+
 	end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON,
-				 elem_count, elem_offset, NULL, 0);
+				 elem_count, elem_offset, NULL, 0, rnr_elem,
+				 &rnr_elem_count, rnr_elem_offset, rnr_len);
 
 	params->mbssid_tx_iface = tx_bss->conf->iface;
 	params->mbssid_index = hostapd_mbssid_get_bss_index(hapd);
@@ -501,12 +513,19 @@
 	params->mbssid_elem_len = end - elem;
 	params->mbssid_elem_count = elem_count;
 	params->mbssid_elem_offset = elem_offset;
+	params->rnr_elem = rnr_elem;
+	params->rnr_elem_len = rnr_len;
+	params->rnr_elem_count = rnr_elem_count;
+	params->rnr_elem_offset = rnr_elem_offset;
 	if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED)
 		params->ema = true;
 
 	return 0;
 
 fail:
+	os_free(rnr_elem);
+	os_free(rnr_elem_offset);
+	os_free(elem_offset);
 	os_free(elem);
 	wpa_printf(MSG_ERROR, "MBSSID: Configuration failed");
 	return -1;
@@ -590,7 +609,7 @@
 #endif /* CONFIG_IEEE80211BE */
 
 	buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL,
-					 known_bss, known_bss_len);
+					 known_bss, known_bss_len, NULL);
 	buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
 	buflen += hostapd_mbo_ie_len(hapd);
 	buflen += hostapd_eid_owe_trans_len(hapd);
@@ -658,7 +677,8 @@
 	pos = hostapd_get_rsne(hapd, pos, epos - pos);
 	pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
 	pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0,
-				 NULL, known_bss, known_bss_len);
+				 NULL, known_bss, known_bss_len, NULL, NULL,
+				 NULL, 0);
 	pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
 	pos = hostapd_get_mde(hapd, pos, epos - pos);
 
@@ -2026,6 +2046,10 @@
 	params->mbssid_elem = NULL;
 	os_free(params->mbssid_elem_offset);
 	params->mbssid_elem_offset = NULL;
+	os_free(params->rnr_elem);
+	params->rnr_elem = NULL;
+	os_free(params->rnr_elem_offset);
+	params->rnr_elem_offset = NULL;
 #ifdef CONFIG_FILS
 	os_free(params->fd_frame_tmpl);
 	params->fd_frame_tmpl = NULL;
@@ -2034,6 +2058,8 @@
 	os_free(params->unsol_bcast_probe_resp_tmpl);
 	params->unsol_bcast_probe_resp_tmpl = NULL;
 #endif /* CONFIG_IEEE80211AX */
+	os_free(params->allowed_freqs);
+	params->allowed_freqs = NULL;
 }
 
 
@@ -2045,7 +2071,8 @@
 	struct hostapd_config *iconf = iface->conf;
 	struct hostapd_hw_modes *cmode = iface->current_mode;
 	struct wpabuf *beacon, *proberesp, *assocresp;
-	int res, ret = -1;
+	int res, ret = -1, i;
+	struct hostapd_hw_modes *mode;
 
 	if (!hapd->drv_priv) {
 		wpa_printf(MSG_ERROR, "Interface is disabled");
@@ -2120,6 +2147,19 @@
 				    &cmode->eht_capab[IEEE80211_MODE_AP]) == 0)
 		params.freq = &freq;
 
+	for (i = 0; i < hapd->iface->num_hw_features; i++) {
+		mode = &hapd->iface->hw_features[i];
+
+		if (iconf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
+		    iconf->hw_mode != mode->mode)
+			continue;
+
+		hostapd_get_hw_mode_any_channels(hapd, mode,
+						 !(iconf->acs_freq_list.num ||
+						   iconf->acs_ch_list.num),
+						 true, &params.allowed_freqs);
+	}
+
 	res = hostapd_drv_set_ap(hapd, &params);
 	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 	if (res)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 8fc128e..510a06c 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -978,7 +978,8 @@
 	hapd->iconf->ch_switch_eht_config = 0;
 
 	if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 ||
-	    width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160)
+	    width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160 ||
+	    width == CHAN_WIDTH_320)
 		hapd->iconf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
 	else if (width == CHAN_WIDTH_20 || width == CHAN_WIDTH_20_NOHT)
 		hapd->iconf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 8b3fb40..112e6fa 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1476,11 +1476,11 @@
 		return -1;
 	}
 
-	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+	if (start_beacon && hostapd_start_beacon(hapd, flush_old_stations) < 0)
 		return -1;
 
-	if (start_beacon)
-		return hostapd_start_beacon(hapd, flush_old_stations);
+	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+		return -1;
 
 	return 0;
 }
@@ -1756,16 +1756,15 @@
 
 static void hostapd_set_6ghz_sec_chan(struct hostapd_iface *iface)
 {
-	int bw, seg0;
+	int bw;
 
 	if (!is_6ghz_op_class(iface->conf->op_class))
 		return;
 
-	seg0 = hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
-	bw = center_idx_to_bw_6ghz(seg0);
+	bw = op_class_to_bandwidth(iface->conf->op_class);
 	/* Assign the secondary channel if absent in config for
 	 * bandwidths > 20 MHz */
-	if (bw > 0 && !iface->conf->secondary_channel) {
+	if (bw >= 40 && !iface->conf->secondary_channel) {
 		if (((iface->conf->channel - 1) / 4) % 2)
 			iface->conf->secondary_channel = -1;
 		else
@@ -3340,7 +3339,6 @@
 		return;
 	}
 
-	hostapd_prune_associations(hapd, sta->addr);
 	ap_sta_clear_disconnect_timeouts(hapd, sta);
 	sta->post_csa_sa_query = 0;
 
@@ -3602,6 +3600,7 @@
 	case 40:
 	case 80:
 	case 160:
+	case 320:
 		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
 		break;
 	default:
@@ -3674,6 +3673,9 @@
 	case 160:
 		bandwidth = CONF_OPER_CHWIDTH_160MHZ;
 		break;
+	case 320:
+		bandwidth = CONF_OPER_CHWIDTH_320MHZ;
+		break;
 	default:
 		bandwidth = CONF_OPER_CHWIDTH_USE_HT;
 		break;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 842d9f5..f836be4 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -1001,6 +1001,24 @@
 }
 
 
+static bool skip_mode(struct hostapd_iface *iface,
+		      struct hostapd_hw_modes *mode)
+{
+	int chan;
+
+	if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, &chan))
+		return true;
+
+	if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 &&
+	    (mode->mode != HOSTAPD_MODE_IEEE80211A ||
+	     mode->num_channels == 0 ||
+	     !is_6ghz_freq(mode->channels[0].freq)))
+		return true;
+
+	return false;
+}
+
+
 static void hostapd_determine_mode(struct hostapd_iface *iface)
 {
 	int i;
@@ -1022,6 +1040,9 @@
 
 		mode = &iface->hw_features[i];
 		if (mode->mode == target_mode) {
+			if (skip_mode(iface, mode))
+				continue;
+
 			iface->current_mode = mode;
 			iface->conf->hw_mode = mode->mode;
 			break;
@@ -1152,11 +1173,9 @@
 	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_mode_get_channel(mode, iface->freq, &chan))
+			if (skip_mode(iface, mode))
 				continue;
 
 			iface->current_mode = mode;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 0142ee4..93a6b4f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2527,6 +2527,7 @@
 	pasn->cb_ctx = hapd;
 	pasn->send_mgmt = hapd_pasn_send_mlme;
 	pasn->pasn_groups = hapd->conf->pasn_groups;
+	pasn->noauth = hapd->conf->pasn_noauth;
 	pasn->wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
 	pasn->rsn_pairwise = hapd->conf->rsn_pairwise;
 	pasn->derive_kdk = hapd->iface->drv_flags2 &
@@ -3696,7 +3697,7 @@
 		if (resp != WLAN_STATUS_SUCCESS)
 			return resp;
 
-		resp = set_sta_vht_opmode(hapd, sta, elems->vht_opmode_notif);
+		resp = set_sta_vht_opmode(hapd, sta, elems->opmode_notif);
 		if (resp != WLAN_STATUS_SUCCESS)
 			return resp;
 	}
@@ -5758,7 +5759,11 @@
 		sta->flags |= WLAN_STA_WDS;
 	}
 
-	if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
+	/* WPS not supported on backhaul BSS. Disable 4addr mode on fronthaul */
+	if ((sta->flags & WLAN_STA_WDS) ||
+	    (sta->flags & WLAN_STA_MULTI_AP &&
+	     !(hapd->conf->multi_ap & FRONTHAUL_BSS) &&
+	     !(sta->flags & WLAN_STA_WPS))) {
 		int ret;
 		char ifname_wds[IFNAMSIZ + 1];
 
@@ -6347,7 +6352,7 @@
 	     !hapd->cs_freq_params.eht_enabled))
 		return eid;
 
-	/* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
+	/* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80, 4: 320 */
 	switch (hapd->cs_freq_params.bandwidth) {
 	case 40:
 		bw = 0;
@@ -6362,6 +6367,9 @@
 	case 160:
 		bw = 2;
 		break;
+	case 320:
+		bw = 4;
+		break;
 	default:
 		/* not valid VHT bandwidth or not in CSA */
 		return eid;
@@ -6379,9 +6387,9 @@
 				   &chan2) != HOSTAPD_MODE_IEEE80211A)
 		return eid;
 
-	*eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
+	*eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
 	*eid++ = 5; /* Length of Channel Switch Wrapper */
-	*eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
+	*eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
 	*eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
 	*eid++ = bw; /* New Channel Width */
 	*eid++ = chan1; /* New Channel Center Frequency Segment 0 */
@@ -6421,9 +6429,16 @@
 }
 
 
-static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
-					struct hostapd_data *reporting_hapd,
-					size_t *current_len)
+struct mbssid_ie_profiles {
+	u8 start;
+	u8 end;
+};
+
+static size_t
+hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
+			  struct hostapd_data *reporting_hapd,
+			  size_t *current_len,
+			  struct mbssid_ie_profiles *skip_profiles)
 {
 	size_t total_len = 0, len = *current_len;
 	int tbtt_count = 0;
@@ -6449,6 +6464,10 @@
 			    bss->conf->ignore_broadcast_ssid)
 				continue;
 
+			if (skip_profiles &&
+			    i >= skip_profiles->start && i < skip_profiles->end)
+				continue;
+
 			if (len + RNR_TBTT_INFO_LEN > 255 ||
 			    tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
 				break;
@@ -6527,7 +6546,7 @@
 			continue;
 
 		len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
-						 current_len);
+						 current_len, NULL);
 	}
 
 	return len;
@@ -6550,15 +6569,18 @@
 			total_len += hostapd_eid_rnr_colocation_len(
 				hapd, &current_len);
 
-		if (hapd->conf->rnr && hapd->iface->num_bss > 1)
+		if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
+		    !hapd->iconf->mbssid)
 			total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
-							       &current_len);
+							       &current_len,
+							       NULL);
 		break;
 
 	case WLAN_FC_STYPE_ACTION:
 		if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
 			total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
-							       &current_len);
+							       &current_len,
+							       NULL);
 		break;
 
 	default:
@@ -6626,7 +6648,8 @@
 
 static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
 				  struct hostapd_data *reporting_hapd,
-				  u8 *eid, size_t *current_len)
+				  u8 *eid, size_t *current_len,
+				  struct mbssid_ie_profiles *skip_profiles)
 {
 	struct hostapd_data *bss;
 	struct hostapd_iface *iface = hapd->iface;
@@ -6671,6 +6694,10 @@
 			    bss->conf->ignore_broadcast_ssid)
 				continue;
 
+			if (skip_profiles &&
+			    i >= skip_profiles->start && i < skip_profiles->end)
+				continue;
+
 			if (len + RNR_TBTT_INFO_LEN > 255 ||
 			    tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
 				break;
@@ -6687,7 +6714,7 @@
 			if (iface->conf->mbssid != MBSSID_DISABLED &&
 			    iface->num_bss > 1) {
 				bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID;
-				if (i == 0)
+				if (bss == hostapd_mbssid_get_tx_bss(hapd))
 					bss_param |=
 						RNR_BSS_PARAM_TRANSMITTED_BSSID;
 			}
@@ -6735,7 +6762,7 @@
 			continue;
 
 		eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
-					    current_len);
+					    current_len, NULL);
 	}
 
 	return eid;
@@ -6759,15 +6786,16 @@
 			eid = hostapd_eid_rnr_colocation(hapd, eid,
 							 &current_len);
 
-		if (hapd->conf->rnr && hapd->iface->num_bss > 1)
+		if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
+		    !hapd->iconf->mbssid)
 			eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
-						    &current_len);
+						    &current_len, NULL);
 		break;
 
 	case WLAN_FC_STYPE_ACTION:
 		if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
 			eid = hostapd_eid_rnr_iface(hapd, hapd,	eid,
-						    &current_len);
+						    &current_len, NULL);
 		break;
 
 	default:
@@ -6856,7 +6884,7 @@
 
 size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
 			      u8 *elem_count, const u8 *known_bss,
-			      size_t known_bss_len)
+			      size_t known_bss_len, size_t *rnr_len)
 {
 	size_t len = 0, bss_index = 1;
 
@@ -6875,13 +6903,29 @@
 	}
 
 	while (bss_index < hapd->iface->num_bss) {
+		size_t rnr_count = bss_index;
+
 		len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
 						   &bss_index, known_bss,
 						   known_bss_len);
 
 		if (frame_type == WLAN_FC_STYPE_BEACON)
 			*elem_count += 1;
+		if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) {
+			size_t rnr_cur_len = 0;
+			struct mbssid_ie_profiles skip_profiles = {
+				rnr_count, bss_index
+			};
+
+			*rnr_len += hostapd_eid_rnr_iface_len(
+				hapd, hostapd_mbssid_get_tx_bss(hapd),
+				&rnr_cur_len, &skip_profiles);
+		}
 	}
+
+	if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len)
+		*rnr_len += hostapd_eid_rnr_len(hapd, frame_type);
+
 	return len;
 }
 
@@ -6993,10 +7037,12 @@
 u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
 			unsigned int frame_stype, u8 elem_count,
 			u8 **elem_offset,
-			const u8 *known_bss, size_t known_bss_len)
+			const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
+			u8 *rnr_count, u8 **rnr_offset, size_t rnr_len)
 {
-	size_t bss_index = 1;
-	u8 elem_index = 0;
+	size_t bss_index = 1, cur_len = 0;
+	u8 elem_index = 0, *rnr_start_eid = rnr_eid;
+	bool add_rnr;
 
 	if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
 	    (frame_stype != WLAN_FC_STYPE_BEACON &&
@@ -7009,7 +7055,13 @@
 		return eid;
 	}
 
+	add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
+		frame_stype == WLAN_FC_STYPE_BEACON &&
+		rnr_eid && rnr_count && rnr_offset && rnr_len;
+
 	while (bss_index < hapd->iface->num_bss) {
+		unsigned int rnr_start_count = bss_index;
+
 		if (frame_stype == WLAN_FC_STYPE_BEACON) {
 			if (elem_index == elem_count) {
 				wpa_printf(MSG_WARNING,
@@ -7024,6 +7076,31 @@
 					      hostapd_max_bssid_indicator(hapd),
 					      &bss_index, elem_count,
 					      known_bss, known_bss_len);
+
+		if (add_rnr) {
+			struct mbssid_ie_profiles skip_profiles = {
+				rnr_start_count, bss_index
+			};
+
+			rnr_offset[*rnr_count] = rnr_eid;
+			*rnr_count = *rnr_count + 1;
+			cur_len = 0;
+			rnr_eid = hostapd_eid_rnr_iface(
+				hapd, hostapd_mbssid_get_tx_bss(hapd),
+				rnr_eid, &cur_len, &skip_profiles);
+		}
+	}
+
+	if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) {
+		rnr_offset[*rnr_count] = rnr_eid;
+		*rnr_count = *rnr_count + 1;
+		cur_len = 0;
+
+		if (hapd->conf->rnr)
+			rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len);
+		if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND)
+			rnr_eid = hostapd_eid_rnr_colocation(hapd, rnr_eid,
+							     &cur_len);
 	}
 
 	return eid;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 1e4c843..1190a5e 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -218,11 +218,12 @@
 		       const u8 *eht_capab, size_t eht_capab_len);
 size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
 			      u8 *elem_count, const u8 *known_bss,
-			      size_t known_bss_len);
+			      size_t known_bss_len, size_t *rnr_len);
 u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
 			unsigned int frame_stype, u8 elem_count,
 			u8 **elem_offset,
-			const u8 *known_bss, size_t known_bss_len);
+			const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
+			u8 *rnr_count, u8 **rnr_offset, size_t rnr_len);
 void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
 			    enum oper_chan_width *width, u8 *seg0, u8 *seg1);
 
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 46a47d0..8b67669 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -43,9 +43,9 @@
 #ifdef CONFIG_HS20
 static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
 #endif /* CONFIG_HS20 */
-static void ieee802_1x_finished(struct hostapd_data *hapd,
+static bool ieee802_1x_finished(struct hostapd_data *hapd,
 				struct sta_info *sta, int success,
-				int remediation);
+				int remediation, bool logoff);
 
 
 static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
@@ -2287,16 +2287,18 @@
 }
 
 
-static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
-				 int preauth, int remediation)
+static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
+				 int preauth, int remediation, bool logoff)
 {
 	struct hostapd_data *hapd = ctx;
 	struct sta_info *sta = sta_ctx;
 
-	if (preauth)
+	if (preauth) {
 		rsn_preauth_finished(hapd, sta, success);
-	else
-		ieee802_1x_finished(hapd, sta, success, remediation);
+		return false;
+	}
+
+	return ieee802_1x_finished(hapd, sta, success, remediation, logoff);
 }
 
 
@@ -2977,9 +2979,9 @@
 #endif /* CONFIG_HS20 */
 
 
-static void ieee802_1x_finished(struct hostapd_data *hapd,
+static bool ieee802_1x_finished(struct hostapd_data *hapd,
 				struct sta_info *sta, int success,
-				int remediation)
+				int remediation, bool logoff)
 {
 	const u8 *key;
 	size_t len;
@@ -3039,6 +3041,11 @@
 		 * EAP-FAST with anonymous provisioning, may require another
 		 * EAPOL authentication to be started to complete connection.
 		 */
-		ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
+		ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta,
+						       logoff ? 0 : 10);
+		if (logoff && sta->wpa_sm)
+			return true;
 	}
+
+	return false;
 }
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 63f514c..2fb6edf 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -197,7 +197,10 @@
 	ap_sta_set_authorized(hapd, sta, 0);
 	hostapd_set_sta_flags(hapd, sta);
 
-	if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
+	if ((sta->flags & WLAN_STA_WDS) ||
+	    (sta->flags & WLAN_STA_MULTI_AP &&
+	     !(hapd->conf->multi_ap & FRONTHAUL_BSS) &&
+	     !(sta->flags & WLAN_STA_WPS)))
 		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
 
 	if (sta->ipaddr)
@@ -1280,10 +1283,12 @@
 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
 		return;
 
-	if (authorized)
+	if (authorized) {
+		hostapd_prune_associations(hapd, sta->addr);
 		sta->flags |= WLAN_STA_AUTHORIZED;
-	else
+	} else {
 		sta->flags &= ~WLAN_STA_AUTHORIZED;
+	}
 
 #ifdef CONFIG_P2P
 	if (hapd->p2p_group == NULL) {
@@ -1536,11 +1541,12 @@
 
 
 void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
-					    struct sta_info *sta)
+					    struct sta_info *sta,
+					    unsigned timeout)
 {
 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
 		"IEEE 802.1X: Force disconnection of " MACSTR
-		" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
+		" after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout);
 
 	/*
 	 * Add a small sleep to increase likelihood of previously requested
@@ -1548,8 +1554,8 @@
 	 * operations.
 	 */
 	eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
-	eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
-			       hapd, sta);
+	eloop_register_timeout(0, timeout * 1000,
+			       ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
 }
 
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index b59b758..8433ff8 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -373,7 +373,8 @@
 
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
 void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
-					    struct sta_info *sta);
+					    struct sta_info *sta,
+					    unsigned timeout);
 int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
 						   struct sta_info *sta);
 int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 35585cd..2402ad9 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -3085,7 +3085,7 @@
 				      struct wpa_state_machine *sm,
 				      const u8 *r0kh_id, size_t r0kh_id_len,
 				      const u8 *req_pmk_r0_name,
-				      const u8 *req_pmk_r1_name,
+				      u8 *out_pmk_r1_name,
 				      u8 *out_pmk_r1, int *out_pairwise,
 				      struct vlan_description *vlan,
 				      const u8 **identity, size_t *identity_len,
@@ -3096,7 +3096,6 @@
 {
 	struct wpa_auth_config *conf = &wpa_auth->conf;
 	const struct wpa_ft_pmk_r0_sa *r0;
-	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	int expires_in = 0;
 	int session_timeout = 0;
 	struct os_reltime now;
@@ -3115,7 +3114,7 @@
 
 	if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_len, r0->pmk_r0_name,
 			      conf->r1_key_holder,
-			      sm->addr, out_pmk_r1, pmk_r1_name) < 0)
+			      sm->addr, out_pmk_r1, out_pmk_r1_name) < 0)
 		return -1;
 
 	os_get_reltime(&now);
@@ -3126,7 +3125,7 @@
 		session_timeout = r0->session_timeout - now.sec;
 
 	wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, r0->pmk_r0_len,
-			    pmk_r1_name,
+			    out_pmk_r1_name,
 			    sm->pairwise, r0->vlan, expires_in, session_timeout,
 			    r0->identity, r0->identity_len,
 			    r0->radius_cui, r0->radius_cui_len);
diff --git a/src/common/defs.h b/src/common/defs.h
index c0c6dbe..aa3c5cf 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -521,6 +521,11 @@
 
 #define MAX_NUM_MLD_LINKS 15
 
+enum mlo_info_change_reason {
+	MLO_TID_TO_LINK_MAP = 0,
+	MLO_LINK_RECONFIG_AP_REMOVAL = 1
+};
+
 enum sae_pwe {
 	SAE_PWE_HUNT_AND_PECK = 0,
 	SAE_PWE_HASH_TO_ELEMENT = 1,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index cd1b198..dcadfbe 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -550,10 +550,10 @@
 				break;
 			elems->vht_operation = pos;
 			break;
-		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
+		case WLAN_EID_OPERATING_MODE_NOTIFICATION:
 			if (elen != 1)
 				break;
-			elems->vht_opmode_notif = pos;
+			elems->opmode_notif = pos;
 			break;
 		case WLAN_EID_LINK_ID:
 			if (elen < 18)
@@ -777,8 +777,8 @@
 		case WLAN_EID_VHT_OPERATION:
 			elems->vht_operation = NULL;
 			break;
-		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
-			elems->vht_opmode_notif = NULL;
+		case WLAN_EID_OPERATING_MODE_NOTIFICATION:
+			elems->opmode_notif = NULL;
 			break;
 		case WLAN_EID_LINK_ID:
 			elems->link_id = NULL;
@@ -1800,6 +1800,7 @@
 
 static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
 {
+	/* Table E-3 in IEEE Std 802.11-2020 - Operating classes in Japan */
 	switch (op_class) {
 	case 30: /* channels 1..13 */
 	case 56: /* channels 1..9; 40 MHz */
@@ -1823,14 +1824,14 @@
 		if (chan < 34 || chan > 64)
 			return -1;
 		return 5000 + 5 * chan;
-	case 34: /* channels 100-140 */
-	case 35: /* channels 100-140 */
-	case 39: /* channels 100-132; 40 MHz */
-	case 40: /* channels 100-132; 40 MHz */
-	case 44: /* channels 104-136; 40 MHz */
-	case 45: /* channels 104-136; 40 MHz */
-	case 58: /* channels 100-140 */
-		if (chan < 100 || chan > 140)
+	case 34: /* channels 100-144 */
+	case 35: /* reserved */
+	case 39: /* channels 100-140; 40 MHz */
+	case 40: /* reserved */
+	case 44: /* channels 104-144; 40 MHz */
+	case 45: /* reserved */
+	case 58: /* channels 100-144 */
+		if (chan < 100 || chan > 144)
 			return -1;
 		return 5000 + 5 * chan;
 	case 59: /* 60 GHz band, channels 1..6 */
@@ -1884,7 +1885,7 @@
 
 static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
 {
-	/* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+	/* Table E-4 in IEEE Std 802.11-2020 - Global operating classes */
 	switch (op_class) {
 	case 81:
 		/* channels 1..13 */
@@ -1910,10 +1911,10 @@
 		if (chan < 36 || chan > 64)
 			return -1;
 		return 5000 + 5 * chan;
-	case 121: /* channels 100-140 */
-	case 122: /* channels 100-142; 40 MHz */
-	case 123: /* channels 104-136; 40 MHz */
-		if (chan < 100 || chan > 140)
+	case 121: /* channels 100-144 */
+	case 122: /* channels 100-140; 40 MHz */
+	case 123: /* channels 104-144; 40 MHz */
+		if (chan < 100 || chan > 144)
 			return -1;
 		return 5000 + 5 * chan;
 	case 124: /* channels 149,153,157,161 */
@@ -2015,7 +2016,7 @@
 
 	if (!modes || !num_modes)
 		return (freq >= 5260 && freq <= 5320) ||
-			(freq >= 5500 && freq <= 5700);
+			(freq >= 5500 && freq <= 5720);
 
 	for (i = 0; i < num_modes; i++) {
 		for (j = 0; j < modes[i].num_channels; j++) {
@@ -2388,9 +2389,9 @@
 	{ HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
-	{ HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP },
-	{ HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
-	{ HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
+	{ HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, NO_P2P_SUPP },
+	{ HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, NO_P2P_SUPP },
+	{ HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, NO_P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP },
@@ -3065,10 +3066,10 @@
 	case 119: /* channels 52,60; 40 MHz; dfs */
 	case 120: /* channels 56,64; 40 MHz; dfs */
 		return 40;
-	case 121: /* channels 100-140 */
+	case 121: /* channels 100-144 */
 		return 20;
-	case 122: /* channels 100-142; 40 MHz */
-	case 123: /* channels 104-136; 40 MHz */
+	case 122: /* channels 100-140; 40 MHz */
+	case 123: /* channels 104-144; 40 MHz */
 		return 40;
 	case 124: /* channels 149,153,157,161 */
 	case 125: /* channels 149,153,157,161,165,169,173,177 */
@@ -3128,10 +3129,10 @@
 	case 119: /* channels 52,60; 40 MHz; dfs */
 	case 120: /* channels 56,64; 40 MHz; dfs */
 		return CONF_OPER_CHWIDTH_USE_HT;
-	case 121: /* channels 100-140 */
+	case 121: /* channels 100-144 */
 		return CONF_OPER_CHWIDTH_USE_HT;
-	case 122: /* channels 100-142; 40 MHz */
-	case 123: /* channels 104-136; 40 MHz */
+	case 122: /* channels 100-140; 40 MHz */
+	case 123: /* channels 104-144; 40 MHz */
 		return CONF_OPER_CHWIDTH_USE_HT;
 	case 124: /* channels 149,153,157,161 */
 	case 125: /* channels 149,153,157,161,165,169,171 */
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index d1f7218..c7afd34 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -55,7 +55,7 @@
 	const u8 *peer_mgmt;
 	const u8 *vht_capabilities;
 	const u8 *vht_operation;
-	const u8 *vht_opmode_notif;
+	const u8 *opmode_notif;
 	const u8 *vendor_ht_cap;
 	const u8 *vendor_vht;
 	const u8 *p2p;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 9846fb4..b9bb226 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -435,13 +435,13 @@
 #define WLAN_EID_ANTENNA_SECTOR_ID_PATTERN 190
 #define WLAN_EID_VHT_CAP 191
 #define WLAN_EID_VHT_OPERATION 192
-#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
-#define WLAN_EID_VHT_WIDE_BW_CHSWITCH  194
+#define WLAN_EID_EXTENDED_BSS_LOAD 193
+#define WLAN_EID_WIDE_BW_CHSWITCH  194
 #define WLAN_EID_TRANSMIT_POWER_ENVELOPE 195
-#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
-#define WLAN_EID_VHT_AID 197
-#define WLAN_EID_VHT_QUIET_CHANNEL 198
-#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
+#define WLAN_EID_CHANNEL_SWITCH_WRAPPER 196
+#define WLAN_EID_AID 197
+#define WLAN_EID_QUIET_CHANNEL 198
+#define WLAN_EID_OPERATING_MODE_NOTIFICATION 199
 #define WLAN_EID_UPSIM 200
 #define WLAN_EID_REDUCED_NEIGHBOR_REPORT 201
 #define WLAN_EID_TVHT_OPERATION 202
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 6c25816..2fcdfbe 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -899,6 +899,61 @@
  *	configure and fetch the state information of the MLO links affiliated
  *	with the STA interface. The attributes used with this command are
  *	defined in enum qca_wlan_vendor_attr_mlo_link_state.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS: Userspace can use this
+ *	vendor subcommand to trigger channel utilization measurement on entire
+ *	channel width of the connected channel(s). For MLO connection, connected
+ *	channel utilization measurement shall be done on all the MLO links.
+ *	The driver may use regular scan or wideband energy detection feature
+ *	based on the hardware capability for connected channel(s) utilization
+ *	measurement. The driver indicates the connected channel(s) utilization
+ *	measurement completion as an asynchronous event with this command ID to
+ *	userspace. Upon receiving this event, userspace can use
+ *	%NL80211_CMD_GET_INTERFACE to determine the channel width of the current
+ *	connected channel(s) and can derive the channel utilization percentage
+ *	(CU) of each 20 MHz sub-channel of the entire connected channel using
+ *	%NL80211_CMD_GET_SURVEY response.
+ *	CU = %NL80211_SURVEY_INFO_TIME_BUSY * 100 / %NL80211_SURVEY_INFO_TIME.
+ *	This command is only used for STA mode.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP: This vendor subcommand is
+ *	used as an event to notify the userspace of TID-to-link map changes
+ *	negotiated by the driver or updated by associated AP MLD with Beacon,
+ *	Probe Response, or Action frames. The attributes used with this command
+ *	are defined in enum qca_wlan_vendor_attr_tid_to_link_map.
+ *
+ *	Note that the attribute
+ *	%QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR may not correspond to
+ *	the current connected AP MLD address.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG: Notify userspace about the removal
+ *	of STA MLD setup links due to the AP MLD removing the corresponding
+ *	affiliated APs with Multi-Link reconfiguration. If all the STA MLD setup
+ *	links are removed during Multi-Link reconfiguration, the driver shall
+ *	use %NL80211_CMD_DISCONNECT instead of this command since it is a
+ *	connection drop. The attributes used with this command are defined in
+ *	enum qca_wlan_vendor_attr_link_reconfig.
+ *	Note that the attribute
+ *	%QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR may not correspond to
+ *	the current connected AP MLD address.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT: Vendor command to configure
+ *	the driver with MLO link id information on which to transmit the TDLS
+ *	discovery response frame on the configured MLO BSS link when the
+ *	local station is connected in MLO mode. This command is sent to the
+ *	driver prior to the TDLS discovery response management transmit
+ *	operation and is followed immediately by the TDLS discovery response
+ *	management frame transmit command.
+ *
+ *	The driver saves the configured MLO link id information and uses it for
+ *	the following TDLS discovery response frame transmission on the
+ *	configured MLO BSS link and the link id information is cleared in the
+ *	driver after the TDLS discovery response frame is successfully
+ *	transmitted. This behavior is indepent of the TDLS peer STA connection
+ *	mode (MLO or non-MLO).
+ *
+ *	Uses the attributes defined in
+ *	enum qca_wlan_vendor_attr_tdls_disc_rsp_ext.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -1110,6 +1165,10 @@
 	QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE = 225,
 	QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS = 226,
 	QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE = 227,
+	QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS = 228,
+	QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP = 229,
+	QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG = 230,
+	QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT = 231,
 };
 
 /* Compatibility defines for previously used subcmd names.
@@ -1787,6 +1846,11 @@
  *	measurement management frames. If
  *	NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE is set, then
  *	QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP will be ignored.
+ * @QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST: Flag indicates that the device
+ *	in AP mode supports configuring allowed frequency list for AP operation
+ *	with %QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST.
+ * @QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN: Flag indicates
+ *	that the device supports enhanced audio experience over WLAN feature.
  * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
  */
 enum qca_wlan_vendor_features {
@@ -1812,6 +1876,8 @@
 	QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP		= 19,
 	QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA = 20,
 	QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP = 21,
+	QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST = 22,
+	QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN = 23,
 	NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
 };
 
@@ -2839,6 +2905,9 @@
 	 * 8-bit unsigned value. This attribute can be used to configure the
 	 * data path mode to be followed for audio traffic. Possible values
 	 * are defined in enum qca_wlan_audio_data_path.
+	 *
+	 * This attribute is used only when the driver advertises support for
+	 * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN.
 	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AUDIO_DATA_PATH = 82,
 
@@ -2917,6 +2986,57 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MODE = 90,
 
+	/* Nested attribute with frequencies in u32 attributes to configure a
+	 * list of allowed 20 MHz channel center frequencies in MHz for AP
+	 * operation. Whenever performing a channel selection operation, the
+	 * driver shall generate a new list based on this provided list by
+	 * filtering out channels that cannot be used at that time due to
+	 * regulatory or other constraints. The resulting list is used as the
+	 * list of all allowed channels, i.e., operation on any channel that is
+	 * not included is not allowed, whenever performing operations like ACS
+	 * and DFS.
+	 *
+	 * Userspace shall configure this before starting the AP and the
+	 * configuration is valid only from the next BSS start and until the
+	 * BSS is stopped. The driver shall clear this configuration when the
+	 * AP is stopped and fall back to the default behavior for subsequent
+	 * AP operation.
+	 *
+	 * The default behavior when this configuration is not applicable is the
+	 * driver can choose any of the channels supported by the hardware
+	 * except the channels that cannot be used due to regulatory or other
+	 * constraints.
+	 *
+	 * The driver shall reject this configuration if done after the AP is
+	 * started. This attribute can be used to specify user's choice of
+	 * frequencies and static puncture channel list, etc.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST = 91,
+
+	/* Nested attribute to indicate EHT MLO links to be forced active.
+	 * It contains link MAC address attributes. These nested attributes are
+	 * of the type NL80211_ATTR_MAC and are used to force enabling of the
+	 * MLO links corresponding to the indicated link MAC addresses.
+	 * Subsequently, the links corresponding to the link MAC addresses that
+	 * are not indicated are forced inactive.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_ACTIVE_LINKS = 92,
+
+	/* 8-bit unsigned value to configure EMLSR mode entry or exit.
+	 * Uses enum qca_wlan_emlsr_mode values.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_EMLSR_MODE_SWITCH = 93,
+
+	/* 8-bit unsigned value to configure the channel bandwidth
+	 * for CTS frame transmission during the dymamic bandwidth
+	 * signaling CTS procedure referred in IEEE Std 802.11-2020,
+	 * 10.3.2.9 CTS and DMG CTS procedure.
+	 * This configuration is used for testing purposes.
+	 *
+	 * This uses values defined in enum nl80211_chan_width.
+	 */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_CTS_CHANNEL_WIDTH = 94,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -3999,18 +4119,55 @@
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST - 1,
 };
 
+/**
+ * qca_wlan_ll_stats_clr_req_bitmap - Represents the bitmap to clear LL STATS
+ * values for %QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO: Clear all radio statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CCA: Clear cca_busy_time within
+ * radio statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CHANNEL: Clear all channel
+ * statistics within radio statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_SCAN: Clear all scan statistics within
+ * radio statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE: Clear all interface statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_TXRATE: Clear all TX rate statistics
+ * within interface statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_AC: Clear all AC statistics within
+ * interface statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_CONTENTION: Clear all contention
+ * (min, max, avg) statistics within AC statistics.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_ALL_PEER: Clear all peer statistics
+ * on this interface.
+ *
+ * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_PER_PEER: Clear particular peer
+ * statistics depending on the peer_mac.
+ */
+enum qca_wlan_ll_stats_clr_req_bitmap {
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO = 		BIT(0),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CCA = 		BIT(1),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CHANNELS = 	BIT(2),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_SCAN = 		BIT(3),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE = 		BIT(4),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_TXRATE = 	BIT(5),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_AC = 		BIT(6),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_CONTENTION =	BIT(7),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_ALL_PEER = 	BIT(8),
+	QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_PER_PEER = 	BIT(9),
+};
+
 enum qca_wlan_vendor_attr_ll_stats_clr {
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID = 0,
-	/* Unsigned 32bit bitmap for clearing statistics
-	 * All radio statistics                     0x00000001
-	 * cca_busy_time (within radio statistics)  0x00000002
-	 * All channel stats (within radio statistics) 0x00000004
-	 * All scan statistics (within radio statistics) 0x00000008
-	 * All interface statistics                     0x00000010
-	 * All tx rate statistics (within interface statistics) 0x00000020
-	 * All ac statistics (with in interface statistics) 0x00000040
-	 * All contention (min, max, avg) statistics (within ac statisctics)
-	 * 0x00000080.
+	/* Unsigned 32bit bitmap for clearing statistics, specified
+	 * in the enum qca_wlan_ll_stats_clr_req_bitmap.
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK = 1,
 	/* Unsigned 8 bit value: Request to stop statistics collection */
@@ -4030,6 +4187,25 @@
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1,
 };
 
+/**
+ * qca_wlan_ll_stats_get_req_bitmap - Represents the bitmap to request LL STATS
+ * values for %QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK.
+ *
+ * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_RADIO: Request all radio statistics.
+ *
+ * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_IFACE: Request interface statistics.
+ *
+ * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_ALL_PEER: Request all peer statistics.
+ *
+ * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_PER_PEER: Request per peer statistics.
+ */
+enum qca_wlan_ll_stats_get_req_bitmap {
+	QCA_WLAN_LL_STATS_GET_REQ_BITMAP_RADIO =	BIT(0),
+	QCA_WLAN_LL_STATS_GET_REQ_BITMAP_IFACE =	BIT(1),
+	QCA_WLAN_LL_STATS_GET_REQ_BITMAP_ALL_PEER = 	BIT(2),
+	QCA_WLAN_LL_STATS_GET_REQ_BITMAP_PER_PEER = 	BIT(3),
+};
+
 enum qca_wlan_vendor_attr_ll_stats_get {
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID = 0,
 	/* Unsigned 32 bit value provided by the caller issuing the GET stats
@@ -4038,11 +4214,8 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID = 1,
 	/* Unsigned 32 bit value - bit mask to identify what statistics are
-	 * requested for retrieval.
-	 * Radio Statistics 0x00000001
-	 * Interface Statistics 0x00000020
-	 * All Peer Statistics 0x00000040
-	 * Peer Statistics     0x00000080
+	 * requested for retrieval specified in the enum
+	 * qca_wlan_ll_stats_get_req_bitmap
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK = 2,
 	/* keep last */
@@ -4053,24 +4226,65 @@
 
 enum qca_wlan_vendor_attr_ll_stats_results {
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0,
+
+	/*
+	 * For Multi Link Operation (MLO) connection, per-link statistics will
+	 * be sent inside of %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and
+	 * cumulative statistics will be sent outside of
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to maintain backward
+	 * compatibility with legacy user space. Attributes which don't have
+	 * explicit documentation for MLO will be sent only outside of
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK, such attributes values
+	 * don't depend on whether the connection is MLO capable or not, e.g.,
+	 * radio and channel specific attributes.
+	 */
+
 	/* Unsigned 32bit value. Used by the driver; must match the request id
 	 * provided with the QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET command.
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID = 1,
 
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX = 2,
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX = 3,
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX = 4,
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX = 5,
-	/* Signed 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT = 6,
-	/* Signed 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA = 7,
-	/* Signed 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK = 8,
 
 	/* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_* are
@@ -4094,7 +4308,8 @@
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES = 13,
 	/* NULL terminated SSID. An array of 33 Unsigned 8bit values */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID = 14,
-	/* BSSID. An array of 6 unsigned 8 bit values */
+	/* For non-MLO connection, BSSID of the AP. For MLO connection, MLD
+	 * address of the AP. An array of 6 unsigned 8 bit values */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID = 15,
 	/* Country string advertised by AP. An array of 3 unsigned 8 bit
 	 * values.
@@ -4107,6 +4322,15 @@
 
 	/* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* could
 	 * be nested within the interface stats.
+	 * For an MLO connection, all %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_*
+	 * attributes except %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_*
+	 * indicate the aggregate of all links outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_* attributes
+	 * indicate value of the MLO link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 * These attributes indicate the link specific value inside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
 	 */
 
 	/* Type = enum wifi_traffic_ac, e.g., V0, VI, BE and BK */
@@ -4209,6 +4433,12 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG = 48,
 
+	/* Unsigned 32 bit value. This is used to indicate radio ID of the radio
+	 * statistics when %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE is
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO. This is also used
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to indicate radio ID
+	 * of the MLO link.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID = 49,
 	/* Unsigned 32 bit value. Total number of msecs the radio is awake
 	 * accruing over time.
@@ -4255,7 +4485,13 @@
 
 	/* Type = enum wifi_channel_width. Channel width, e.g., 20, 40, 80 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH = 60,
-	/* Unsigned 32 bit value. Primary 20 MHz channel. */
+	/* Unsigned 32 bit value. Primary 20 MHz channel. This is used to
+	 * indicate the primary frequency of the channel when
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE is
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO. This is also used inside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to indicate the frequency
+	 * on which the MLO link is operating.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ = 61,
 	/* Unsigned 32 bit value. Center frequency (MHz) first segment. */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0 = 62,
@@ -4285,7 +4521,9 @@
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67,
 
 	/* Signifies the nested list of peer info attributes
-	 * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_*
+	 * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_*. For MLO connection,
+	 * this also contains %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID to
+	 * indicate on which link the peer is connected.
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO = 68,
 
@@ -4306,16 +4544,32 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA = 71,
 
-	/* Unsigned 64 bit value */
+	/* Unsigned 64 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET = 72,
 
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED = 73,
 
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED = 74,
 
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME = 75,
 
 	/* Unsigned 32 bit value */
@@ -4328,13 +4582,29 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL = 78,
 
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT = 79,
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT = 80,
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT = 81,
-	/* Unsigned 32 bit value */
+	/* Unsigned 32 bit value. For an MLO connection, indicates the value of
+	 * the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
+	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT = 82,
 
 	/* Unsigned int 32 value.
@@ -4358,12 +4628,18 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE = 86,
 	/* u8 value representing the time slicing duty cycle percentage.
-	 * Possible values are 0-100.
+	 * Possible values are 0-100. For an MLO connection, indicates the value
+	 * of the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE = 87,
 	/* Unsigned 32 bit value. The number of Beacon frames which are received
 	 * from the associated AP and indicate buffered unicast frame(s) for us
-	 * in the TIM element.
+	 * in the TIM element. For an MLO connection, indicates the value of the
+	 * link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON = 88,
 	/* Unsigned 32 bit value. The total number of Beacon frames received
@@ -4374,16 +4650,46 @@
 	 *      doesn’t receive any unicast data after this beacon.
 	 * 2)	The related TIM element is still set in the beacon for STA
 	 *	after STA has indicated power save exit by QoS Null Data frame.
+	 * For an MLO connection, indicates the value of the link with the best
+	 * RSSI outside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link
+	 * specific value inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR = 89,
-	/* Attribute used for padding for 64-bit alignment */
-	QCA_WLAN_VENDOR_ATTR_LL_STATS_PAD = 90,
 
 	/* Signed 32 bit value. It represents the noise floor calibration value.
-	 * Possible values are -120~-50 dBm.
+	 * Possible values are -120~-50 dBm. For an MLO connection, indicates
+	 * the value of the link with the best RSSI outside
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value
+	 * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK.
 	 */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL = 90,
 
+	/* Attribute used for padding for 64-bit alignment */
+	QCA_WLAN_VENDOR_ATTR_LL_STATS_PAD = 91,
+
+	/* Unsigned u8 value, link ID of an MLO link. Used inside nested
+	 * attribute %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to represent the
+	 * link ID of the MLO link for which the statistics are embedded in the
+	 * nested attribute. Used inside nested attribute
+	 * %QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO to represent the connected
+	 * link ID of the peer.
+	 */
+	QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID = 92,
+
+	/* A nested array of attributes for each MLO link, each containing
+	 * per-link statistics of a multi link connection. The attributes used
+	 * inside this nested attribute are defined in enum
+	 * qca_wlan_vendor_attr_ll_stats_results.
+	 *
+	 * For non-MLO connection, this attribute is not present and the
+	 * statistics will be sent outside this attribute (without nesting).
+	 *
+	 * For MLO connection, this attribute is present and also cumulative
+	 * statistics of all the links will be sent outside of this attribute
+	 * to be compatible with legacy user space.
+	 */
+	QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK = 93,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
@@ -4865,6 +5171,8 @@
  * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: WPA3-SAE pre-authentication times
  * out.
  * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: WPA3-SAE pre-authentication fails.
+ * @QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK: Roam scan did not happen since the
+ * current network conditions are fine.
  */
 enum qca_vendor_roam_fail_reasons {
 	QCA_ROAM_FAIL_REASON_NONE = 0,
@@ -4897,6 +5205,7 @@
 	QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID = 27,
 	QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT = 28,
 	QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL = 29,
+	QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK = 30,
 };
 
 /*
@@ -8558,9 +8867,19 @@
 };
 
 /**
- * enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for
- * HE operating mode control transmit request. These attributes are
- * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and
+ * enum qca_wlan_emlsr_mode: Enhanced Multi-link Single Radio mode configuration
+ * @QCA_WLAN_EMLSR_MODE_ENTER: Enter EMLSR mode
+ * @QCA_WLAN_EMLSR_MODE_EXIT: Exit EMLSR mode
+ */
+enum qca_wlan_emlsr_mode {
+	QCA_WLAN_EMLSR_MODE_ENTER = 0,
+	QCA_WLAN_EMLSR_MODE_EXIT = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_omi_tx: Represents attributes for HE and
+ * EHT operating mode control transmit request. These attributes are
+ * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX and
  * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
  *
  * @QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: Mandatory 8-bit unsigned value
@@ -8590,21 +8909,48 @@
  * 1 - Determine which HE TB PPDU types are allowed by the STA if UL MU disable
  * bit is not set, else UL MU Tx is suspended.
  *
+ * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN: 8-bit unsigned value in the EHT OM
+ * Control subfield combined with the Rx NSS subfield in the OM Control subfield
+ * indicates NSS - 1, where NSS is the maximum number of spatial streams that
+ * STA supports in reception for PPDU bandwidths less than or equal to 80 MHz.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN: 8-bit unsigned value indicates
+ * 320 MHz operating channel width supported by the EHT STA for both reception
+ * and transmission.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN: 8-bit unsigned value in the EHT OM
+ * Control subfield combined with the Tx NSTS subfield in OM Control subfield
+ * indicates NSTS - 1, where NSTS is the maximum number of space-time streams
+ * that the STA supports in transmission for PPDU bandwidths less than or equal
+ * to 80 MHz.
  */
-enum qca_wlan_vendor_attr_he_omi_tx {
+enum qca_wlan_vendor_attr_omi_tx {
 	QCA_WLAN_VENDOR_ATTR_HE_OMI_INVALID = 0,
 	QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS = 1,
 	QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW = 2,
 	QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE = 3,
 	QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS = 4,
 	QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE = 5,
+	QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN = 6,
+	QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN = 7,
+	QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN = 8,
 
 	/* keep last */
-	QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST,
-	QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX =
-	QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
+	QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_OMI_MAX =
+	QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST - 1,
 };
 
+/* deprecated legacy names */
+#define QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX \
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX
+#define qca_wlan_vendor_attr_he_omi_tx \
+	qca_wlan_vendor_attr_omi_tx
+#define QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST \
+	QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST
+#define QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX \
+	QCA_WLAN_VENDOR_ATTR_OMI_MAX
+
  /**
   * enum qca_wlan_vendor_phy_mode - Different PHY modes
   * These values are used with %QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE.
@@ -8922,10 +9268,10 @@
 	 * channel bandwidth, Tx Nsts and UL MU disable attributes.
 	 * These nested attributes are used to send HE operating mode control
 	 * with configured values.
-	 * Uses the enum qca_wlan_vendor_attr_he_omi_tx attributes.
+	 * Uses the enum qca_wlan_vendor_attr_omi_tx attributes.
 	 * This attribute is used to configure the testbed device.
 	 */
-	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX = 33,
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX = 33,
 
 	/* 8-bit unsigned value to configure +HTC_HE support to indicate the
 	 * support for the reception of a frame that carries an HE variant
@@ -9207,6 +9553,46 @@
 	 */
 	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_TB_SOUNDING_FB_RL = 66,
 
+	/* 8-bit unsigned value to configure the support for receiving an MPDU
+	 * that contains an EHT operating mode control subfield.
+	 * This attribute is used to configure the testbed device.
+	 * 1-enable, 0-disable.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_OM_CTRL_SUPPORT = 67,
+
+	/* 8-bit unsigned value to configure the driver with EMLSR padding delay
+	 * subfield value.
+	 *
+	 * 0 - 0 us
+	 * 1 - 32 us
+	 * 2 - 64 us
+	 * 3 - 128 us
+	 * 4 - 256 us
+	 * 5-255 - Reserved
+	 *
+	 * This attribute is used for testing purposes.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EMLSR_PADDING_DELAY = 68,
+
+	/*
+	 * 8-bit unsigned value to indicate the firmware to force the active MLO
+	 * links to power save mode for the configured number of beacon periods.
+	 * This allows the firmware to suspend STA links for X beacon periods
+	 * and remain asleep even if the AP advertises TIM as opposed to regular
+	 * power save mode where STA links wake up if the AP indicates that it
+	 * has buffered data to send.
+	 * This attribute is used to configure the testbed device.
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FORCE_MLO_POWER_SAVE_BCN_PERIOD = 69,
+
+	/*
+	 * 8-bit unsigned value to indicate the firmware to be in STR MLMR mode
+	 * to enable simultaneous transmission of PPDUs on all active links.
+	 * 0 - Default behavior
+	 * 1 - Enter STR mode for simultaneous data transmission on all links
+	 */
+	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_STR_TX = 70,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -12194,9 +12580,13 @@
  *
  * @QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO: Select interface concurrencies
  * to meet gaming audio latency requirements.
+ * This policy is used only when the driver advertises support for
+ * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN.
  *
  * @QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: Select interface
  * concurrencies to meet lossless audio streaming requirements.
+ * This policy is used only when the driver advertises support for
+ * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN.
  *
  * @QCA_WLAN_CONCURRENT_AP_POLICY_XR: Select interface concurrencies to meet
  * XR (eXtended Reality) requirements.
@@ -15117,4 +15507,100 @@
 	QCA_WLAN_VENDOR_ATTR_LINK_STATE_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_vendor_attr_tid_link_map_status - Definition of attributes used
+ * inside nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK: Required u16 attribute
+ * within nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS.
+ * Indicates the link mapping bitmap of a TID for uplink traffic. It is a
+ * bitmask of the link IDs in which a bit set means that the TID is mapped with
+ * that link ID in uplink traffic. Otherwise, the TID is not mapped to uplink
+ * traffic for that link.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK: Required u16 attribute
+ * within nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS.
+ * Indicates the link mapping bitmap of a TID for downlink traffic. It is a
+ * bitmask of the link IDs in which a bit set means that the TID is mapped with
+ * that link ID in downlink traffic. Otherwise, the TID is not mapped to
+ * downlink traffic for that link.
+ */
+enum qca_wlan_vendor_attr_tid_link_map_status {
+	QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK = 1,
+	QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX =
+	QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_tid_to_link_map: Definition of attributes used with
+ * %QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP event.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR: Required attribute. 6-byte
+ * AP MLD address with which this TID-to-link negotiation mapping is
+ * established/updated.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS: Optional attribute. Array of
+ * nested attributes containing TID-to-links mapping information. This will have
+ * TID-to-link mapping for TID0 to TID7, each containing the uplink and downlink
+ * map information. If this attribute is not present the default TID-to-link
+ * mapping is in use, i.e., all TIDs are mapped to all links for both uplink and
+ * downlink traffic.
+ * See enum qca_wlan_vendor_attr_tid_link_map_status for the nested attributes.
+ */
+enum qca_wlan_vendor_attr_tid_to_link_map {
+	QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR = 1,
+	QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX =
+	QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_link_reconfig: Definition of attributes used
+ * with %QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG event.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR: Required attribute.
+ * 6-byte AP MLD address of the AP which indicated the link reconfiguration.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS: Required u16 attribute.
+ * A bitmap of the removed setup links link IDs.
+ */
+enum qca_wlan_vendor_attr_link_reconfig {
+
+	QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR = 1,
+	QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS = 2,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX =
+	QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_tdls_disc_rsp_ext - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK: u8 attribute.
+ * Indicates the MLO link id on which the TDLS discovery response
+ * frame is to be transmitted.
+ */
+enum qca_wlan_vendor_attr_tdls_disc_rsp_ext {
+	QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK = 1,
+
+	/* Keep last */
+	QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_MAX =
+	QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 15ebcab..367af8f 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -3567,7 +3567,7 @@
 		} else if (*pos == WLAN_EID_HT_CAP &&
 			   pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
 			ie->ht_capabilities = pos + 2;
-		} else if (*pos == WLAN_EID_VHT_AID) {
+		} else if (*pos == WLAN_EID_AID) {
 			if (pos[1] >= 2)
 				ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
 		} else if (*pos == WLAN_EID_VHT_CAP &&
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 4ab2a1b..06149ec 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -110,6 +110,10 @@
 #define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM "
 /** Decision made to skip a within-ESS roam */
 #define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-ROAM "
+/** TID-to-link mapping response event */
+#define WPA_EVENT_T2LM_UPDATE "CTRL-EVENT-T2LM-UPDATE "
+/** MLO link reconfiguration event */
+#define WPA_EVENT_LINK_RECONFIG "CTRL-EVENT-LINK-RECONFIG "
 
 /** IP subnet status change notification
  *
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 1477ecc..3c4de7a 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -430,6 +430,18 @@
 	size_t ssid_len;
 };
 
+struct t2lm_mapping {
+	/**
+	 * downlink - Bitmap of TIDs mapped with a link in downlink direction
+	 */
+	u8 downlink;
+
+	/**
+	 * uplink - Bitmap of TIDs mapped with a link in uplink direction
+	 */
+	u8 uplink;
+};
+
 /**
  * struct wpa_driver_scan_params - Scan parameters
  * Data for struct wpa_driver_ops::scan2().
@@ -1733,6 +1745,38 @@
 	 * subchannel is punctured, otherwise active.
 	 */
 	u16 punct_bitmap;
+
+	/**
+	 * rnr_elem - This buffer contains all of reduced neighbor report (RNR)
+	 * elements
+	 */
+	u8 *rnr_elem;
+
+	/**
+	 * rnr_elem_len - Length of rnr_elem buffer
+	 */
+	size_t rnr_elem_len;
+
+	/**
+	 * rnr_elem_count - Number of RNR elements
+	 */
+	unsigned int rnr_elem_count;
+
+	/**
+	 * rnr_elem_offset - The offsets to the elements in rnr_elem.
+	 * The driver will use these to include RNR elements in EMA beacons.
+	 */
+	u8 **rnr_elem_offset;
+
+	/**
+	 * allowed_freqs - List of allowed 20 MHz channel center frequencies in
+	 * MHz for AP operation. Drivers which support this parameter will
+	 * generate a new list based on this provided list by filtering out
+	 * channels that cannot be used at that time due to regulatory or other
+	 * constraints. The resulting list is used as the list of all allowed
+	 * channels whenever performing operations like ACS and DFS.
+	 */
+	int *allowed_freqs;
 };
 
 struct wpa_driver_mesh_bss_params {
@@ -2889,6 +2933,7 @@
 };
 
 struct driver_sta_mlo_info {
+	bool default_map;
 	u16 req_links; /* bitmap of requested link IDs */
 	u16 valid_links; /* bitmap of accepted link IDs */
 	u8 assoc_link_id;
@@ -2897,6 +2942,7 @@
 		u8 addr[ETH_ALEN];
 		u8 bssid[ETH_ALEN];
 		unsigned int freq;
+		struct t2lm_mapping t2lmap;
 	} links[MAX_NUM_MLD_LINKS];
 };
 
@@ -5618,6 +5664,21 @@
 	 * Described in wpa_event_data.ch_switch.
 	 */
 	EVENT_LINK_CH_SWITCH_STARTED,
+
+	/**
+	 * EVENT_TID_LINK_MAP - MLD event to set TID-to-link mapping
+	 *
+	 * This event is used by the driver to indicate the received TID-to-link
+	 * mapping response from the associated AP MLD.
+	 *
+	 * Described in wpa_event_data.t2l_map_info.
+	 */
+	EVENT_TID_LINK_MAP,
+
+	/**
+	 * EVENT_LINK_RECONFIG - Notification that AP links removed
+	 */
+	EVENT_LINK_RECONFIG,
 };
 
 
@@ -6542,6 +6603,15 @@
 		const u8 *td_bitmap;
 		size_t td_bitmap_len;
 	} port_authorized;
+
+	/**
+	 * struct tid_link_map_info - Data for EVENT_TID_LINK_MAP
+	 */
+	struct tid_link_map_info {
+		bool default_map;
+		u8 valid_links;
+		struct t2lm_mapping t2lmap[MAX_NUM_MLD_LINKS];
+	} t2l_map_info;
 };
 
 /**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index bbd1a7c..f3625e8 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -98,6 +98,8 @@
 	E2S(PASN_AUTH);
 	E2S(LINK_CH_SWITCH);
 	E2S(LINK_CH_SWITCH_STARTED);
+	E2S(TID_LINK_MAP);
+	E2S(LINK_RECONFIG);
 	}
 
 	return "UNKNOWN";
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index cc87e72..5f39e80 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -283,6 +283,10 @@
 #ifdef CONFIG_DRIVER_NL80211_QCA
 	os_free(drv->pending_roam_data);
 	drv->pending_roam_data = NULL;
+	os_free(drv->pending_t2lm_data);
+	drv->pending_t2lm_data = NULL;
+	os_free(drv->pending_link_reconfig_data);
+	drv->pending_link_reconfig_data = NULL;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 	drv->auth_mld = false;
@@ -4838,12 +4842,80 @@
 		nla_nest_end(msg, elems);
 	}
 
+	if (!params->ema)
+		return 0;
+
+	if (params->rnr_elem_count && params->rnr_elem_len &&
+	    params->rnr_elem_offset && *params->rnr_elem_offset) {
+		u8 i, **offs = params->rnr_elem_offset;
+
+		elems = nla_nest_start(msg, NL80211_ATTR_EMA_RNR_ELEMS);
+		if (!elems)
+			return -1;
+
+		for (i = 0; i < params->rnr_elem_count - 1; i++) {
+			if (nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i]))
+				return -1;
+		}
+
+		if (nla_put(msg, i + 1, *offs + params->rnr_elem_len - offs[i],
+			    offs[i]))
+			return -1;
+		nla_nest_end(msg, elems);
+	}
+
 	return 0;
 }
 
 #endif /* CONFIG_IEEE80211AX */
 
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static void qca_set_allowed_ap_freqs(struct wpa_driver_nl80211_data *drv,
+				    const int *freqs, int num_freqs)
+{
+	struct nl_msg *msg;
+	struct nlattr *params, *freqs_list;
+	int i, ret;
+
+	if (!drv->set_wifi_conf_vendor_cmd_avail || !drv->qca_ap_allowed_freqs)
+		return;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set AP allowed frequency list");
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
+	    !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)))
+		goto err;
+
+	freqs_list = nla_nest_start(
+		msg, QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST);
+	if (!freqs_list)
+		goto err;
+
+	for (i = 0; i < num_freqs; i++) {
+		if (nla_put_u32(msg, i, freqs[i]))
+			goto err;
+	}
+
+	nla_nest_end(msg, freqs_list);
+	nla_nest_end(msg, params);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	if (ret)
+		wpa_printf(MSG_ERROR,
+			   "nl80211: Failed set AP alllowed frequency list: %d (%s)",
+			   ret, strerror(-ret));
+
+	return;
+err:
+	nlmsg_free(msg);
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
 				     struct wpa_driver_ap_params *params)
 {
@@ -5166,6 +5238,12 @@
 			goto fail;
 	}
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+	if (cmd == NL80211_CMD_NEW_BEACON && params->allowed_freqs)
+		qca_set_allowed_ap_freqs(drv, params->allowed_freqs,
+					 int_array_len(params->allowed_freqs));
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
 	ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -9618,6 +9696,11 @@
 		}
 	}
 
+	if (os_strstr(param, "secure_ltf=1")) {
+		drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA |
+			WPA_DRIVER_FLAGS2_SEC_LTF_AP;
+	}
+
 	return 0;
 }
 
@@ -10662,8 +10745,10 @@
 		struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info;
 
 		res = os_snprintf(pos, end - pos,
-				  "ap_mld_addr=" MACSTR "\n",
-				   MAC2STR(mlo->ap_mld_addr));
+				  "ap_mld_addr=" MACSTR "\n"
+				  "default_map=%d\n",
+				   MAC2STR(mlo->ap_mld_addr),
+				   mlo->default_map);
 		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
@@ -10682,6 +10767,18 @@
 			if (os_snprintf_error(end - pos, res))
 				return pos - buf;
 			pos += res;
+
+			if (!mlo->default_map) {
+				res = os_snprintf(
+					pos, end - pos,
+					"uplink_map[%u]=%x\n"
+					"downlink_map[%u]=%x\n",
+					i, mlo->links[i].t2lmap.uplink,
+					i, mlo->links[i].t2lmap.downlink);
+				if (os_snprintf_error(end - pos, res))
+					return pos - buf;
+				pos += res;
+			}
 		}
 	}
 
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index bd35e52..c597295 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -199,6 +199,7 @@
 	unsigned int uses_6ghz:1;
 	unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
 	unsigned int puncturing:1;
+	unsigned int qca_ap_allowed_freqs:1;
 
 	u64 vendor_scan_cookie;
 	u64 remain_on_chan_cookie;
@@ -257,6 +258,10 @@
 	bool roam_indication_done;
 	u8 *pending_roam_data;
 	size_t pending_roam_data_len;
+	u8 *pending_t2lm_data;
+	size_t pending_t2lm_data_len;
+	u8 *pending_link_reconfig_data;
+	size_t pending_link_reconfig_data_len;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 };
 
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 3152529..09771bb 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1414,6 +1414,9 @@
 		    QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP,
 		    &info))
 		drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP;
+	if (check_feature(QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST,
+			  &info))
+		drv->qca_ap_allowed_freqs = 1;
 	os_free(info.flags);
 }
 
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 14d7842..e99afdc 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -421,6 +421,78 @@
 }
 
 
+static void qca_nl80211_link_reconfig_event(struct wpa_driver_nl80211_data *drv,
+					    u8 *data, size_t len)
+{
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX + 1];
+	u16 removed_links;
+	u8 *ap_mld;
+	int i;
+
+	if (!data)
+		return;
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX,
+		      (struct nlattr *) data, len, NULL) ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR])
+		return;
+
+	ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR]);
+	wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR
+		   " received in link reconfig event", MAC2STR(ap_mld));
+	if (!drv->sta_mlo_info.valid_links ||
+	    os_memcmp(drv->sta_mlo_info.ap_mld_addr, ap_mld, ETH_ALEN) != 0) {
+		if (drv->pending_link_reconfig_data == data) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Drop pending link reconfig event since AP MLD not matched even after new connect/roam event");
+			os_free(drv->pending_link_reconfig_data);
+			drv->pending_link_reconfig_data = NULL;
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Cache new link reconfig event till next connect/roam event");
+		if (drv->pending_link_reconfig_data) {
+			wpa_printf(MSG_DEBUG, "nl80211: Override old link reconfig event data");
+			os_free(drv->pending_link_reconfig_data);
+		}
+		drv->pending_link_reconfig_data = os_memdup(data, len);
+		if (!drv->pending_link_reconfig_data)
+			return;
+		drv->pending_link_reconfig_data_len = len;
+		return;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS])
+		return;
+	removed_links = nla_get_u16(
+		tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS]);
+
+	drv->sta_mlo_info.valid_links &= ~removed_links;
+
+	/*
+	 * Set default BSSID to the BSSID of the lowest link ID of remaining
+	 * links when the link used for (re)association is removed.
+	 */
+	if (removed_links & BIT(drv->sta_mlo_info.assoc_link_id)) {
+		for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+			if (!(drv->sta_mlo_info.valid_links & BIT(i)))
+				continue;
+
+			os_memcpy(drv->bssid, drv->sta_mlo_info.links[i].bssid,
+				  ETH_ALEN);
+			drv->sta_mlo_info.assoc_link_id = i;
+			break;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Removed MLO links bitmap: 0x%x",
+		   removed_links);
+
+	wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL);
+}
+
+
 static void
 nl80211_parse_qca_vendor_mlo_link_info(struct driver_sta_mlo_info *mlo,
 				       struct nlattr *mlo_links)
@@ -713,6 +785,126 @@
 }
 
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static void
+qca_nl80211_tid_to_link_map_event(struct wpa_driver_nl80211_data *drv,
+				  u8 *data, size_t len)
+{
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX + 1];
+	struct nlattr *tids;
+	union wpa_event_data event;
+	u8 *ap_mld;
+	int i, rem, tidnum = 0;
+
+	os_memset(&event, 0, sizeof(event));
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX,
+		      (struct nlattr *) data, len, NULL) ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR])
+		return;
+
+	ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR
+		   " received in TID to link mapping event", MAC2STR(ap_mld));
+	if (!drv->sta_mlo_info.valid_links ||
+	    os_memcmp(drv->sta_mlo_info.ap_mld_addr, ap_mld, ETH_ALEN) != 0) {
+		if (drv->pending_t2lm_data == data) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Drop pending TID-to-link mapping event since AP MLD not matched even after new connect/roam event");
+			os_free(drv->pending_t2lm_data);
+			drv->pending_t2lm_data = NULL;
+			return;
+		}
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Cache new TID-to-link map event until the next connect/roam event");
+		if (drv->pending_t2lm_data) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Override old TID-to-link map event data");
+			os_free(drv->pending_t2lm_data);
+		}
+		drv->pending_t2lm_data = os_memdup(data, len);
+		if (!drv->pending_t2lm_data)
+			return;
+		drv->pending_t2lm_data_len = len;
+		return;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Default TID-to-link map");
+		event.t2l_map_info.default_map = true;
+		goto out;
+	}
+
+	event.t2l_map_info.default_map = false;
+
+	nla_for_each_nested(tids,
+			    tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS],
+			    rem) {
+		u16 uplink, downlink;
+		struct nlattr *tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX + 1];
+
+		if (nla_parse_nested(
+			    tid, QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX,
+			    tids,  NULL)) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: TID-to-link: nla_parse_nested() failed");
+			return;
+		}
+
+		if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: TID-to-link: uplink not present for tid: %d",
+				   tidnum);
+			return;
+		}
+		uplink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]);
+
+		if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: TID-to-link: downlink not present for tid: %d",
+				   tidnum);
+			return;
+		}
+		downlink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]);
+
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: TID-to-link: Received uplink %x downlink %x",
+			   uplink, downlink);
+		for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+			if (!(drv->sta_mlo_info.valid_links & BIT(i)))
+				continue;
+			if (uplink & BIT(i))
+				event.t2l_map_info.t2lmap[i].uplink |=
+					BIT(tidnum);
+			if (downlink & BIT(i))
+				event.t2l_map_info.t2lmap[i].downlink |=
+					BIT(tidnum);
+		}
+
+		tidnum++;
+	}
+
+out:
+	drv->sta_mlo_info.default_map = event.t2l_map_info.default_map;
+
+	event.t2l_map_info.valid_links = drv->sta_mlo_info.valid_links;
+	for (i = 0; i < MAX_NUM_MLD_LINKS && !drv->sta_mlo_info.default_map;
+	     i++) {
+		if (!(drv->sta_mlo_info.valid_links & BIT(i)))
+			continue;
+
+		drv->sta_mlo_info.links[i].t2lmap.uplink =
+			event.t2l_map_info.t2lmap[i].uplink;
+		drv->sta_mlo_info.links[i].t2lmap.downlink =
+			event.t2l_map_info.t2lmap[i].downlink;
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_TID_LINK_MAP, &event);
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
 static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
 			       enum nl80211_commands cmd, bool qca_roam_auth,
 			       struct nlattr *status,
@@ -912,6 +1104,19 @@
 	 * operation that happened in parallel with the disconnection request.
 	 */
 	drv->ignore_next_local_disconnect = 0;
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+	if (drv->pending_t2lm_data)
+		qca_nl80211_tid_to_link_map_event(drv, drv->pending_t2lm_data,
+						  drv->pending_t2lm_data_len);
+	else
+		drv->sta_mlo_info.default_map = true;
+
+	if (drv->pending_link_reconfig_data)
+		qca_nl80211_link_reconfig_event(
+			drv, drv->pending_link_reconfig_data,
+			drv->pending_link_reconfig_data_len);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
 }
 
 
@@ -2861,6 +3066,12 @@
 		qca_nl80211_pasn_auth(drv, data, len);
 		break;
 #endif /* CONFIG_PASN */
+	case QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP:
+		qca_nl80211_tid_to_link_map_event(drv, data, len);
+		break;
+	case QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG:
+		qca_nl80211_link_reconfig_event(drv, data, len);
+		break;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 	default:
 		wpa_printf(MSG_DEBUG,
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 7a7890c..4d33b14 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -21,7 +21,7 @@
 #include "driver_nl80211.h"
 
 
-#define MAX_NL80211_NOISE_FREQS 50
+#define MAX_NL80211_NOISE_FREQS 100
 
 struct nl80211_noise_info {
 	u32 freq[MAX_NL80211_NOISE_FREQS];
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 9a0ac03..c59fec4 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -2794,6 +2794,17 @@
  * @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should
  *	be enabled or not (flag attribute).
  *
+ * @NL80211_ATTR_EMA_RNR_ELEMS: Optional nested attribute for
+ *	reduced neighbor report (RNR) elements. This attribute can be used
+ *	only when NL80211_MBSSID_CONFIG_ATTR_EMA is enabled.
+ *	Userspace is responsible for splitting the RNR into multiple
+ *	elements such that each element excludes the non-transmitting
+ *	profiles already included in the MBSSID element
+ *	(%NL80211_ATTR_MBSSID_ELEMS) at the same index. Each EMA beacon
+ *	will be generated by adding MBSSID and RNR elements at the same
+ *	index. If the userspace includes more RNR elements than number of
+ *	MBSSID elements then these will be added in every EMA beacon.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3328,6 +3339,8 @@
 	NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
 	NL80211_ATTR_HW_TIMESTAMP_ENABLED,
 
+	NL80211_ATTR_EMA_RNR_ELEMS,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -4048,6 +4061,10 @@
  * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
  *	the allowed channel bandwidth configurations.
  *	Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+ * @NL80211_BAND_ATTR_S1G_MCS_NSS_SET: S1G capabilities, supported S1G-MCS and NSS
+ *	set subfield, as in the S1G information IE, 5 bytes
+ * @NL80211_BAND_ATTR_S1G_CAPA: S1G capabilities information subfield as in the
+ *	S1G information IE, 10 bytes
  * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
  * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
  */
@@ -4068,6 +4085,9 @@
 	NL80211_BAND_ATTR_EDMG_CHANNELS,
 	NL80211_BAND_ATTR_EDMG_BW_CONFIG,
 
+	NL80211_BAND_ATTR_S1G_MCS_NSS_SET,
+	NL80211_BAND_ATTR_S1G_CAPA,
+
 	/* keep last */
 	__NL80211_BAND_ATTR_AFTER_LAST,
 	NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -6544,7 +6564,9 @@
  *	channels on which APs are expected to be found. Note that when not set,
  *	the scan logic would scan all 6GHz channels, but since transmission of
  *	probe requests on non PSC channels is limited, it is highly likely that
- *	these channels would passively be scanned.
+ *	these channels would passively be scanned. Also note that when the flag
+ *	is set, in addition to the colocated APs, PSC channels would also be
+ *	scanned if the user space has asked for it.
  */
 enum nl80211_scan_flags {
 	NL80211_SCAN_FLAG_LOW_PRIORITY				= 1<<0,
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 59fac90..1454447 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -483,6 +483,14 @@
 	 * 1 = use cryptobinding if server supports it
 	 * 2 = require cryptobinding
 	 *
+	 * phase2_auth option can be used to control Phase 2 (i.e., within TLS
+	 * tunnel) behavior for PEAP:
+	 * 0 = do not require Phase 2 authentication
+	 * 1 = require Phase 2 authentication when client certificate
+	 *  (private_key/client_cert) is not used and TLS session resumption was
+	 *  not used (default)
+	 * 2 = require Phase 2 authentication in all cases
+	 *
 	 * EAP-WSC (WPS) uses following options: pin=Device_Password and
 	 * uuid=Device_UUID
 	 *
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 12e30df..6080697 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -67,6 +67,7 @@
 	u8 cmk[20];
 	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
 		  * is enabled. */
+	enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth;
 };
 
 
@@ -114,6 +115,19 @@
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
 	}
 
+	if (os_strstr(phase1, "phase2_auth=0")) {
+		data->phase2_auth = NO_AUTH;
+		wpa_printf(MSG_DEBUG,
+			   "EAP-PEAP: Do not require Phase 2 authentication");
+	} else if (os_strstr(phase1, "phase2_auth=1")) {
+		data->phase2_auth = FOR_INITIAL;
+		wpa_printf(MSG_DEBUG,
+			   "EAP-PEAP: Require Phase 2 authentication for initial connection");
+	} else if (os_strstr(phase1, "phase2_auth=2")) {
+		data->phase2_auth = ALWAYS;
+		wpa_printf(MSG_DEBUG,
+			   "EAP-PEAP: Require Phase 2 authentication for all cases");
+	}
 #ifdef EAP_TNC
 	if (os_strstr(phase1, "tnc=soh2")) {
 		data->soh = 2;
@@ -142,6 +156,7 @@
 	data->force_peap_version = -1;
 	data->peap_outer_success = 2;
 	data->crypto_binding = OPTIONAL_BINDING;
+	data->phase2_auth = FOR_INITIAL;
 
 	if (config && config->phase1)
 		eap_peap_parse_phase1(data, config->phase1);
@@ -454,6 +469,20 @@
 }
 
 
+static bool peap_phase2_sufficient(struct eap_sm *sm,
+				   struct eap_peap_data *data)
+{
+	if ((data->phase2_auth == ALWAYS ||
+	     (data->phase2_auth == FOR_INITIAL &&
+	      !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn) &&
+	      !data->ssl.client_cert_conf) ||
+	     data->phase2_eap_started) &&
+	    !data->phase2_eap_success)
+		return false;
+	return true;
+}
+
+
 /**
  * eap_tlv_process - Process a received EAP-TLV message and generate a response
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
@@ -568,6 +597,11 @@
 					   " - force failed Phase 2");
 				resp_status = EAP_TLV_RESULT_FAILURE;
 				ret->decision = DECISION_FAIL;
+			} else if (!peap_phase2_sufficient(sm, data)) {
+				wpa_printf(MSG_INFO,
+					   "EAP-PEAP: Server indicated Phase 2 success, but sufficient Phase 2 authentication has not been completed");
+				resp_status = EAP_TLV_RESULT_FAILURE;
+				ret->decision = DECISION_FAIL;
 			} else {
 				resp_status = EAP_TLV_RESULT_SUCCESS;
 				ret->decision = DECISION_UNCOND_SUCC;
@@ -887,8 +921,7 @@
 			/* EAP-Success within TLS tunnel is used to indicate
 			 * shutdown of the TLS channel. The authentication has
 			 * been completed. */
-			if (data->phase2_eap_started &&
-			    !data->phase2_eap_success) {
+			if (!peap_phase2_sufficient(sm, data)) {
 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
 					   "Success used to indicate success, "
 					   "but Phase 2 EAP was not yet "
@@ -1199,8 +1232,9 @@
 static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
 {
 	struct eap_peap_data *data = priv;
+
 	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
-		data->phase2_success;
+		data->phase2_success && data->phase2_auth != ALWAYS;
 }
 
 
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 3050456..5594216 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -242,6 +242,12 @@
 
 	sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
 
+	if (!phase2)
+		data->client_cert_conf = params->client_cert ||
+			params->client_cert_blob ||
+			params->private_key ||
+			params->private_key_blob;
+
 	return 0;
 }
 
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 9ac0012..3348634 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -79,6 +79,11 @@
 	 * tls_v13 - Whether TLS v1.3 or newer is used
 	 */
 	int tls_v13;
+
+	/**
+	 * client_cert_conf: Whether client certificate has been configured
+	 */
+	bool client_cert_conf;
 };
 
 
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index c8e2de0..6adc222 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -65,9 +65,30 @@
 	int ready_for_tnc;
 	int tnc_started;
 #endif /* EAP_TNC */
+
+	enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth;
 };
 
 
+static void eap_ttls_parse_phase1(struct eap_ttls_data *data,
+				  const char *phase1)
+{
+	if (os_strstr(phase1, "phase2_auth=0")) {
+		data->phase2_auth = NO_AUTH;
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TTLS: Do not require Phase 2 authentication");
+	} else if (os_strstr(phase1, "phase2_auth=1")) {
+		data->phase2_auth = FOR_INITIAL;
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TTLS: Require Phase 2 authentication for initial connection");
+	} else if (os_strstr(phase1, "phase2_auth=2")) {
+		data->phase2_auth = ALWAYS;
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TTLS: Require Phase 2 authentication for all cases");
+	}
+}
+
+
 static void * eap_ttls_init(struct eap_sm *sm)
 {
 	struct eap_ttls_data *data;
@@ -82,6 +103,10 @@
 	selected = "EAP";
 	selected_non_eap = 0;
 	data->phase2_type = EAP_TTLS_PHASE2_EAP;
+	data->phase2_auth = FOR_INITIAL;
+
+	if (config && config->phase1)
+		eap_ttls_parse_phase1(data, config->phase1);
 
 	/*
 	 * Either one auth= type or one or more autheap= methods can be
@@ -1703,8 +1728,9 @@
 static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
 {
 	struct eap_ttls_data *data = priv;
+
 	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
-		data->phase2_success;
+		data->phase2_success && data->phase2_auth != ALWAYS;
 }
 
 
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 1c11cb6..e1b82eb 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -217,6 +217,9 @@
 SM_STATE(AUTH_PAE, DISCONNECTED)
 {
 	int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
+	bool pre_auth_logoff = sm->auth_pae_state == AUTH_PAE_ABORTING &&
+		sm->eapolLogoff && !sm->authenticated;
+	bool logoff = sm->eapolLogoff;
 
 	if (sm->eapolLogoff) {
 		if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
@@ -231,10 +234,14 @@
 	setPortUnauthorized();
 	sm->reAuthCount = 0;
 	sm->eapolLogoff = false;
-	if (!from_initialize) {
-		sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
-				       sm->flags & EAPOL_SM_PREAUTH,
-				       sm->remediation);
+	if (!from_initialize && !pre_auth_logoff) {
+		if (sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
+					   sm->flags & EAPOL_SM_PREAUTH,
+					   sm->remediation, logoff)) {
+			wpa_printf(MSG_DEBUG,
+				   "EAPOL: Do not restart since lower layers will disconnect the port after EAPOL-Logoff");
+			sm->stopped = true;
+		}
 	}
 }
 
@@ -291,7 +298,8 @@
 				   eap_server_get_name(0, sm->eap_type_supp));
 	}
 	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
-			       sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
+			       sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
+			       false);
 }
 
 
@@ -316,8 +324,11 @@
 			   sm->eap_type_authsrv,
 			   eap_server_get_name(0, sm->eap_type_authsrv),
 			   extra);
+	if (sm->authSuccess)
+		sm->authenticated++;
 	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
-			       sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
+			       sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
+			       false);
 }
 
 
@@ -397,7 +408,8 @@
 			SM_ENTER(AUTH_PAE, DISCONNECTED);
 			break;
 		case AUTH_PAE_DISCONNECTED:
-			SM_ENTER(AUTH_PAE, RESTART);
+			if (!sm->stopped)
+				SM_ENTER(AUTH_PAE, RESTART);
 			break;
 		case AUTH_PAE_RESTART:
 			if (!sm->eap_if->eapRestart)
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 61b7039..7296a3a 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -46,8 +46,8 @@
 			   size_t datalen);
 	void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
 			 size_t datalen);
-	void (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
-			 int remediation);
+	bool (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
+			 int remediation, bool logoff);
 	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
 			    int phase2, struct eap_user *user);
 	int (*sta_entry_alive)(void *ctx, const u8 *addr);
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index 3c68983..a0cef0f 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -171,6 +171,10 @@
 	int remediation;
 
 	u64 acct_multi_session_id;
+
+	unsigned int authenticated; /* The number of times authentication has
+				     * been completed successfully. */
+	bool stopped;
 };
 
 #endif /* EAPOL_AUTH_SM_I_H */
diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h
index 9c2f397..a4850a2 100644
--- a/src/pasn/pasn_common.h
+++ b/src/pasn/pasn_common.h
@@ -95,7 +95,8 @@
 	u8 wrapped_data_format;
 	struct wpabuf *secret;
 
-	/* Reponder */
+	/* Responder */
+	bool noauth; /* Whether PASN without mutual authentication is enabled */
 	int wpa_key_mgmt;
 	int rsn_pairwise;
 	bool derive_kdk;
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index 3b1912d..78a9dd7 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -743,6 +743,12 @@
 		goto send_resp;
 	}
 
+	if (!pasn->noauth && pasn->akmp == WPA_KEY_MGMT_PASN) {
+		wpa_printf(MSG_DEBUG, "PASN: Refuse PASN-UNAUTH");
+		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,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 3a39886..5a28ef5 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -4561,6 +4561,9 @@
 		sm->dpp_pfs = value;
 		break;
 #endif /* CONFIG_DPP2 */
+	case WPA_PARAM_WMM_ENABLED:
+		sm->wmm_enabled = value;
+		break;
 	default:
 		break;
 	}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index cd3ef3e..47d2344 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -123,6 +123,7 @@
 	WPA_PARAM_USE_EXT_KEY_ID,
 	WPA_PARAM_FT_RSNXE_USED,
 	WPA_PARAM_DPP_PFS,
+	WPA_PARAM_WMM_ENABLED,
 	WPA_PARAM_OCI_FREQ_EAPOL,
 	WPA_PARAM_OCI_FREQ_EAPOL_G2,
 	WPA_PARAM_OCI_FREQ_FT_ASSOC,
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index a3c13b1..300ef54 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -220,6 +220,8 @@
 	int dpp_pfs;
 #endif /* CONFIG_DPP2 */
 	struct wpa_sm_mlo mlo;
+
+	bool wmm_enabled;
 };
 
 
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 50bd2b2..2a6c79b 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -109,6 +109,10 @@
 {
 	u16 capab = 0;
 
+	if (sm->wmm_enabled) {
+		/* Advertise 16 PTKSA replay counters when using WMM */
+		capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+	}
 	if (sm->mfp)
 		capab |= WPA_CAPABILITY_MFPC;
 	if (sm->mfp == 2)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index c643b26..f8da781 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -442,7 +442,9 @@
   nl80211 = Linux nl80211/cfg80211
   wext = Linux wireless extensions (generic)
   wired = wpa_supplicant wired Ethernet driver
+  macsec_linux = MACsec Ethernet driver for Linux
   roboswitch = wpa_supplicant Broadcom switch driver
+  none = no driver (RADIUS server/WPS ER only)
   bsd = BSD 802.11 support (Atheros, etc.)
   ndis = Windows NDIS driver
 
diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/aidl.cpp
index 6a22a2a..f221862 100644
--- a/wpa_supplicant/aidl/aidl.cpp
+++ b/wpa_supplicant/aidl/aidl.cpp
@@ -312,6 +312,22 @@
 	aidl_manager->notifyDisconnectReason(wpa_s);
 }
 
+void wpas_aidl_notify_mlo_info_change_reason(struct wpa_supplicant *wpa_s,
+					     enum mlo_info_change_reason reason)
+{
+	if (!wpa_s)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notifying MLO info change reason to aidl control: %d",
+		   reason);
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	aidl_manager->notifyMloLinksInfoChanged(wpa_s, reason);
+}
+
 void wpas_aidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
 	const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len)
 {
diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/aidl.h
index f9b374e..dfe5c74 100644
--- a/wpa_supplicant/aidl/aidl.h
+++ b/wpa_supplicant/aidl/aidl.h
@@ -52,6 +52,10 @@
 	void wpas_aidl_notify_hs20_rx_terms_and_conditions_acceptance(
 			struct wpa_supplicant *wpa_s, const char *url);
 	void wpas_aidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+	void wpas_aidl_notify_mlo_info_change_reason(
+		struct wpa_supplicant *wpa_s,
+		enum mlo_info_change_reason reason);
+
 	void wpas_aidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len);
 	void wpas_aidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
@@ -198,6 +202,9 @@
 		struct wpa_supplicant *wpa_s, const char *url)
 {}
 static void wpas_aidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
+static void wpas_aidl_notify_mlo_info_change_reason(
+	struct wpa_supplicant *wpa_s, enum mlo_info_change_reason reason)
+{}
 static void wpas_aidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid,
 	u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len) {}
 static void wpas_aidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index db566ab..b3baf5b 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -2666,6 +2666,23 @@
 			std::placeholders::_1, wpa_s->dscp_req_dialog_token, qosPolicyData));
 }
 
+void AidlManager::notifyMloLinksInfoChanged(struct wpa_supplicant *wpa_s,
+					    enum mlo_info_change_reason reason)
+{
+	if (!wpa_s)
+		return;
+
+	if (sta_iface_object_map_.find(wpa_s->ifname) ==
+		sta_iface_object_map_.end())
+		return;
+
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname),
+		std::bind(&ISupplicantStaIfaceCallback::onMloLinksInfoChanged,
+			  std::placeholders::_1,
+			  static_cast<ISupplicantStaIfaceCallback::MloLinkInfoChangeReason>(reason)));
+}
+
 ssize_t AidlManager::getCertificate(const char* alias, uint8_t** value) {
 	if (alias == nullptr || value == nullptr) {
 		wpa_printf(MSG_ERROR, "Null pointer argument was passed to getCertificate");
diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/aidl_manager.h
index fcea1f7..8f1f177 100644
--- a/wpa_supplicant/aidl/aidl_manager.h
+++ b/wpa_supplicant/aidl/aidl_manager.h
@@ -167,6 +167,8 @@
 	ssize_t listAliases(const char *prefix, char ***aliases);
 	void notifyQosPolicyScsResponse(struct wpa_supplicant *wpa_s,
 			unsigned int count, int **scs_resp);
+	void notifyMloLinksInfoChanged(struct wpa_supplicant *wpa_s,
+				       enum mlo_info_change_reason reason);
 
 	// Methods called from aidl objects.
 	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index afcd4b5..fb3ebcd 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -2021,6 +2021,7 @@
 std::pair<MloLinksInfo, ndk::ScopedAStatus> StaIface::getConnectionMloLinksInfoInternal()
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct driver_sta_mlo_info mlo;
 	MloLinksInfo linksInfo;
 	MloLink link;
 
@@ -2028,6 +2029,7 @@
 	if (!wpa_s->valid_links)
 		 return {linksInfo, ndk::ScopedAStatus::ok()};
 
+	wpas_drv_get_sta_mlo_info(wpa_s, &mlo);
 	for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
 		if (!(wpa_s->valid_links & BIT(i)))
 			continue;
@@ -2055,8 +2057,13 @@
 		// mapping by the AP, a default TID-to-link mapping is assumed
 		// unless an individual TID-to-link mapping is successfully
 		// negotiated.
-		link.tidsUplinkMap = 0xFF;
-		link.tidsDownlinkMap = 0xFF;
+		if (!mlo.default_map) {
+			link.tidsUplinkMap = mlo.links[i].t2lmap.uplink;
+			link.tidsDownlinkMap = mlo.links[i].t2lmap.downlink;
+		} else {
+			link.tidsUplinkMap = 0xFF;
+			link.tidsDownlinkMap = 0xFF;
+		}
 		linksInfo.links.push_back(link);
 	}
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a5d4d81..c843cb0 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2501,6 +2501,7 @@
 	{ FUNC(freq_list) },
 	{ INT_RANGE(ht, 0, 1) },
 	{ INT_RANGE(vht, 0, 1) },
+	{ INT_RANGE(he, 0, 1) },
 	{ INT_RANGE(ht40, -1, 1) },
 	{ INT_RANGE(max_oper_chwidth, CONF_OPER_CHWIDTH_USE_HT,
 		    CONF_OPER_CHWIDTH_80P80MHZ) },
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 898765c..df538e3 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -274,6 +274,13 @@
       </varlistentry>
 
       <varlistentry>
+	<term>macsec_linux</term>
+	<listitem>
+	  <para>MACsec Ethernet driver for Linux</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>roboswitch</term>
 	<listitem>
 	  <para>wpa_supplicant Broadcom switch driver</para>
@@ -281,6 +288,13 @@
       </varlistentry>
 
       <varlistentry>
+	<term>none</term>
+	<listitem>
+	  <para>no driver (RADIUS server/WPS ER only)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
 	<term>bsd</term>
 	<listitem>
 	  <para>BSD 802.11 support (Atheros, etc.).</para>
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 253f87d..b09d51d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -60,6 +60,10 @@
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
 					      int new_scan, int own_request);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
+#ifdef CONFIG_OWE
+static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			   const u8 **ret_ssid, size_t *ret_ssid_len);
+#endif /* CONFIG_OWE */
 
 
 int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
@@ -187,6 +191,7 @@
 					union wpa_event_data *data)
 {
 	struct wpa_ssid *ssid, *old_ssid;
+	struct wpa_bss *bss;
 	u8 drv_ssid[SSID_MAX_LEN];
 	size_t drv_ssid_len;
 	int res;
@@ -210,6 +215,14 @@
 			return 0; /* current profile still in use */
 
 #ifdef CONFIG_OWE
+		if (wpa_s->current_bss &&
+		    !(wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION)) {
+			const u8 *match_ssid;
+			size_t match_ssid_len;
+
+			owe_trans_ssid(wpa_s, wpa_s->current_bss,
+				       &match_ssid, &match_ssid_len);
+		}
 		if ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
 		    wpa_s->current_bss &&
 		    (wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION) &&
@@ -254,6 +267,7 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
 		"current AP");
+	bss = wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid);
 	if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
 		u8 wpa_ie[80];
 		size_t wpa_ie_len = sizeof(wpa_ie);
@@ -263,7 +277,7 @@
 		 * driver indicated the actual values used in the
 		 * (Re)Association Request frame. */
 		skip_default_rsne = data && data->assoc_info.req_ies;
-		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
 					      wpa_ie, &wpa_ie_len,
 					      skip_default_rsne) < 0)
 			wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites");
@@ -276,8 +290,6 @@
 	old_ssid = wpa_s->current_ssid;
 	wpa_s->current_ssid = ssid;
 
-	wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid);
-
 	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
 	wpa_supplicant_initiate_eapol(wpa_s);
 	if (old_ssid != wpa_s->current_ssid)
@@ -611,8 +623,7 @@
 #ifdef CONFIG_WEP
 	int wep_ok;
 #endif /* CONFIG_WEP */
-	bool is_6ghz_bss_or_mld = is_6ghz_freq(bss->freq) ||
-		!is_zero_ether_addr(bss->mld_addr);
+	bool is_6ghz_bss = is_6ghz_freq(bss->freq);
 
 	ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
 	if (ret >= 0)
@@ -627,10 +638,10 @@
 #endif /* CONFIG_WEP */
 
 	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (is_6ghz_bss_or_mld && !rsn_ie) {
+	if (is_6ghz_bss && !rsn_ie) {
 		if (debug_print)
 			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - 6 GHz/MLD BSS without RSNE");
+				"   skip - 6 GHz BSS without RSNE");
 		return 0;
 	}
 
@@ -648,8 +659,8 @@
 		if (!ie.has_group)
 			ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
 
-		if (is_6ghz_bss_or_mld) {
-			/* WEP and TKIP are not allowed on 6 GHz */
+		if (is_6ghz_bss || !is_zero_ether_addr(bss->mld_addr)) {
+			/* WEP and TKIP are not allowed on 6 GHz/MLD */
 			ie.pairwise_cipher &= ~(WPA_CIPHER_WEP40 |
 						WPA_CIPHER_WEP104 |
 						WPA_CIPHER_TKIP);
@@ -699,12 +710,12 @@
 			break;
 		}
 
-		if (is_6ghz_bss_or_mld) {
+		if (is_6ghz_bss) {
 			/* MFPC must be supported on 6 GHz */
 			if (!(ie.capabilities & WPA_CAPABILITY_MFPC)) {
 				if (debug_print)
 					wpa_dbg(wpa_s, MSG_DEBUG,
-						"   skip RSNE - 6 GHz/MLD without MFPC");
+						"   skip RSNE - 6 GHz without MFPC");
 				break;
 			}
 
@@ -744,10 +755,10 @@
 		return 1;
 	}
 
-	if (is_6ghz_bss_or_mld) {
+	if (is_6ghz_bss) {
 		if (debug_print)
 			wpa_dbg(wpa_s, MSG_DEBUG,
-				"   skip - 6 GHz/MLD BSS without matching RSNE");
+				"   skip - 6 GHz BSS without matching RSNE");
 		return 0;
 	}
 
@@ -1828,6 +1839,7 @@
 			   struct wpa_bss *selected,
 			   struct wpa_ssid *ssid)
 {
+#ifdef IEEE8021X_EAPOL
 	if ((eap_is_wps_pbc_enrollee(&ssid->eap) &&
 	     wpas_wps_partner_link_overlap_detect(wpa_s)) ||
 	    wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
@@ -1850,6 +1862,7 @@
 #endif /* CONFIG_WPS */
 		return -1;
 	}
+#endif /* IEEE8021X_EAPOL */
 
 	wpa_msg(wpa_s, MSG_DEBUG,
 		"Considering connect request: reassociate: %d  selected: "
@@ -3793,7 +3806,13 @@
 	wpas_fst_update_mb_assoc(wpa_s, data);
 
 #ifdef CONFIG_SME
-	os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
+	/*
+	 * Cache the current AP's BSSID (for non-MLO connection) or MLD address
+	 * (for MLO connection) as the previous BSSID for subsequent
+	 * reassociation requests handled by SME-in-wpa_supplicant.
+	 */
+	os_memcpy(wpa_s->sme.prev_bssid,
+		  wpa_s->valid_links ? wpa_s->ap_mld_addr : bssid, ETH_ALEN);
 	wpa_s->sme.prev_bssid_set = 1;
 	wpa_s->sme.last_unprot_disconnect.sec = 0;
 #endif /* CONFIG_SME */
@@ -3889,6 +3908,7 @@
 			 * EVENT_PORT_AUTHORIZED handler when the driver is done
 			 * with the 4-way handshake.
 			 */
+			wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
 			wpa_msg(wpa_s, MSG_INFO,
 				"ASSOC INFO: wait for driver port authorized indication");
 		}
@@ -5020,7 +5040,7 @@
 
 static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s->wpa_state == WPA_ASSOCIATED) {
+	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
 		eapol_sm_notify_portValid(wpa_s->eapol, true);
@@ -5382,6 +5402,99 @@
 }
 
 
+static const char * bitmap_to_str(u8 value, char *buf)
+{
+	char *pos = buf;
+	int i, k = 0;
+
+	for (i = 7; i >= 0; i--)
+		pos[k++] = (value & BIT(i)) ? '1' : '0';
+
+	pos[8] = '\0';
+	return pos;
+}
+
+
+static void wpas_tid_link_map(struct wpa_supplicant *wpa_s,
+			      struct tid_link_map_info *info)
+{
+	char map_info[1000], *pos, *end;
+	int res, i;
+
+	pos = map_info;
+	end = pos + sizeof(map_info);
+	res = os_snprintf(map_info, sizeof(map_info), "default=%d",
+			  info->default_map);
+	if (os_snprintf_error(end - pos, res))
+		return;
+	pos += res;
+
+	if (!info->default_map) {
+		for (i = 0; i < MAX_NUM_MLD_LINKS && end > pos; i++) {
+			char uplink_map_str[9];
+			char downlink_map_str[9];
+
+			if (!(info->valid_links & BIT(i)))
+				continue;
+
+			bitmap_to_str(info->t2lmap[i].uplink, uplink_map_str);
+			bitmap_to_str(info->t2lmap[i].downlink,
+				      downlink_map_str);
+
+			res = os_snprintf(pos, end - pos,
+					  " link_id=%d up_link=%s down_link=%s",
+					  i, uplink_map_str,
+					  downlink_map_str);
+			if (os_snprintf_error(end - pos, res))
+				return;
+			pos += res;
+		}
+	}
+
+	wpas_notify_mlo_info_change_reason(wpa_s, MLO_TID_TO_LINK_MAP);
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_T2LM_UPDATE "%s", map_info);
+}
+
+
+static void wpas_link_reconfig(struct wpa_supplicant *wpa_s)
+{
+	u8 bssid[ETH_ALEN];
+
+	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+		wpa_printf(MSG_ERROR, "LINK_RECONFIG: Failed to get BSSID");
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		return;
+	}
+
+	if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+		os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
+		wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid);
+		wpas_notify_bssid_changed(wpa_s);
+	}
+
+	if (wpa_drv_get_mlo_info(wpa_s) < 0) {
+		wpa_printf(MSG_ERROR,
+			   "LINK_RECONFIG: Failed to get MLO connection info");
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		return;
+	}
+
+	if (wpa_sm_set_ml_info(wpa_s)) {
+		wpa_printf(MSG_ERROR,
+			   "LINK_RECONFIG: Failed to set MLO connection info to wpa_sm");
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		return;
+	}
+
+	wpas_notify_mlo_info_change_reason(wpa_s, MLO_LINK_RECONFIG_AP_REMOVAL);
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_LINK_RECONFIG "valid_links=0x%x",
+		wpa_s->valid_links);
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -5481,6 +5594,9 @@
 		wpas_event_deauth(wpa_s,
 				  data ? &data->deauth_info : NULL);
 		break;
+	case EVENT_LINK_RECONFIG:
+		wpas_link_reconfig(wpa_s);
+		break;
 	case EVENT_MICHAEL_MIC_FAILURE:
 		wpa_supplicant_event_michael_mic_failure(wpa_s, data);
 		break;
@@ -6291,6 +6407,10 @@
 		wpas_dpp_tx_wait_expire(wpa_s);
 #endif /* CONFIG_DPP */
 		break;
+	case EVENT_TID_LINK_MAP:
+		if (data)
+			wpas_tid_link_map(wpa_s, &data->t2l_map_info);
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index da6d9db..c9e14d5 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -771,7 +771,7 @@
 #ifdef CONFIG_IEEE80211AC
 	copy_sta_vht_capab(data, sta, elems->vht_capabilities);
 	copy_sta_vht_oper(data, sta, elems->vht_operation);
-	set_sta_vht_opmode(data, sta, elems->vht_opmode_notif);
+	set_sta_vht_opmode(data, sta, elems->opmode_notif);
 #endif /* CONFIG_IEEE80211AC */
 
 #ifdef CONFIG_IEEE80211AX
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 89a0389..c6e2dbe 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -154,6 +154,16 @@
 }
 
 
+void wpas_notify_mlo_info_change_reason(struct wpa_supplicant *wpa_s,
+					enum mlo_info_change_reason reason)
+{
+	if (wpa_s->p2p_mgmt)
+		return;
+
+	wpas_aidl_notify_mlo_info_change_reason(wpa_s, reason);
+}
+
+
 void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->p2p_mgmt)
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index bc2bd64..c41aa6e 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -229,5 +229,7 @@
 void wpas_notify_signal_change(struct wpa_supplicant *wpa_s);
 void wpas_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
 		unsigned int num_scs_resp, int **scs_resp);
+void wpas_notify_mlo_info_change_reason(struct wpa_supplicant *wpa_s,
+					enum mlo_info_change_reason reason);
 
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index ea4023c..8068f1e 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -378,10 +378,12 @@
 }
 
 
-static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			    struct wpa_ssid *ssid)
 {
 	struct wpabuf *mlbuf;
-	const u8 *rnr_ie, *pos;
+	const u8 *rnr_ie, *pos, *rsn_ie;
+	struct wpa_ie_data ie;
 	u8 ml_ie_len, rnr_ie_len;
 	const struct ieee80211_eht_ml *eht_ml;
 	const struct eht_ml_basic_common_info *ml_basic_common_info;
@@ -402,6 +404,26 @@
 		return false;
 	}
 
+	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	if (!rsn_ie || wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element");
+		goto out;
+	}
+
+	if (!(ie.capabilities & WPA_CAPABILITY_MFPC) ||
+	    wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"MLD: No management frame protection");
+		goto out;
+	}
+
+	ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_PSK_SHA256);
+	if (!(ie.key_mgmt & ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No valid key management");
+		goto out;
+	}
+
 	ml_ie_len = wpabuf_len(mlbuf);
 
 	/* control + common info len + MLD address + MLD link information */
@@ -525,20 +547,28 @@
 {
 	struct ieee802_11_elems elems;
 	const u8 *mld_addr;
+	u16 status_code = data->auth.status_code;
 
 	if (!wpa_s->valid_links)
 		return;
 
 	if (ieee802_11_parse_elems(data->auth.ies + ie_offset,
 				   data->auth.ies_len - ie_offset,
-				   &elems, 0) != ParseOK) {
+				   &elems, 0) == ParseFailed) {
 		wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements");
 		goto out;
 	}
 
 	if (!elems.basic_mle || !elems.basic_mle_len) {
 		wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication");
-		goto out;
+		if (status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ ||
+		    status_code == WLAN_STATUS_SUCCESS ||
+		    status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+		    status_code == WLAN_STATUS_SAE_PK)
+			goto out;
+		/* Accept missing Multi-Link element in failed authentication
+		 * cases. */
+		return;
 	}
 
 	mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
@@ -604,7 +634,7 @@
 	params.ssid_len = bss->ssid_len;
 	params.p2p = ssid->p2p_group;
 
-	if (wpas_ml_element(wpa_s, bss)) {
+	if (wpas_ml_element(wpa_s, bss, ssid)) {
 		wpa_printf(MSG_DEBUG, "MLD: In authentication");
 		params.mld = true;
 		params.mld_link_id = wpa_s->mlo_assoc_link_id;
@@ -1596,20 +1626,28 @@
 
 
 static int sme_external_ml_auth(struct wpa_supplicant *wpa_s,
-				const u8 *data, size_t len, int ie_offset)
+				const u8 *data, size_t len, int ie_offset,
+				u16 status_code)
 {
 	struct ieee802_11_elems elems;
 	const u8 *mld_addr;
 
 	if (ieee802_11_parse_elems(data + ie_offset, len - ie_offset,
-				   &elems, 0) != ParseOK) {
+				   &elems, 0) == ParseFailed) {
 		wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements");
 		return -1;
 	}
 
 	if (!elems.basic_mle || !elems.basic_mle_len) {
 		wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication");
-		return -1;
+		if (status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ ||
+		    status_code == WLAN_STATUS_SUCCESS ||
+		    status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+		    status_code == WLAN_STATUS_SAE_PK)
+			return -1;
+		/* Accept missing Multi-Link element in failed authentication
+		 * cases. */
+		return 0;
 	}
 
 	mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
@@ -1623,7 +1661,8 @@
 	if (os_memcmp(wpa_s->sme.ext_auth_ap_mld_addr, mld_addr, ETH_ALEN) !=
 	    0) {
 		wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected "
-			   MACSTR ")", MAC2STR(wpa_s->ap_mld_addr));
+			   MACSTR ")",
+			   MAC2STR(wpa_s->sme.ext_auth_ap_mld_addr));
 		return -1;
 	}
 
@@ -1714,7 +1753,8 @@
 						wpa_s->current_ssid, 2);
 		} else {
 			if (wpa_s->sme.ext_ml_auth &&
-			    sme_external_ml_auth(wpa_s, data, len, *ie_offset))
+			    sme_external_ml_auth(wpa_s, data, len, *ie_offset,
+						 status_code))
 				return -1;
 
 			sme_external_auth_send_sae_commit(
@@ -1741,7 +1781,8 @@
 						wpa_s->current_ssid, 1);
 		} else {
 			if (wpa_s->sme.ext_ml_auth &&
-			    sme_external_ml_auth(wpa_s, data, len, *ie_offset))
+			    sme_external_ml_auth(wpa_s, data, len, *ie_offset,
+						 status_code))
 				return -1;
 
 			sme_external_auth_send_sae_commit(
@@ -1840,7 +1881,8 @@
 						wpa_s->current_ssid, 0);
 		} else {
 			if (wpa_s->sme.ext_ml_auth &&
-			    sme_external_ml_auth(wpa_s, data, len, *ie_offset))
+			    sme_external_ml_auth(wpa_s, data, len, *ie_offset,
+						 status_code))
 				return -1;
 
 			sme_external_auth_send_sae_confirm(wpa_s, sa);
@@ -1856,7 +1898,8 @@
 				      ie_offset) < 0)
 			return -1;
 		if (external && wpa_s->sme.ext_ml_auth &&
-		    sme_external_ml_auth(wpa_s, data, len, *ie_offset))
+		    sme_external_ml_auth(wpa_s, data, len, *ie_offset,
+					 status_code))
 			return -1;
 
 		wpa_s->sme.sae.state = SAE_ACCEPTED;
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index f808ac4..effc7b3 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1427,7 +1427,7 @@
 	"bssid_accept", "psk", "proto", "key_mgmt",
 	"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
 	"freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1",
-	"vht_center_freq2", "ht", "edmg",
+	"vht_center_freq2", "ht", "edmg", "he",
 #ifdef IEEE8021X_EAPOL
 	"eap", "identity", "anonymous_identity", "password", "ca_cert",
 	"ca_path", "client_cert", "private_key", "private_key_passwd",
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 1344ef6..a3645d1 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1587,6 +1587,7 @@
 	int sel, proto;
 	enum sae_pwe sae_pwe;
 	const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
+	bool wmm;
 
 	if (bss) {
 		bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
@@ -1983,6 +1984,22 @@
 		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
 	}
 
+	/* Mark WMM enabled for any HT/VHT/HE/EHT association to get more
+	 * appropriate advertisement of the supported number of PTKSA receive
+	 * counters. In theory, this could be based on a driver capability, but
+	 * in practice all cases using WMM support at least eight replay
+	 * counters, so use a hardcoded value for now since there is no explicit
+	 * driver capability indication for this.
+	 *
+	 * In addition, claim WMM to be enabled if the AP supports it since it
+	 * is far more likely for any current device to support WMM. */
+	wmm = wpa_s->connection_set &&
+		(wpa_s->connection_ht || wpa_s->connection_vht ||
+		 wpa_s->connection_he || wpa_s->connection_eht);
+	if (!wmm && bss)
+		wmm = wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm);
+
 	if (!skip_default_rsne) {
 		if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
 						    wpa_ie_len)) {
@@ -3975,7 +3992,16 @@
 		return;
 	}
 
-	os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
+	/*
+	 * Set the current AP's BSSID (for non-MLO connection) or MLD address
+	 * (for MLO connection) as the previous BSSID for reassociation requests
+	 * handled by SME-in-driver. If wpa_supplicant is in disconnected state,
+	 * prev_bssid will be zero as both wpa_s->valid_links and wpa_s->bssid
+	 * will be zero.
+	 */
+	os_memcpy(prev_bssid,
+		  wpa_s->valid_links ? wpa_s->ap_mld_addr : wpa_s->bssid,
+		  ETH_ALEN);
 	os_memset(&params, 0, sizeof(params));
 	wpa_s->reassociate = 0;
 	wpa_s->eap_expected_failure = 0;
@@ -4829,7 +4855,8 @@
 		wpa_s->current_ssid = ssid;
 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 		wpa_s->connect_without_scan =
-			(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
+			(ssid->mode == WPAS_MODE_MESH ||
+			 ssid->mode == WPAS_MODE_AP) ? ssid : NULL;
 
 		/*
 		 * Don't optimize next scan freqs since a new ESS has been
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 8753fba..a8abf9a 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1378,6 +1378,13 @@
 #	 * 0 = do not use cryptobinding (default)
 #	 * 1 = use cryptobinding if server supports it
 #	 * 2 = require cryptobinding
+#	'phase2_auth' option can be used to control Phase 2 (i.e., within TLS
+#	tunnel) behavior for PEAP:
+#	 * 0 = do not require Phase 2 authentication
+#	 * 1 = require Phase 2 authentication when client certificate
+#	   (private_key/client_cert) is not used and TLS session resumption was
+#	   not used (default)
+#	 * 2 = require Phase 2 authentication in all cases
 #	EAP-WSC (WPS) uses following options: pin=<Device Password> or
 #	pbc=1.
 #
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index cec26c4..6a2fbd3 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -9,3 +9,4 @@
 sae_pwe=2
 p2p_optimize_listen_chan=1
 wowlan_disconnect_on_deinit=1
+sae_pmkid_in_assoc=1