Эх сурвалжийг харах

Merge commit '9b47fb7c5eb08266b788a067c46393ca31eeae4c' into wlan-cld3.driver.lnx.2.0.r112-rel

Change-Id: Ie083a564567b568adfcbce5eb0dd8b73326f0da7
V S Ganga VaraPrasad (VARA) Adabala 1 жил өмнө
parent
commit
b31d8feb1f
84 өөрчлөгдсөн 2302 нэмэгдсэн , 531 устгасан
  1. 5 0
      Kbuild
  2. 4 0
      components/action_oui/core/src/wlan_action_oui_main.c
  3. 2 2
      components/action_oui/core/src/wlan_action_oui_parse.c
  4. 31 0
      components/action_oui/dispatcher/inc/wlan_action_oui_cfg.h
  5. 3 0
      components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h
  6. 40 9
      components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c
  7. 18 9
      components/cmn_services/logging/inc/wlan_connectivity_logging.h
  8. 75 10
      components/cmn_services/logging/src/wlan_connectivity_logging.c
  9. 10 10
      components/cmn_services/policy_mgr/inc/cfg_policy_mgr.h
  10. 18 28
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  11. 10 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c
  12. 11 1
      components/coex/core/inc/wlan_coex_main.h
  13. 42 1
      components/coex/core/src/wlan_coex_main.c
  14. 23 1
      components/coex/dispatcher/inc/wlan_coex_tgt_api.h
  15. 19 0
      components/coex/dispatcher/inc/wlan_coex_ucfg_api.h
  16. 45 1
      components/coex/dispatcher/src/wlan_coex_tgt_api.c
  17. 8 0
      components/coex/dispatcher/src/wlan_coex_ucfg_api.c
  18. 12 0
      components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h
  19. 17 0
      components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
  20. 116 96
      components/dp/core/src/wlan_dp_rx_thread.c
  21. 17 0
      components/mlme/core/inc/wlan_mlme_main.h
  22. 32 0
      components/mlme/core/src/wlan_mlme_main.c
  23. 27 0
      components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c
  24. 9 7
      components/mlme/dispatcher/inc/cfg_mlme_fe_wlm.h
  25. 25 1
      components/mlme/dispatcher/inc/cfg_mlme_he_caps.h
  26. 4 2
      components/mlme/dispatcher/inc/wlan_mlme_api.h
  27. 40 2
      components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
  28. 11 0
      components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
  29. 164 3
      components/mlme/dispatcher/src/wlan_mlme_api.c
  30. 18 0
      components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
  31. 6 3
      components/p2p/core/src/wlan_p2p_off_chan_tx.c
  32. 19 0
      components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h
  33. 19 0
      components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c
  34. 17 7
      components/pmo/core/src/wlan_pmo_ns.c
  35. 4 1
      components/pmo/core/src/wlan_pmo_suspend_resume.c
  36. 54 0
      components/target_if/coex/src/target_if_coex.c
  37. 28 0
      components/target_if/cp_stats/src/target_if_mc_cp_stats.c
  38. 52 33
      components/tdls/core/src/wlan_tdls_main.c
  39. 19 0
      components/tdls/core/src/wlan_tdls_main.h
  40. 65 19
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c
  41. 55 34
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c
  42. 9 0
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h
  43. 2 3
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c
  44. 17 0
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h
  45. 5 0
      components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c
  46. 3 0
      components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c
  47. 40 23
      components/wmi/src/wmi_unified_roam_tlv.c
  48. 4 0
      configs/config_to_feature.h
  49. 2 2
      configs/default_defconfig
  50. 2 0
      configs/kiwi_v2_defconfig
  51. 2 0
      core/cds/src/cds_api.c
  52. 3 0
      core/hdd/inc/wlan_hdd_main.h
  53. 16 0
      core/hdd/inc/wlan_hdd_power.h
  54. 89 36
      core/hdd/src/wlan_hdd_cfg.c
  55. 76 41
      core/hdd/src/wlan_hdd_cfg80211.c
  56. 65 1
      core/hdd/src/wlan_hdd_cm_connect.c
  57. 21 12
      core/hdd/src/wlan_hdd_hostapd.c
  58. 198 10
      core/hdd/src/wlan_hdd_main.c
  59. 2 0
      core/hdd/src/wlan_hdd_nan_datapath.c
  60. 37 0
      core/hdd/src/wlan_hdd_p2p.c
  61. 1 10
      core/hdd/src/wlan_hdd_power.c
  62. 4 4
      core/hdd/src/wlan_hdd_stats.c
  63. 20 0
      core/hdd/src/wlan_hdd_sysfs.c
  64. 256 0
      core/hdd/src/wlan_hdd_tx_power.c
  65. 29 0
      core/hdd/src/wlan_hdd_tx_power.h
  66. 3 3
      core/mac/inc/qwlan_version.h
  67. 1 1
      core/mac/src/pe/lim/lim_ft.c
  68. 6 1
      core/mac/src/pe/lim/lim_mlo.c
  69. 9 6
      core/mac/src/pe/lim/lim_process_message_queue.c
  70. 15 11
      core/mac/src/pe/lim/lim_process_sme_req_messages.c
  71. 4 0
      core/mac/src/pe/lim/lim_process_tdls.c
  72. 21 2
      core/mac/src/pe/lim/lim_send_management_frames.c
  73. 7 0
      core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
  74. 12 6
      core/mac/src/pe/lim/lim_utils.c
  75. 6 5
      core/mac/src/pe/sch/sch_beacon_process.c
  76. 10 4
      core/mac/src/sys/legacy/src/utils/src/parser_api.c
  77. 13 0
      core/sap/inc/sap_api.h
  78. 3 3
      core/sap/src/sap_api_link_cntl.c
  79. 7 54
      core/sap/src/sap_fsm.c
  80. 47 9
      core/sme/src/common/sme_api.c
  81. 1 0
      core/wma/inc/wma_api.h
  82. 8 2
      core/wma/src/wma_data.c
  83. 2 2
      core/wma/src/wma_main.c
  84. 30 0
      core/wma/src/wma_power.c

+ 5 - 0
Kbuild

@@ -4919,6 +4919,11 @@ ifeq ($(CONFIG_DP_HW_TX_DELAY_STATS_ENABLE), y)
 ccflags-y += -DHW_TX_DELAY_STATS_ENABLE
 endif
 
+# Config MAX SAP interface number
+ifdef CONFIG_QDF_MAX_NO_OF_SAP_MODE
+ccflags-y += -DQDF_MAX_NO_OF_SAP_MODE=$(CONFIG_QDF_MAX_NO_OF_SAP_MODE)
+endif
+
 #Flags to enable/disable Dynamic WLAN interface control feature
 ifeq ($(CONFIG_CNSS_HW_SECURE_DISABLE), y)
 ccflags-y += -DFEATURE_CNSS_HW_SECURE_DISABLE

+ 4 - 0
components/action_oui/core/src/wlan_action_oui_main.c

@@ -198,6 +198,10 @@ static void action_oui_load_config(struct action_oui_psoc_priv *psoc_priv)
 		      cfg_get(psoc,
 			      CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN),
 		      ACTION_OUI_MAX_STR_LEN);
+	qdf_str_lcopy(psoc_priv->action_oui_str
+			[ACTION_OUI_RESTRICT_MAX_MLO_LINKS],
+		      cfg_get(psoc, CFG_ACTION_OUI_RESTRICT_MAX_MLO_LINKS),
+		      ACTION_OUI_MAX_STR_LEN);
 	qdf_str_lcopy(psoc_priv->action_oui_str
 			[ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ],
 		      cfg_get(psoc, CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ),

+ 2 - 2
components/action_oui/core/src/wlan_action_oui_parse.c

@@ -172,8 +172,8 @@ validate_and_convert_data_length(uint8_t *token,
 	}
 
 	if ((uint32_t)len > ACTION_OUI_MAX_DATA_LENGTH) {
-		action_oui_err("action OUI data len is more than %u",
-			ACTION_OUI_MAX_DATA_LENGTH);
+		action_oui_err("action OUI data len %d is more than %u",
+			       len, ACTION_OUI_MAX_DATA_LENGTH);
 		return false;
 	}
 

+ 31 - 0
components/action_oui/dispatcher/inc/wlan_action_oui_cfg.h

@@ -844,6 +844,36 @@
 	"", \
 	"Used to send SMPS frame along with OMN for specified APs")
 
+/*
+ * <ini>
+ * gActionOUIRestrictMaxMLOLinks - Used to downgrade 3 link to 2 link ML
+ * connection for specific AP build version.
+ *
+ * Sample OUIs: (All values in Hex)
+ * OUI 3 : 8CFDF0
+ *   OUI data Len : 13
+ *   OUI Data : 040000494c510302097201cb17000009110000
+ *   OUI data Mask: FFFFE0 - 1111 1111 1111 1111 1110 0000
+ *   Info Mask : 01 - only OUI present in Info mask
+ *
+ * gActionOUIRestrictMaxMLOLinks=8CFDF0 13 040000494c510c00203000cb17000009110000 FFFFE0 01
+ * Refer to gEnableActionOUI for more detail about the format.
+ *
+ * Related: gEnableActionOUI
+ *
+ * Supported Feature: Action OUIs
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_ACTION_OUI_RESTRICT_MAX_MLO_LINKS CFG_INI_STRING( \
+	"gActionOUIRestrictMaxMLOLinks", \
+	0, \
+	ACTION_OUI_MAX_STR_LEN, \
+	"8CFDF0 13 040000494c510302097201cb17000009110000 FFFFE0 01", \
+	"To restrict matching OUI APs to two link connection at max")
+
 #define CFG_ACTION_OUI \
 	CFG(CFG_ACTION_OUI_CCKM_1X1) \
 	CFG(CFG_ACTION_OUI_CONNECT_1X1) \
@@ -861,6 +891,7 @@
 	CFG(CFG_ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE) \
 	CFG(CFG_ACTION_OUI_ENABLE_CTS2SELF) \
 	CFG(CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL) \
+	CFG(CFG_ACTION_OUI_RESTRICT_MAX_MLO_LINKS) \
 	CFG(CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN) \
 	CFG(CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ) \
 	CFG(CFG_ACTION_OUI_DISABLE_BFORMEE) \

+ 3 - 0
components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h

@@ -125,6 +125,8 @@
  * @ACTION_OUI_DISABLE_BFORMEE: disable SU/MU beam formee capability for
  * specified AP
  * @ACTION_OUI_ENABLE_CTS2SELF: enable cts to self for specified AP's
+ * @ACTION_OUI_RESTRICT_MAX_MLO_LINKS: Downgrade MLO if particular AP
+ *                                     build present.
  * @ACTION_OUI_MAXIMUM_ID: maximum number of action oui types
  */
 enum action_oui_id {
@@ -150,6 +152,7 @@ enum action_oui_id {
 	ACTION_OUI_DISABLE_BFORMEE,
 	ACTION_OUI_DISABLE_AGGRESSIVE_EDCA,
 	ACTION_OUI_ENABLE_CTS2SELF,
+	ACTION_OUI_RESTRICT_MAX_MLO_LINKS,
 	ACTION_OUI_MAXIMUM_ID
 };
 

+ 40 - 9
components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c

@@ -38,6 +38,8 @@
 #include "wlan_mlo_mgr_roam.h"
 #include "wlan_mlo_mgr_sta.h"
 #include "wlan_mlo_mgr_link_switch.h"
+#include <wlan_action_oui_main.h>
+
 
 #ifdef WLAN_FEATURE_11BE_MLO
 static inline bool
@@ -799,22 +801,51 @@ static void if_mgr_update_candidate(struct wlan_objmgr_psoc *psoc,
 				    struct validate_bss_data *candidate_info)
 {
 	struct scan_cache_entry *scan_entry = candidate_info->scan_entry;
+	struct action_oui_search_attr attr;
+	int8_t i, allowed_partner_links = 0;
+	uint8_t mlo_support_link_num;
 
 	if (!(scan_entry->ie_list.multi_link_bv || scan_entry->ie_list.ehtcap ||
 	      scan_entry->ie_list.ehtop))
 		return;
 
-	if (mlme_get_bss_11be_allowed(psoc, &candidate_info->peer_addr,
-				      util_scan_entry_ie_data(scan_entry),
-				      util_scan_entry_ie_len(scan_entry)) &&
-	    (!wlan_vdev_mlme_get_user_dis_eht_flag(vdev)))
+	attr.ie_data = util_scan_entry_ie_data(scan_entry);
+	attr.ie_length = util_scan_entry_ie_len(scan_entry);
+
+	if (!mlme_get_bss_11be_allowed(psoc, &candidate_info->peer_addr,
+				       attr.ie_data, attr.ie_length) ||
+	    wlan_vdev_mlme_get_user_dis_eht_flag(vdev)) {
+		scan_entry->ie_list.multi_link_bv = NULL;
+		scan_entry->ie_list.ehtcap = NULL;
+		scan_entry->ie_list.ehtop = NULL;
+		qdf_mem_zero(&scan_entry->ml_info, sizeof(scan_entry->ml_info));
+		candidate_info->is_mlo = false;
+		return;
+	}
+
+	mlo_support_link_num = wlan_mlme_get_sta_mlo_conn_max_num(psoc);
+
+	if (mlo_support_link_num <= WLAN_MAX_ML_DEFAULT_LINK)
 		return;
 
-	scan_entry->ie_list.multi_link_bv = NULL;
-	scan_entry->ie_list.ehtcap = NULL;
-	scan_entry->ie_list.ehtop = NULL;
-	qdf_mem_zero(&scan_entry->ml_info, sizeof(scan_entry->ml_info));
-	candidate_info->is_mlo = false;
+	if (!wlan_action_oui_search(psoc, &attr,
+				    ACTION_OUI_RESTRICT_MAX_MLO_LINKS))
+		return;
+
+	for (i = 0; i < scan_entry->ml_info.num_links; i++) {
+		if (i < WLAN_MAX_ML_DEFAULT_LINK - 1) {
+			allowed_partner_links++;
+			continue;
+		}
+
+		scan_entry->ml_info.link_info[i].is_valid_link = false;
+	}
+
+	if (allowed_partner_links != scan_entry->ml_info.num_links)
+		ifmgr_nofl_debug("Downgrade " QDF_MAC_ADDR_FMT " partner links from %d to %d",
+				 QDF_MAC_ADDR_REF(scan_entry->ml_info.mld_mac_addr.bytes),
+				 scan_entry->ml_info.num_links,
+				 allowed_partner_links);
 }
 #else
 static inline uint32_t

+ 18 - 9
components/cmn_services/logging/inc/wlan_connectivity_logging.h

@@ -481,24 +481,28 @@ struct wlan_diag_mlo_t2lm_teardown {
 } qdf_packed;
 
 #define DIAG_MLO_LINK_STATUS_VERSION 1
+#define DIAG_MLO_LINK_STATUS_VERSION_2 2
 /**
  * struct wlan_diag_mlo_link_status - MLO Link status diag event structure
  * @diag_cmn: Common diag info
  * @version: structure version
- * @active_link: List of current active links. BIT 0: 2.4GHz BIT 1: 5GHz
- * BIT 2: 6GHz
- * @prev_active_link: List of inactive links. BIT 0: 2.4GHz BIT 1: 5GHz
- * BIT 2: 6GHz
+ * @active_link: List of current active links. BIT 0: 2.4 GHz BIT 1: 5 GHz
+ * BIT 2: 6 GHz
+ * @prev_active_link: List of previous active links. BIT 0: 2.4 G Hz
+ * BIT 1: 5 GHz BIT 2: 6 GHz
+ * @associated_links: Links associated in the current connection.
+ * BIT 0: 2.4 GHz BIT 1: 5 GHz BIT 2: 6 GHz
+ * @reserved: Reserved field
  * @reason: Reason for changed link status. Refer
  * enum wlan_diag_mlo_link_switch_reason
- * @reserved: Reserved field
  */
 struct wlan_diag_mlo_link_status {
 	struct wlan_connectivity_log_diag_cmn diag_cmn;
 	uint8_t version;
 	uint8_t active_link:5;
 	uint8_t prev_active_link:5;
-	uint8_t reserved:6;
+	uint8_t associated_links:5;
+	uint8_t reserved:1;
 	uint8_t reason;
 } qdf_packed;
 
@@ -1439,11 +1443,13 @@ wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc,
 /**
  * wlan_connectivity_connecting_event() - API to log connecting event
  * @vdev: vdev pointer
+ * @con_req: Connection request parameter
  *
  * Return: None
  */
 void
-wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev);
+wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_cm_connect_req *con_req);
 
 #elif defined(WLAN_FEATURE_CONNECTIVITY_LOGGING)
 /**
@@ -1517,11 +1523,13 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 /**
  * wlan_connectivity_connecting_event() - API to log connecting event
  * @vdev: vdev pointer
+ * @con_req: Connection request parameter
  *
  * Return: None
  */
 void
-wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev);
+wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_cm_connect_req *con_req);
 
 /**
  * wlan_populate_vsie() - Populate VSIE field for logging
@@ -1662,7 +1670,8 @@ wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev)
 }
 
 static inline void
-wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev)
+wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_cm_connect_req *con_req)
 {
 }
 #endif

+ 75 - 10
components/cmn_services/logging/src/wlan_connectivity_logging.c

@@ -892,7 +892,7 @@ wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	}
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_STA_INFO);
-	wlan_connectivity_connecting_event(vdev);
+	wlan_connectivity_connecting_event(vdev, NULL);
 out:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
 }
@@ -1023,18 +1023,27 @@ out:
 }
 
 void
-wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev)
+wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_cm_connect_req *con_req)
 {
 	QDF_STATUS status;
 	struct wlan_cm_connect_req req;
 
 	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_connect);
 
-	status = wlan_cm_get_active_connect_req_param(vdev, &req);
-	if (QDF_IS_STATUS_ERROR(status)) {
-		logging_err("vdev: %d failed to get active cmd request",
-			    wlan_vdev_get_id(vdev));
+	if (!wlan_cm_is_first_candidate_connect_attempt(vdev))
 		return;
+
+	/* for candidate not found case*/
+	if (con_req) {
+		req = *con_req;
+	} else {
+		status = wlan_cm_get_active_connect_req_param(vdev, &req);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			logging_err("vdev: %d failed to get active cmd request",
+				    wlan_vdev_get_id(vdev));
+			return;
+		}
 	}
 
 	wlan_diag_event.version = DIAG_CONN_VERSION;
@@ -1091,7 +1100,7 @@ wlan_convert_link_id_to_diag_band(struct qdf_mac_addr *peer_mld,
 	mlpeer = wlan_mlo_get_mlpeer_by_peer_mladdr(peer_mld, &mldev);
 	if (!mlpeer) {
 		logging_err("ml peer not found");
-		goto out;
+		return 0;
 	}
 
 	for (i = 0; i < MAX_MLO_LINK_ID; i++) {
@@ -1099,7 +1108,7 @@ wlan_convert_link_id_to_diag_band(struct qdf_mac_addr *peer_mld,
 			link_info = mlo_mgr_get_ap_link_by_link_id(mldev, i);
 			if (!link_info) {
 				logging_err("link: %d info does not exist", i);
-				continue;
+				return 0;
 			}
 
 			freq = link_info->link_chan_info->ch_freq;
@@ -1111,29 +1120,85 @@ wlan_convert_link_id_to_diag_band(struct qdf_mac_addr *peer_mld,
 		}
 	}
 
-out:
+	return band_bitmap;
+}
+
+static uint8_t
+wlan_get_supported_link_band_bitmap(struct mlo_link_switch_context *link_ctx)
+{
+	uint8_t band_bitmap = 0, i = 0;
+	struct mlo_link_info link_info;
+	struct wlan_channel *chan_info;
+	enum wlan_diag_wifi_band band;
+
+	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
+		link_info = link_ctx->links_info[i];
+
+		chan_info = link_info.link_chan_info;
+		if (!chan_info)
+			continue;
+
+		band = wlan_convert_freq_to_diag_band(chan_info->ch_freq);
+		if (band == WLAN_INVALID_BAND)
+			continue;
+
+		band_bitmap |= BIT(band - 1);
+	}
+
 	return band_bitmap;
 }
 
 void wlan_connectivity_mld_link_status_event(struct wlan_objmgr_psoc *psoc,
 					     struct mlo_link_switch_params *src)
 {
+	struct wlan_mlo_peer_context *ml_peer = NULL;
+	struct wlan_mlo_dev_context *mld_ctx = NULL;
+
 	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
 				 struct wlan_diag_mlo_link_status);
 
 	qdf_mem_zero(&wlan_diag_event,
 		     sizeof(struct wlan_diag_mlo_link_status));
 
+	ml_peer = wlan_mlo_get_mlpeer_by_peer_mladdr(&src->mld_addr, &mld_ctx);
+
+	if (!mld_ctx) {
+		logging_err("mlo dev ctx for mld_mac: "
+			    QDF_MAC_ADDR_FMT
+			    " not found",
+			    QDF_MAC_ADDR_REF(src->mld_addr.bytes));
+		return;
+	}
+
 	wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us();
 	wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get());
-	wlan_diag_event.version = DIAG_MLO_LINK_STATUS_VERSION;
+	wlan_diag_event.version = DIAG_MLO_LINK_STATUS_VERSION_2;
 
 	wlan_diag_event.active_link =
 		wlan_convert_link_id_to_diag_band(&src->mld_addr,
 						  src->active_link_bitmap);
+	if (!wlan_diag_event.active_link)
+		return;
 	wlan_diag_event.prev_active_link =
 		wlan_convert_link_id_to_diag_band(&src->mld_addr,
 						  src->prev_link_bitmap);
+	if (!wlan_diag_event.prev_active_link)
+		return;
+
+	if (!mld_ctx->link_ctx) {
+		logging_err("link ctx for mld_mac: "
+			    QDF_MAC_ADDR_FMT
+			    " not found",
+			    QDF_MAC_ADDR_REF(src->mld_addr.bytes));
+		return;
+	}
+
+	wlan_diag_event.associated_links =
+			wlan_get_supported_link_band_bitmap(mld_ctx->link_ctx);
+
+	if (!wlan_diag_event.associated_links)
+		return;
+
 	wlan_diag_event.reason = src->reason_code;
 	/*
 	 * FW timestamp received from FW in milliseconds and to be sent to

+ 10 - 10
components/cmn_services/policy_mgr/inc/cfg_policy_mgr.h

@@ -25,20 +25,20 @@
  * <ini>
  * gWlanMccToSccSwitchMode - Control SAP channel.
  * @Min: 0
- * @Max: 5
+ * @Max: 6
  * @Default: 0
  *
  * This ini is used to override SAP channel.
  * If gWlanMccToSccSwitchMode = 0: disabled.
- * If gWlanMccToSccSwitchMode = 1: Enable switch.
- * If gWlainMccToSccSwitchMode = 2: Force switch with SAP restart.
- * If gWlainMccToSccSwitchMode = 3: Force switch without SAP restart.
- * If gWlainMccToSccSwitchMode = 4: Switch using
- *					fav channel(s)without SAP restart.
- * If gWlainMccToSccSwitchMode = 5: Force switch without SAP restart.MCC allowed
- *					in exceptional cases.
- * If gWlainMccToSccSwitchMode = 6: Force Switch without SAP restart only in
-					user preferred band.
+ * If gWlanMccToSccSwitchMode = 1: deprecated, overwritten to 3 in driver
+ * If gWlanMccToSccSwitchMode = 2: deprecated, overwritten to 3 in driver
+ * If gWlanMccToSccSwitchMode = 3: Force switch without SAP restart.
+ * If gWlanMccToSccSwitchMode = 4: Switch using
+ *                                 fav channel(s)without SAP restart.
+ * If gWlanMccToSccSwitchMode = 5: Force switch without SAP restart.MCC allowed
+ *                                 in exceptional cases.
+ * If gWlanMccToSccSwitchMode = 6: Force Switch without SAP restart only in
+ *                                 user preferred band.
  * Related: None.
  *
  * Supported Feature: Concurrency

+ 18 - 28
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -4487,9 +4487,24 @@ policy_mgr_update_dynamic_inactive_bitmap(
 		inactive_links |= candidate_inactive_links;
 	}
 
-	/* 3. If there are links inactive from fw event's
+	/* 3. If standby link is present (may not be force inactive),
+	 * select the standby link as dynamic inactive link.
+	 */
+	if (num < force_inactive_num &&
+	    num < QDF_ARRAY_SIZE(link_ids)) {
+		candidate_inactive_links =
+			force_inactive_num_bitmap &
+			standby_links;
+		num += ml_nlink_convert_link_bitmap_to_ids(
+				candidate_inactive_links,
+				QDF_ARRAY_SIZE(link_ids) - num,
+				&link_ids[num]);
+		inactive_links |= candidate_inactive_links;
+	}
+
+	/* 4. If there are links inactive from fw event's
 	 * curr_inactive_linkid_bitmap, select the current inactive
-	 * links as third option. note: those link may not be force
+	 * links as last option. note: those link may not be force
 	 * inactive.
 	 */
 	if (num < force_inactive_num &&
@@ -7150,27 +7165,6 @@ policy_mgr_is_emlsr_sta_concurrency_present(struct wlan_objmgr_psoc *psoc)
 	return false;
 }
 
-static bool
-policy_mgr_is_ml_sta_concurrency_present(struct wlan_objmgr_psoc *psoc)
-{
-	uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0;
-	uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
-	qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
-	uint8_t num_enabled_ml_sta, conn_count;
-
-	conn_count = policy_mgr_get_connection_count(psoc);
-	policy_mgr_get_ml_sta_info_psoc(psoc, &num_ml_sta,
-					&num_disabled_ml_sta,
-					ml_sta_vdev_lst, ml_freq_lst,
-					&num_non_ml,
-					NULL, NULL);
-	num_enabled_ml_sta = num_ml_sta;
-	if (num_ml_sta >= num_disabled_ml_sta)
-		num_enabled_ml_sta = num_ml_sta - num_disabled_ml_sta;
-
-	return conn_count > num_enabled_ml_sta;
-}
-
 static uint8_t
 policy_mgr_get_affected_links_for_sta_sta(struct wlan_objmgr_psoc *psoc,
 					  uint8_t num_ml, qdf_freq_t *freq_list,
@@ -8665,10 +8659,6 @@ void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc,
 		policy_mgr_debug("Concurrency exists, cannot enter EMLSR mode");
 		goto done;
 	} else {
-		if (policy_mgr_is_ml_sta_concurrency_present(psoc)) {
-			policy_mgr_debug("Concurrency exists, don't enter EMLSR mode");
-				goto done;
-		}
 		ml_nlink_get_curr_force_state(psoc, vdev, &curr);
 		if (curr.force_inactive_num || curr.force_active_num) {
 			if (curr.force_inactive_num) {
@@ -8679,7 +8669,7 @@ void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc,
 					policy_mgr_debug("force num exists with act %d %d don't enter EMLSR mode",
 							 curr.force_active_num,
 							 curr.force_inactive_num);
-				goto done;
+					goto done;
 				}
 			}
 		}

+ 10 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c

@@ -64,6 +64,16 @@ static QDF_STATUS policy_mgr_init_cfg(struct wlan_objmgr_psoc *psoc)
 	cfg = &pm_ctx->cfg;
 
 	cfg->mcc_to_scc_switch = cfg_get(psoc, CFG_MCC_TO_SCC_SWITCH);
+	if (cfg->mcc_to_scc_switch != QDF_MCC_TO_SCC_SWITCH_DISABLE &&
+	    cfg->mcc_to_scc_switch <
+			QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION) {
+		policy_mgr_info("User configured mcc_to_scc_switch: %d, overwrite it to: %d",
+			cfg->mcc_to_scc_switch,
+			QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION);
+		cfg->mcc_to_scc_switch =
+			QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION;
+	}
+
 	cfg->sys_pref = cfg_get(psoc, CFG_CONC_SYS_PREF);
 
 	if (wlan_is_mlo_sta_nan_ndi_allowed(psoc)) {

+ 11 - 1
components/coex/core/inc/wlan_coex_main.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -115,6 +115,16 @@ wlan_coex_psoc_deinit(struct wlan_objmgr_psoc *psoc);
 QDF_STATUS wlan_coex_config_send(struct wlan_objmgr_vdev *vdev,
 				 struct coex_config_params *param);
 
+/**
+ * wlan_coex_multi_config_send() - API to send coex multiple configure
+ * @vdev: pointer to vdev object
+ * @param: parameters of coex multiple config
+ *
+ * QDF_STATUS
+ */
+QDF_STATUS wlan_coex_multi_config_send(struct wlan_objmgr_vdev *vdev,
+				       struct coex_multi_config *param);
+
 /**
  * wlan_coex_config_updated() - private API to notify that coex config
  * is updated.

+ 42 - 1
components/coex/core/src/wlan_coex_main.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -95,6 +95,47 @@ QDF_STATUS wlan_coex_config_send(struct wlan_objmgr_vdev *vdev,
 	return status;
 }
 
+QDF_STATUS wlan_coex_multi_config_send(struct wlan_objmgr_vdev *vdev,
+				       struct coex_multi_config *param)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct coex_config_params one_param;
+	QDF_STATUS status, ret = QDF_STATUS_SUCCESS;
+	uint32_t i;
+
+	if (!vdev) {
+		coex_err("Null vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		coex_err("failed to get coex_obj");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (tgt_get_coex_multi_config_support(psoc))
+		return tgt_send_coex_multi_config(vdev, param);
+
+	for (i = 0; i < param->num_configs; i++) {
+		one_param.vdev_id = param->vdev_id;
+		one_param.config_type = param->cfg_items[i].config_type;
+		one_param.config_arg1 = param->cfg_items[i].config_arg1;
+		one_param.config_arg2 = param->cfg_items[i].config_arg2;
+		one_param.config_arg3 = param->cfg_items[i].config_arg3;
+		one_param.config_arg4 = param->cfg_items[i].config_arg4;
+		one_param.config_arg5 = param->cfg_items[i].config_arg5;
+		one_param.config_arg6 = param->cfg_items[i].config_arg6;
+		status = tgt_send_coex_config(vdev, &one_param);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			coex_err("fail to send one coex config");
+			ret = status;
+		}
+	}
+
+	return ret;
+}
+
 QDF_STATUS
 wlan_coex_config_updated(struct wlan_objmgr_vdev *vdev, uint8_t type)
 {

+ 23 - 1
components/coex/dispatcher/inc/wlan_coex_tgt_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -28,6 +28,7 @@
 
 #ifdef FEATURE_COEX
 struct coex_config_params;
+struct coex_multi_config;
 
 /**
  * tgt_send_coex_config() - invoke target_if send coex config
@@ -39,6 +40,27 @@ struct coex_config_params;
 QDF_STATUS
 tgt_send_coex_config(struct wlan_objmgr_vdev *vdev,
 		     struct coex_config_params *param);
+
+/**
+ * tgt_send_coex_multi_config() - invoke target_if send coex multiple config
+ * @vdev: vdev object
+ * @param: coex multiple config parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+tgt_send_coex_multi_config(struct wlan_objmgr_vdev *vdev,
+			   struct coex_multi_config *param);
+
+/**
+ * tgt_get_coex_multi_config_support() - invoke target_if get coex multiple
+ * configure support
+ * @psoc: PSOC object
+ *
+ * Return: true if target support coex multiple config command
+ */
+bool
+tgt_get_coex_multi_config_support(struct wlan_objmgr_psoc *psoc);
 #endif
 
 #ifdef WLAN_FEATURE_DBAM_CONFIG

+ 19 - 0
components/coex/dispatcher/inc/wlan_coex_ucfg_api.h

@@ -109,6 +109,18 @@ ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS
 ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
 			      enum coex_btc_chain_mode mode);
+
+/**
+ * ucfg_coex_send_multi_config() - API to send coex multiple config to target
+ * @vdev: pointer to vdev object
+ * @param: pointer to coex multiple config parameters
+ *
+ * Return: status of operation
+ */
+QDF_STATUS
+ucfg_coex_send_multi_config(struct wlan_objmgr_vdev *vdev,
+			    struct coex_multi_config *param);
+
 /**
  * ucfg_coex_send_logging_config() - API to send BT coex logging config to
  * target if
@@ -146,6 +158,13 @@ ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline QDF_STATUS
+ucfg_coex_send_multi_config(struct wlan_objmgr_vdev *vdev,
+			    struct coex_multi_config *param)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
 static inline QDF_STATUS
 ucfg_coex_send_logging_config(struct wlan_objmgr_psoc *psoc,
 			      uint32_t *apps_args)

+ 45 - 1
components/coex/dispatcher/src/wlan_coex_tgt_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -84,6 +84,50 @@ tgt_send_coex_config(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS
+tgt_send_coex_multi_config(struct wlan_objmgr_vdev *vdev,
+			   struct coex_multi_config *param)
+{
+	struct wlan_lmac_if_coex_tx_ops *coex_ops;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (!vdev) {
+		coex_err("NULL vdev");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		coex_err("NULL psoc");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		coex_err("NULL pdev");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	coex_ops = wlan_psoc_get_coex_txops(psoc);
+	if (coex_ops && coex_ops->coex_multi_config_send)
+		return coex_ops->coex_multi_config_send(pdev, param);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool
+tgt_get_coex_multi_config_support(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_coex_tx_ops *coex_ops;
+
+	coex_ops = wlan_psoc_get_coex_txops(psoc);
+	if (coex_ops && coex_ops->coex_get_multi_config_support)
+		return coex_ops->coex_get_multi_config_support(psoc);
+
+	return false;
+}
+
 #ifdef WLAN_FEATURE_DBAM_CONFIG
 QDF_STATUS
 tgt_send_dbam_config(struct wlan_objmgr_vdev *vdev,

+ 8 - 0
components/coex/dispatcher/src/wlan_coex_ucfg_api.c

@@ -23,6 +23,7 @@
 #include <wlan_coex_ucfg_api.h>
 #include "wmi_unified.h"
 #include "wlan_coex_public_structs.h"
+#include "wlan_coex_tgt_api.h"
 
 QDF_STATUS
 ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc,
@@ -77,6 +78,13 @@ ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
 	return wlan_coex_config_send(vdev, &param);
 }
 
+QDF_STATUS
+ucfg_coex_send_multi_config(struct wlan_objmgr_vdev *vdev,
+			    struct coex_multi_config *param)
+{
+	return wlan_coex_multi_config_send(vdev, param);
+}
+
 #ifdef WLAN_FEATURE_DBAM_CONFIG
 QDF_STATUS
 ucfg_coex_send_dbam_config(struct wlan_objmgr_vdev *vdev,

+ 12 - 0
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h

@@ -99,6 +99,18 @@ QDF_STATUS tgt_send_mc_cp_stats_req(struct wlan_objmgr_psoc *psoc,
 				    enum stats_req_type type,
 				    struct request_info *req);
 
+/**
+ * tgt_set_pdev_stats_update_period(): API to set pdev stats update
+ * period to FW
+ * @psoc: pointer to psoc object
+ * @pdev_id: pdev id
+ * @val: pdev stats update period, 0: disabled periodical stats report.
+ *
+ * Return: status of operation
+ */
+QDF_STATUS tgt_set_pdev_stats_update_period(struct wlan_objmgr_psoc *psoc,
+					    uint8_t pdev_id, uint32_t val);
+
 /**
  * tgt_mc_cp_stats_inc_wake_lock_stats() : API to increment wake lock stats
  * given the wake reason code

+ 17 - 0
components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c

@@ -1542,3 +1542,20 @@ QDF_STATUS tgt_send_mc_cp_stats_req(struct wlan_objmgr_psoc *psoc,
 
 	return status;
 }
+
+QDF_STATUS tgt_set_pdev_stats_update_period(struct wlan_objmgr_psoc *psoc,
+					    uint8_t pdev_id, uint32_t val)
+{
+	struct wlan_lmac_if_cp_stats_tx_ops *tx_ops;
+	QDF_STATUS status;
+
+	tx_ops = target_if_cp_stats_get_tx_ops(psoc);
+	if (!tx_ops || !tx_ops->set_pdev_stats_update_period) {
+		cp_stats_err("could not get tx_ops");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	status = tx_ops->set_pdev_stats_update_period(psoc, pdev_id, val);
+
+	return status;
+}
+

+ 116 - 96
components/dp/core/src/wlan_dp_rx_thread.c

@@ -40,6 +40,8 @@
 #else
 #define DP_RX_THREAD_WAIT_TIMEOUT 2000
 #endif
+#define DP_RX_THREAD_FLUSH_TIMEOUT 6000
+#define DP_RX_THREAD_MIN_FLUSH_TIMEOUT 10
 
 #ifdef CONFIG_SLUB_DEBUG_ON
 /* number of rx pkts that thread should yield */
@@ -1100,139 +1102,157 @@ suspend_fail:
 	return qdf_status;
 }
 
-/**
- * dp_rx_thread_flush_by_vdev_id() - flush rx packets by vdev_id in
- * a particular rx thread queue
- * @rx_thread: rx_thread pointer of the queue from which packets are
- * to be flushed out
+/*
+ * dp_rx_tm_flush_nbuf_list() - Flush rx thread nbuf list
+ * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread
+ *  infrastructure
  * @vdev_id: vdev id for which packets are to be flushed
- * @wait_timeout: wait time value for rx thread to complete flush
  *
- * The function will flush the RX packets by vdev_id in a particular
- * RX thead queue. And will notify and wait the TX thread to flush the
- * packets in the NAPI RX GRO hash list
- *
- * Return: Success/Failure
+ * Return: None
  */
-static inline
-QDF_STATUS dp_rx_thread_flush_by_vdev_id(struct dp_rx_thread *rx_thread,
-					 uint8_t vdev_id, int wait_timeout)
+static inline void
+dp_rx_tm_flush_nbuf_list(struct dp_rx_tm_handle *rx_tm_hdl, uint8_t vdev_id)
 {
 	qdf_nbuf_t nbuf_list, tmp_nbuf_list;
 	uint32_t num_list_elements = 0;
-	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
-	uint64_t lock_time, unlock_time;
+	uint64_t lock_time, unlock_time, flush_time;
 	qdf_nbuf_t nbuf_list_head = NULL, nbuf_list_next;
+	struct dp_rx_thread *rx_thread;
+	int i;
 
-	qdf_nbuf_queue_head_lock(&rx_thread->nbuf_queue);
-	lock_time = qdf_get_log_timestamp();
-	QDF_NBUF_QUEUE_WALK_SAFE(&rx_thread->nbuf_queue, nbuf_list,
-				 tmp_nbuf_list) {
-		if (QDF_NBUF_CB_RX_VDEV_ID(nbuf_list) == vdev_id) {
-			qdf_nbuf_unlink_no_lock(nbuf_list,
-						&rx_thread->nbuf_queue);
-			DP_RX_HEAD_APPEND(nbuf_list_head, nbuf_list);
-		}
-	}
-	qdf_nbuf_queue_head_unlock(&rx_thread->nbuf_queue);
-	unlock_time = qdf_get_log_timestamp();
-	dp_info("Lock held time: %llu us",
-		qdf_log_timestamp_to_usecs(unlock_time - lock_time));
-
-	while (nbuf_list_head) {
-		nbuf_list_next = qdf_nbuf_queue_next(nbuf_list_head);
-		qdf_nbuf_set_next(nbuf_list_head, NULL);
-		dp_rx_thread_adjust_nbuf_list(nbuf_list_head);
-		num_list_elements =
-			QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf_list_head);
-		rx_thread->stats.rx_flushed += num_list_elements;
-		qdf_nbuf_list_free(nbuf_list_head);
-		nbuf_list_head = nbuf_list_next;
-	}
-
-	qdf_event_reset(&rx_thread->vdev_del_event);
-	qdf_set_bit(RX_VDEV_DEL_EVENT, &rx_thread->event_flag);
-	qdf_wake_up_interruptible(&rx_thread->wait_q);
+	for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) {
+		rx_thread = rx_tm_hdl->rx_thread[i];
+		if (!rx_thread)
+			continue;
 
-	qdf_status = qdf_wait_single_event(&rx_thread->vdev_del_event,
-					   wait_timeout);
+		qdf_nbuf_queue_head_lock(&rx_thread->nbuf_queue);
+		lock_time = qdf_get_log_timestamp();
+		QDF_NBUF_QUEUE_WALK_SAFE(&rx_thread->nbuf_queue, nbuf_list,
+					 tmp_nbuf_list) {
+			if (QDF_NBUF_CB_RX_VDEV_ID(nbuf_list) == vdev_id) {
+				qdf_nbuf_unlink_no_lock(nbuf_list,
+							&rx_thread->nbuf_queue);
+				DP_RX_HEAD_APPEND(nbuf_list_head, nbuf_list);
+			}
+		}
+		qdf_nbuf_queue_head_unlock(&rx_thread->nbuf_queue);
+		unlock_time = qdf_get_log_timestamp();
+
+		while (nbuf_list_head) {
+			nbuf_list_next = qdf_nbuf_queue_next(nbuf_list_head);
+			qdf_nbuf_set_next(nbuf_list_head, NULL);
+			dp_rx_thread_adjust_nbuf_list(nbuf_list_head);
+			num_list_elements =
+			    QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf_list_head);
+			rx_thread->stats.rx_flushed += num_list_elements;
+			qdf_nbuf_list_free(nbuf_list_head);
+			nbuf_list_head = nbuf_list_next;
+		}
 
-	if (QDF_IS_STATUS_SUCCESS(qdf_status))
-		dp_debug("thread:%d napi gro flush successfully",
-			 rx_thread->id);
-	else if (qdf_status == QDF_STATUS_E_TIMEOUT) {
-		dp_err("thread:%d timed out waiting for napi gro flush",
-		       rx_thread->id);
-		/*
-		 * If timeout, then force flush here in case any rx packets
-		 * belong to this vdev is still pending on stack queue,
-		 * while net_vdev will be freed soon.
-		 */
-		dp_rx_thread_gro_flush(rx_thread,
-				       DP_RX_GRO_NORMAL_FLUSH);
-	} else
-		dp_err("thread:%d failed while waiting for napi gro flush",
-		       rx_thread->id);
+		flush_time = qdf_get_log_timestamp();
+		dp_info("Thread: %u lock held time: %llu us flush time: %llu us",
+			rx_thread->id,
+			qdf_log_timestamp_to_usecs(unlock_time - lock_time),
+			qdf_log_timestamp_to_usecs(flush_time - unlock_time));
 
-	return qdf_status;
+		qdf_event_reset(&rx_thread->vdev_del_event);
+		qdf_set_bit(RX_VDEV_DEL_EVENT, &rx_thread->event_flag);
+		qdf_wake_up_interruptible(&rx_thread->wait_q);
+		}
 }
 
 /**
- * dp_rx_tm_flush_by_vdev_id() - flush rx packets by vdev_id in all
- * rx thread queues
+ * dp_rx_tm_wait_vdev_del_event() - wait on rx thread vdev delete event
  * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread
- * infrastructure
- * @vdev_id: vdev id for which packets are to be flushed
+ *  infrastructure
  *
- * Return: QDF_STATUS_SUCCESS
+ * Return: None
  */
-#ifdef HAL_CONFIG_SLUB_DEBUG_ON
-QDF_STATUS dp_rx_tm_flush_by_vdev_id(struct dp_rx_tm_handle *rx_tm_hdl,
-				     uint8_t vdev_id)
+static inline void
+dp_rx_tm_wait_vdev_del_event(struct dp_rx_tm_handle *rx_tm_hdl)
 {
-	struct dp_rx_thread *rx_thread;
 	QDF_STATUS qdf_status;
 	int i;
-	int wait_timeout = DP_RX_THREAD_WAIT_TIMEOUT;
+	struct dp_rx_thread *rx_thread;
+	int wait_timeout = DP_RX_THREAD_FLUSH_TIMEOUT;
+	uint64_t entry_time, exit_time, wait_time;
 
 	for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) {
 		rx_thread = rx_tm_hdl->rx_thread[i];
 		if (!rx_thread)
 			continue;
 
-		dp_debug("thread %d", i);
-		qdf_status = dp_rx_thread_flush_by_vdev_id(rx_thread, vdev_id,
-							   wait_timeout);
+		entry_time = qdf_get_log_timestamp();
+		qdf_status =
+			qdf_wait_single_event(&rx_thread->vdev_del_event,
+					      wait_timeout);
 
-		/* if one thread timeout happened, shrink timeout value
-		 * to 1/4 of original value
+		if (QDF_IS_STATUS_SUCCESS(qdf_status))
+			dp_debug("thread:%d napi gro flush successfully",
+				 rx_thread->id);
+		else if (qdf_status == QDF_STATUS_E_TIMEOUT) {
+			dp_err("thread:%d timed out waiting for napi gro flush",
+			       rx_thread->id);
+			/*
+			 * If timeout, then force flush in case any rx packets
+			 * belong to this vdev is still pending on stack queue,
+			 * while net_vdev will be freed soon.
+			 */
+			dp_rx_thread_gro_flush(rx_thread,
+					       DP_RX_GRO_NORMAL_FLUSH);
+		} else {
+			dp_err("thread:%d event wait failed with status: %d",
+			       rx_thread->id, qdf_status);
+		}
+
+		exit_time = qdf_get_log_timestamp();
+		wait_time = qdf_do_div(qdf_log_timestamp_to_usecs(exit_time -
+								  entry_time),
+				       QDF_USEC_PER_MSEC);
+		/**
+		 *
+		 * Maximum wait timeout to flush all thread is
+		 * DP_RX_THREAD_MIN_FLUSH_TIMEOUT, This logic
+		 * limit maximum wait time of all the thread to
+		 * DP_RX_THREAD_FLUSH_TIMEOUT. In case if
+		 * DP_RX_THREAD_FLUSH_TIMEOUT is exhausted
+		 * give remaining thread DP_RX_THREAD_MIN_FLUSH_TIMEOUT.
+		 *
+		 * Since all the threads are already woken before calling
+		 * wait API. So each thread will get
+		 * DP_RX_THREAD_FLUSH_TIMEOUT to set the event.
 		 */
-		if (qdf_status == QDF_STATUS_E_TIMEOUT)
-			wait_timeout = DP_RX_THREAD_WAIT_TIMEOUT / 4;
+		if (wait_timeout > DP_RX_THREAD_MIN_FLUSH_TIMEOUT)
+			wait_timeout = (wait_timeout > wait_time) ?
+				       (wait_timeout - wait_time) :
+				       DP_RX_THREAD_MIN_FLUSH_TIMEOUT;
 	}
-
-	return QDF_STATUS_SUCCESS;
 }
-#else
+
+/**
+ * dp_rx_tm_flush_by_vdev_id() - flush rx packets by vdev_id in all
+ * rx thread queues
+ * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread
+ * infrastructure
+ * @vdev_id: vdev id for which packets are to be flushed
+ *
+ * Return: QDF_STATUS_SUCCESS
+ */
 QDF_STATUS dp_rx_tm_flush_by_vdev_id(struct dp_rx_tm_handle *rx_tm_hdl,
 				     uint8_t vdev_id)
 {
-	struct dp_rx_thread *rx_thread;
-	int i;
+	uint64_t entry_time, exit_time;
 
-	for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) {
-		rx_thread = rx_tm_hdl->rx_thread[i];
-		if (!rx_thread)
-			continue;
-
-		dp_debug("thread %d", i);
-		dp_rx_thread_flush_by_vdev_id(rx_thread, vdev_id,
-					      DP_RX_THREAD_WAIT_TIMEOUT);
-	}
+	entry_time = qdf_get_log_timestamp();
+	dp_rx_tm_flush_nbuf_list(rx_tm_hdl, vdev_id);
+	dp_rx_tm_wait_vdev_del_event(rx_tm_hdl);
+	exit_time = qdf_get_log_timestamp();
+	dp_info("Vdev: %u total flush time: %llu us",
+		vdev_id,
+		qdf_log_timestamp_to_usecs(exit_time - entry_time));
 
 	return QDF_STATUS_SUCCESS;
 }
-#endif
 
 /**
  * dp_rx_tm_resume() - resume DP RX threads

+ 17 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -1653,6 +1653,16 @@ wlan_set_sap_user_config_freq(struct wlan_objmgr_vdev *vdev,
  */
 void wlan_clear_mlo_sta_link_removed_flag(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * wlan_get_mlo_link_agnostic_flag() - Update mlo link agnostic flag
+ *
+ * @vdev: pointer to vdev
+ * @dest_addr: destination address
+ *
+ * Return: true/false
+ */
+bool wlan_get_mlo_link_agnostic_flag(struct wlan_objmgr_vdev *vdev,
+				     uint8_t *dest_addr);
 /**
  * wlan_set_vdev_link_removed_flag_by_vdev_id() - Set link removal flag
  * on vdev
@@ -1692,6 +1702,13 @@ wlan_clear_mlo_sta_link_removed_flag(struct wlan_objmgr_vdev *vdev)
 {
 }
 
+static inline
+bool wlan_get_mlo_link_agnostic_flag(struct wlan_objmgr_vdev *vdev,
+				     uint8_t *dest_addr)
+{
+	return false;
+}
+
 static inline QDF_STATUS
 wlan_set_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc,
 					   uint8_t vdev_id, bool removed)

+ 32 - 0
components/mlme/core/src/wlan_mlme_main.c

@@ -2198,6 +2198,9 @@ static void mlme_init_he_cap_in_cfg(struct wlan_objmgr_psoc *psoc,
 		QDF_GET_BITS(mcs_12_13,
 			     HE_MCS12_13_5G_INDEX * HE_MCS12_13_BITS,
 			     HE_MCS12_13_BITS);
+
+	mlme_cfg->he_caps.disable_sap_mcs_12_13 = cfg_get(psoc,
+						CFG_DISABLE_MCS_12_13_SAP);
 }
 #else
 static void mlme_init_he_cap_in_cfg(struct wlan_objmgr_psoc *psoc,
@@ -2694,6 +2697,35 @@ void wlan_clear_mlo_sta_link_removed_flag(struct wlan_objmgr_vdev *vdev)
 				     &link_info[i].link_status_flags);
 }
 
+bool wlan_get_mlo_link_agnostic_flag(struct wlan_objmgr_vdev *vdev,
+				     uint8_t *dest_addr)
+{
+	struct wlan_objmgr_peer *bss_peer = NULL;
+	bool mlo_link_agnostic = false;
+	uint8_t *peer_mld_addr = NULL;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
+		return mlo_link_agnostic;
+
+	bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLME_OBJMGR_ID);
+	if (bss_peer) {
+		peer_mld_addr = wlan_peer_mlme_get_mldaddr(bss_peer);
+		if (!qdf_mem_cmp(bss_peer->macaddr, dest_addr,
+				 QDF_MAC_ADDR_SIZE) ||
+		    (peer_mld_addr && !qdf_mem_cmp(peer_mld_addr, dest_addr,
+						   QDF_MAC_ADDR_SIZE))) {
+			mlme_legacy_debug("dest address" QDF_MAC_ADDR_FMT "bss peer address"
+					  QDF_MAC_ADDR_FMT "mld addr" QDF_MAC_ADDR_FMT,
+					  QDF_MAC_ADDR_REF(dest_addr),
+					  QDF_MAC_ADDR_REF(bss_peer->macaddr),
+					  QDF_MAC_ADDR_REF(peer_mld_addr));
+			mlo_link_agnostic = true;
+		}
+		wlan_objmgr_peer_release_ref(bss_peer, WLAN_MLME_OBJMGR_ID);
+	}
+	return mlo_link_agnostic;
+}
+
 bool wlan_drop_mgmt_frame_on_link_removal(struct wlan_objmgr_vdev *vdev)
 {
 	if (!vdev || !mlo_is_mld_sta(vdev))

+ 27 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -47,6 +47,8 @@
 #include <wlan_lmac_if_def.h>
 #include "target_if_mlme.h"
 #include "wlan_mlo_mgr_sta.h"
+#include "wlan_cp_stats_mc_tgt_api.h"
+#include "wlan_objmgr_pdev_obj.h"
 
 static struct vdev_mlme_ops sta_mlme_ops;
 static struct vdev_mlme_ops ap_mlme_ops;
@@ -1822,6 +1824,31 @@ static QDF_STATUS mon_mlme_vdev_disconnect_peers(
 		uint16_t data_len, void *data,
 		bool is_disconnect_legacy_only)
 {
+	struct wlan_objmgr_psoc *psoc = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	uint32_t pdev_id;
+
+	psoc = wlan_vdev_get_psoc(vdev_mlme->vdev);
+	if (!psoc) {
+		mlme_legacy_debug("Invalid psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev_mlme->vdev);
+	if (!pdev) {
+		mlme_legacy_debug("Invalid pdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+	if (pdev_id == WLAN_INVALID_PDEV_ID) {
+		mlme_legacy_debug("Invalid pdev id");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* Cancel periodic pdev stats update */
+	tgt_set_pdev_stats_update_period(psoc, pdev_id, 0);
+
 	mlme_legacy_debug("vdev id = %d",
 			  vdev_mlme->vdev->vdev_objmgr.vdev_id);
 	return wlan_vdev_mlme_sm_deliver_evt(

+ 9 - 7
components/mlme/dispatcher/inc/cfg_mlme_fe_wlm.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -316,11 +316,11 @@
  * @max: 0xffffffffffffffff
  * @default: 0xc83
  *
- * |31  12|  11  |  10  |9    8|7    6|5    4|3    2|  1  |  0  |
- * +------+------+------+------+------+------+------+-----+-----+
- * | RSVD | SSLP | CSLP | RSVD | Roam | RSVD | DWLT | DFS | SUP |
- * +------+-------------+-------------+-------------------------+
- * |  WAL |      PS     |     Roam    |         Scan            |
+ * |31  25|  24  |23  12|  11  |  10  |9    8|7    6|5    4|3    2|  1  |  0  |
+ * +------+------+------+------+------+------+------+------+------+-----+-----+
+ * | RSVD | MLMR | RSVD | SSLP | CSLP | RSVD | Roam | RSVD | DWLT | DFS | SUP |
+ * +------+------+------+-------------+-------------+-------------------------+
+ * |  WAL |  PS  |  WAL |      PS     |     Roam    |         Scan            |
  *
  * bit 0: Avoid scan request from HLOS if setting
  * bit 1: Skip DFS channel SCAN if setting
@@ -340,7 +340,9 @@
  * bit 8-9: Reserve for roaming
  * bit 10: Disable css power collapse if setting
  * bit 11: Disable sys sleep if setting
- * bit 12-31: Reserve for future usage
+ * bit 12-23: Reserve for future usage
+ * bit 24: Disable MLMR mode
+ * bit 25-31: Reserved for future use
  *
  * |63  50|  49  |  48    |47        40|39   33|    32     |
  * +------+------+--------+------------+-------+-----------+

+ 25 - 1
components/mlme/dispatcher/inc/cfg_mlme_he_caps.h

@@ -855,6 +855,29 @@
 				CFG_VALUE_OR_DEFAULT, \
 				"He Configure MCS_12_13 bits")
 
+/*
+ * <ini>
+ * disable_mcs_12_13_sap - Bitmask to disable HE MCS 12 13 support for SAP
+ * @Min: 0
+ * @Max: 4095
+ * @Default: 0
+ *
+ * This ini is used to disable HE MCS_12_13 for SAP.
+ * Currently only support is present to disable 2.4 GHz 40 MHz SAP for value
+ * 2 i.e. 2nd bit set.
+ *
+ * Related: NA
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_DISABLE_MCS_12_13_SAP CFG_INI_UINT( \
+			"disable_mcs_12_13_sap", \
+			0, 4095, 0, \
+			CFG_VALUE_OR_DEFAULT, \
+			"Disable HE MCS_12_13 for SAP")
+
 #define CFG_HE_CAPS_ALL \
 	CFG(CFG_HE_CONTROL) \
 	CFG(CFG_HE_FRAGMENTATION) \
@@ -945,7 +968,8 @@
 	CFG(CFG_ENABLE_UL_MIMO) \
 	CFG(CFG_ENABLE_UL_OFDMA) \
 	CFG(CFG_HE_STA_OBSSPD) \
-	CFG(CFG_HE_MCS_12_13_SUPPORT)
+	CFG(CFG_HE_MCS_12_13_SUPPORT) \
+	CFG(CFG_DISABLE_MCS_12_13_SAP)
 
 #endif /* __CFG_MLME_HE_CAPS_H */
 

+ 4 - 2
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -28,6 +28,8 @@
 #include <wlan_cmn.h>
 #include "sme_api.h"
 
+#define DISABLE_MCS_12_13_2G_40M 1
+
 #define ASSEMBLE_RATECODE_V1(_pream, _nss, _rate) \
 		(((1) << 28) | ((_pream) << 8) | ((_nss) << 5) | (_rate))
 
@@ -1210,7 +1212,7 @@ void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev,
  * channel bandwidth
  * @psoc: pointer to psoc object
  * @vdev: pointer to vdev object
- * @vdev_id: vdev id
+ * @link_id: mlo link id
  * @ch_width: channel width to update
  *
  * Return: none
@@ -1218,7 +1220,7 @@ void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS
 wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 					   struct wlan_objmgr_vdev *vdev,
-					   uint8_t vdev_id,
+					   uint8_t link_id,
 					   enum phy_ch_width ch_width);
 
 /**

+ 40 - 2
components/mlme/dispatcher/inc/wlan_mlme_public_struct.h

@@ -1064,6 +1064,7 @@ struct wlan_mlme_qos {
  * @he_sta_obsspd:
  * @he_mcs_12_13_supp_2g:
  * @he_mcs_12_13_supp_5g:
+ * @disable_sap_mcs_12_13: Bitmap to disable he mcs 12 13 for SAP
  */
 struct wlan_mlme_he_caps {
 	tDot11fIEhe_cap dot11_he_cap;
@@ -1077,6 +1078,7 @@ struct wlan_mlme_he_caps {
 	uint32_t he_sta_obsspd;
 	uint16_t he_mcs_12_13_supp_2g;
 	uint16_t he_mcs_12_13_supp_5g;
+	uint32_t disable_sap_mcs_12_13;
 };
 #endif
 
@@ -2960,6 +2962,42 @@ struct wlan_change_bi {
 };
 
 #ifdef FEATURE_SET
+/**
+ * enum wlan_mlme_iface_combinations - Iface combinations
+ * @MLME_IFACE_STA_P2P_SUPPORT: STA + P2P concurrency bit
+ * @MLME_IFACE_STA_SAP_SUPPORT: STA + SAP concurrency bit
+ * @MLME_IFACE_STA_NAN_SUPPORT: STA + NAN concurrency bit
+ * @MLME_IFACE_STA_TDLS_SUPPORT: STA + TDLS concurrency bit
+ * @MLME_IFACE_STA_DUAL_P2P_SUPPORT: STA + P2P + P2P concurrency bit
+ * @MLME_IFACE_STA_SAP_P2P_SUPPORT: STA + SAP + P2P concurrency bit
+ * @MLME_IFACE_STA_SAP_NAN_SUPPORT: STA + SAP + NAN concurrency bit
+ * @MLME_IFACE_STA_P2P_NAN_SUPPORT: STA + P2P + NAN concurrency bit
+ * @MLME_IFACE_STA_P2P_TDLS_SUPPORT: STA + P2P + TDLS concurrency bit
+ * @MLME_IFACE_STA_SAP_TDLS_SUPPORT: STA + SAP + TDLS concurrency bit
+ * @MLME_IFACE_STA_NAN_TDLS_SUPPORT: STA + NAN + TDLS concurrency bit
+ * @MLME_IFACE_STA_SAP_P2P_TDLS_SUPPORT: STA + SAP + P2P + TDLS concurrency bit
+ * @MLME_IFACE_STA_SAP_NAN_TDLS_SUPPORT: STA + SAP + NAN + TDLS concurrency bit
+ * @MLME_IFACE_STA_P2P_P2P_TDLS_SUPPORT: STA + P2P + P2P + TDLS concurrency bit
+ * @MLME_IFACE_STA_P2P_NAN_TDLS_SUPPORT: STA + P2P + NAN + TDLS concurrency bit
+ */
+enum wlan_mlme_iface_combinations {
+	MLME_IFACE_STA_P2P_SUPPORT = 0x1,
+	MLME_IFACE_STA_SAP_SUPPORT = 0x2,
+	MLME_IFACE_STA_NAN_SUPPORT = 0x4,
+	MLME_IFACE_STA_TDLS_SUPPORT = 0x8,
+	MLME_IFACE_STA_DUAL_P2P_SUPPORT = 0x10,
+	MLME_IFACE_STA_SAP_P2P_SUPPORT = 0x20,
+	MLME_IFACE_STA_SAP_NAN_SUPPORT = 0x40,
+	MLME_IFACE_STA_P2P_NAN_SUPPORT = 0x80,
+	MLME_IFACE_STA_P2P_TDLS_SUPPORT = 0x100,
+	MLME_IFACE_STA_SAP_TDLS_SUPPORT = 0x200,
+	MLME_IFACE_STA_NAN_TDLS_SUPPORT = 0x400,
+	MLME_IFACE_STA_SAP_P2P_TDLS_SUPPORT = 0x800,
+	MLME_IFACE_STA_SAP_NAN_TDLS_SUPPORT = 0x1000,
+	MLME_IFACE_STA_P2P_P2P_TDLS_SUPPORT = 0x2000,
+	MLME_IFACE_STA_P2P_NAN_TDLS_SUPPORT = 0x4000,
+};
+
 /**
  * struct wlan_mlme_features - Mlme feature set structure
  * @enable_wifi_optimizer: indicates wifi optimizer is enabled or disabled
@@ -2979,8 +3017,8 @@ struct wlan_change_bi {
  * @roaming_ctrl_get_cu: Roaming ctrl get cu enabled or disabled
  * @vendor_req_1_version: Vendor requirement version 1
  * @vendor_req_2_version: Vendor requirement version 2
- * @sta_dual_p2p_support: STA + dual p2p support enabled or not
  * @enable2x2: Enable 2x2
+ * @iface_combinations: iface combination bitmask
  */
 struct wlan_mlme_features {
 	bool enable_wifi_optimizer;
@@ -2999,8 +3037,8 @@ struct wlan_mlme_features {
 	bool roaming_ctrl_get_cu;
 	WMI_HOST_VENDOR1_REQ1_VERSION vendor_req_1_version;
 	WMI_HOST_VENDOR1_REQ2_VERSION vendor_req_2_version;
-	bool sta_dual_p2p_support;
 	bool enable2x2;
+	uint32_t iface_combinations;
 };
 #endif
 

+ 11 - 0
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -4604,6 +4604,17 @@ QDF_STATUS
 ucfg_mlme_get_current_tx_power_level(struct wlan_objmgr_psoc *psoc,
 				     uint8_t *value);
 
+/**
+ * ucfg_wlan_mlme_get_reg_tpc_info() - get current regulatory tpc info
+ * @vdev:   pointer to vdev object
+ * @tpc_info:  pointer to tpc info buffer
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_wlan_mlme_get_reg_tpc_info(struct wlan_objmgr_vdev *vdev,
+				struct reg_tpc_power_info *tpc_info);
+
 /**
  * ucfg_mlme_set_obss_detection_offload_enabled() - Enable obss offload
  * @psoc:   pointer to psoc object

+ 164 - 3
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -7303,7 +7303,8 @@ wlan_mlme_get_adaptive11r_enabled(struct wlan_objmgr_psoc *psoc, bool *val)
 }
 #endif
 
-#ifdef WLAN_FEATURE_P2P_P2P_STA
+#if defined(WLAN_FEATURE_P2P_P2P_STA) && \
+	!defined(WLAN_FEATURE_NO_P2P_CONCURRENCY)
 static bool
 wlan_mlme_get_p2p_p2p_host_conc_support(void)
 {
@@ -7317,6 +7318,167 @@ wlan_mlme_get_p2p_p2p_host_conc_support(void)
 }
 #endif
 
+#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY
+static bool
+wlan_mlme_get_sta_sap_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_sap_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+#ifndef WLAN_FEATURE_NO_STA_NAN_CONCURRENCY
+static bool
+wlan_mlme_get_sta_nan_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_nan_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+#ifdef FEATURE_WLAN_TDLS
+static bool
+wlan_mlme_get_sta_tdls_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_tdls_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+#if !defined(WLAN_FEATURE_NO_STA_SAP_CONCURRENCY) && \
+	(!defined(WLAN_FEATURE_NO_P2P_CONCURRENCY) || \
+	 defined(WLAN_FEATURE_STA_SAP_P2P_CONCURRENCY))
+static bool
+wlan_mlme_get_sta_sap_p2p_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_sap_p2p_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+#if defined(FEATURE_WLAN_TDLS)
+static bool
+wlan_mlme_get_sta_p2p_tdls_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_p2p_tdls_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+#if defined(FEATURE_WLAN_TDLS) && !defined(WLAN_FEATURE_NO_STA_SAP_CONCURRENCY)
+static bool
+wlan_mlme_get_sta_sap_tdls_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_sap_tdls_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+#if defined(FEATURE_WLAN_TDLS) && \
+	!defined(WLAN_FEATURE_NO_STA_SAP_CONCURRENCY) && \
+	(!defined(WLAN_FEATURE_NO_P2P_CONCURRENCY) || \
+	 defined(WLAN_FEATURE_STA_SAP_P2P_CONCURRENCY))
+
+static bool
+wlan_mlme_get_sta_sap_p2p_tdls_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_sap_p2p_tdls_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+#if defined(FEATURE_WLAN_TDLS) && defined(WLAN_FEATURE_P2P_P2P_STA) && \
+	!defined(WLAN_FEATURE_NO_P2P_CONCURRENCY)
+static bool
+wlan_mlme_get_sta_p2p_p2p_tdls_host_conc_support(void)
+{
+	return true;
+}
+#else
+static bool
+wlan_mlme_get_sta_p2p_p2p_tdls_host_conc_support(void)
+{
+	return false;
+}
+#endif
+
+/**
+ * wlan_mlme_set_iface_combinations() - Set interface combinations
+ * @mlme_feature_set: Pointer to wlan_mlme_features
+ *
+ * Return: None
+ */
+static void
+wlan_mlme_set_iface_combinations(struct wlan_mlme_features *mlme_feature_set)
+{
+	mlme_feature_set->iface_combinations = 0;
+	mlme_feature_set->iface_combinations |= MLME_IFACE_STA_P2P_SUPPORT;
+	if (wlan_mlme_get_sta_sap_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_SAP_SUPPORT;
+	if (wlan_mlme_get_sta_nan_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_NAN_SUPPORT;
+	if (wlan_mlme_get_sta_tdls_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_TDLS_SUPPORT;
+	if (wlan_mlme_get_p2p_p2p_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_DUAL_P2P_SUPPORT;
+	if (wlan_mlme_get_sta_sap_p2p_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_SAP_P2P_SUPPORT;
+	if (wlan_mlme_get_sta_p2p_tdls_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_P2P_TDLS_SUPPORT;
+	if (wlan_mlme_get_sta_sap_tdls_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_SAP_TDLS_SUPPORT;
+	if (wlan_mlme_get_sta_sap_p2p_tdls_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_SAP_P2P_TDLS_SUPPORT;
+	if (wlan_mlme_get_sta_p2p_p2p_tdls_host_conc_support())
+		mlme_feature_set->iface_combinations |=
+					MLME_IFACE_STA_P2P_P2P_TDLS_SUPPORT;
+	mlme_debug("iface combinations = %x",
+		   mlme_feature_set->iface_combinations);
+}
+
 void wlan_mlme_get_feature_info(struct wlan_objmgr_psoc *psoc,
 				struct wlan_mlme_features *mlme_feature_set)
 {
@@ -7363,8 +7525,7 @@ void wlan_mlme_get_feature_info(struct wlan_objmgr_psoc *psoc,
 
 	mlme_feature_set->vendor_req_2_version =
 					WMI_HOST_VENDOR1_REQ2_VERSION_3_50;
-	mlme_feature_set->sta_dual_p2p_support =
-				wlan_mlme_get_p2p_p2p_host_conc_support();
+	wlan_mlme_set_iface_combinations(mlme_feature_set);
 	wlan_mlme_get_vht_enable2x2(psoc, &mlme_feature_set->enable2x2);
 }
 #endif

+ 18 - 0
components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c

@@ -1732,6 +1732,24 @@ ucfg_mlme_get_current_tx_power_level(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS ucfg_wlan_mlme_get_reg_tpc_info(struct wlan_objmgr_vdev *vdev,
+					   struct reg_tpc_power_info *tpc_info)
+{
+	struct vdev_mlme_obj *mlme_obj;
+
+	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev);
+
+	if (!mlme_obj) {
+		mlme_legacy_err("vdev component object is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	qdf_mem_copy(tpc_info, &mlme_obj->reg_tpc_obj,
+		     sizeof(struct reg_tpc_power_info));
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS
 ucfg_mlme_set_obss_detection_offload_enabled(struct wlan_objmgr_psoc *psoc,
 					     uint8_t value)

+ 6 - 3
components/p2p/core/src/wlan_p2p_off_chan_tx.c

@@ -1185,13 +1185,14 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx,
 	mgmt_tx_download_comp_cb tx_comp_cb;
 	mgmt_ota_comp_cb tx_ota_comp_cb;
 	struct wlan_frame_hdr *wh;
-	struct wlan_objmgr_peer *peer;
+	struct wlan_objmgr_peer *peer = NULL;
 	struct wmi_mgmt_params mgmt_param = { 0 };
 	struct wlan_objmgr_psoc *psoc;
 	void *mac_addr;
 	uint8_t pdev_id;
 	struct wlan_objmgr_vdev *vdev;
 	enum QDF_OPMODE opmode;
+	bool mlo_link_agnostic;
 
 	psoc = tx_ctx->p2p_soc_obj->soc;
 	mgmt_param.tx_frame = packet;
@@ -1217,6 +1218,8 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx,
 		return QDF_STATUS_E_INVAL;
 	}
 
+	mlo_link_agnostic = wlan_get_mlo_link_agnostic_flag(vdev, mac_addr);
+
 	peer = wlan_objmgr_get_peer(psoc, pdev_id,  mac_addr, WLAN_P2P_ID);
 	if (!peer) {
 		mac_addr = wh->i_addr2;
@@ -1265,10 +1268,10 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx,
 	tx_ctx->nbuf = packet;
 
 	if (mlo_is_mld_sta(vdev) && tx_ctx->frame_info.type == P2P_FRAME_MGMT &&
-	    tx_ctx->frame_info.sub_type == P2P_MGMT_ACTION) {
+	    tx_ctx->frame_info.sub_type == P2P_MGMT_ACTION &&
+	    mlo_link_agnostic) {
 		mgmt_param.mlo_link_agnostic = true;
 	}
-
 	status = wlan_mgmt_txrx_mgmt_frame_tx(peer, tx_ctx->p2p_soc_obj,
 			packet, tx_comp_cb, tx_ota_comp_cb,
 			WLAN_UMAC_COMP_P2P, &mgmt_param);

+ 19 - 0
components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h

@@ -476,4 +476,23 @@ bool ucfg_p2p_is_roam_config_disabled(struct wlan_objmgr_psoc *psoc)
  * Return: p2p go supported on indoor channel
  */
 bool ucfg_p2p_get_indoor_ch_support(struct wlan_objmgr_psoc *psoc);
+
+#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
+/**
+ * ucfg_is_p2p_device_dynamic_set_mac_addr_supported() - API to check P2P device
+ * dynamic MAC address update is supported or not
+ *
+ * @psoc: Pointer to psoc
+ *
+ * Return: true or false
+ */
+bool
+ucfg_is_p2p_device_dynamic_set_mac_addr_supported(struct wlan_objmgr_psoc *psoc);
+#else
+static inline bool
+ucfg_is_p2p_device_dynamic_set_mac_addr_supported(struct wlan_objmgr_psoc *psoc)
+{
+	return false;
+}
+#endif
 #endif /* _WLAN_P2P_UCFG_API_H_ */

+ 19 - 0
components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c

@@ -31,6 +31,7 @@
 #include "../../core/src/wlan_p2p_main.h"
 #include "../../core/src/wlan_p2p_roc.h"
 #include "../../core/src/wlan_p2p_off_chan_tx.h"
+#include "target_if.h"
 
 static inline struct wlan_lmac_if_p2p_tx_ops *
 ucfg_p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc)
@@ -661,3 +662,21 @@ bool ucfg_p2p_get_indoor_ch_support(struct wlan_objmgr_psoc *psoc)
 
 	return p2p_soc_obj->param.indoor_channel_support;
 }
+
+#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
+bool
+ucfg_is_p2p_device_dynamic_set_mac_addr_supported(struct wlan_objmgr_psoc *psoc)
+{
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		p2p_err("wmi handle is NULL");
+		return false;
+	}
+
+	return wmi_service_enabled(wmi_handle,
+				   wmi_service_p2p_device_update_mac_addr_support);
+}
+#endif
+

+ 17 - 7
components/pmo/core/src/wlan_pmo_ns.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -78,6 +78,7 @@ static QDF_STATUS pmo_core_cache_ns_in_vdev_priv(
 	struct pmo_vdev_priv_obj *vdev_ctx;
 	struct pmo_ns_offload_params *request;
 	struct wlan_objmgr_peer *peer;
+	uint8_t *self_addr, *peer_addr;
 
 	vdev_ctx = pmo_vdev_get_priv(vdev);
 
@@ -91,9 +92,6 @@ static QDF_STATUS pmo_core_cache_ns_in_vdev_priv(
 
 	request->enable = PMO_OFFLOAD_ENABLE;
 	request->is_offload_applied = false;
-	qdf_mem_copy(&request->self_macaddr.bytes,
-		     wlan_vdev_mlme_get_macaddr(vdev),
-		     QDF_MAC_ADDR_SIZE);
 
 	/* set number of ns offload address count */
 	request->num_ns_offload_count = ns_req->count;
@@ -104,11 +102,23 @@ static QDF_STATUS pmo_core_cache_ns_in_vdev_priv(
 		status = QDF_STATUS_E_INVAL;
 		goto out;
 	}
+
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		self_addr = wlan_vdev_mlme_get_mldaddr(vdev);
+		peer_addr = wlan_peer_mlme_get_mldaddr(peer);
+	} else {
+		self_addr = wlan_vdev_mlme_get_macaddr(vdev);
+		peer_addr = wlan_peer_get_macaddr(peer);
+	}
+
 	pmo_debug("vdev self mac addr: "QDF_MAC_ADDR_FMT" bss peer mac addr: "QDF_MAC_ADDR_FMT,
-		QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
-		QDF_MAC_ADDR_REF(wlan_peer_get_macaddr(peer)));
+		QDF_MAC_ADDR_REF(self_addr),
+		QDF_MAC_ADDR_REF(peer_addr));
+
+	qdf_mem_copy(&request->self_macaddr.bytes, self_addr,
+		     QDF_MAC_ADDR_SIZE);
 	/* get peer and peer mac accdress aka ap mac address */
-	qdf_mem_copy(&request->bssid, wlan_peer_get_macaddr(peer),
+	qdf_mem_copy(&request->bssid, peer_addr,
 		     QDF_MAC_ADDR_SIZE);
 	wlan_objmgr_peer_release_ref(peer, WLAN_PMO_ID);
 	/* cache ns request */

+ 4 - 1
components/pmo/core/src/wlan_pmo_suspend_resume.c

@@ -1032,10 +1032,13 @@ QDF_STATUS pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc)
 		goto out;
 	}
 
+	cdp_display_txrx_hw_info(dp_soc);
+	/* drain RX rings only */
+	cdp_drain_txrx(dp_soc, 1);
+
 	if (ret == -EOPNOTSUPP)
 		goto out;
 
-	cdp_drain_txrx(dp_soc);
 	pmo_ctx->wow.txrx_suspended = true;
 out:
 	pmo_psoc_put_ref(psoc);

+ 54 - 0
components/target_if/coex/src/target_if_coex.c

@@ -22,6 +22,13 @@
 #include <target_if_coex.h>
 #include "wlan_coex_public_structs.h"
 
+/**
+ * target_if_coex_config_send() - Function to send coex config command
+ * @pdev: PDEV object
+ * @param: Pointer to coex config parameters
+ *
+ * Return: QDF STATUS
+ */
 static QDF_STATUS
 target_if_coex_config_send(struct wlan_objmgr_pdev *pdev,
 			   struct coex_config_params *param)
@@ -37,6 +44,50 @@ target_if_coex_config_send(struct wlan_objmgr_pdev *pdev,
 	return wmi_unified_send_coex_config_cmd(pdev_wmi_handle, param);
 }
 
+/**
+ * target_if_coex_multi_config_send() - Function to send coex multiple config
+ * command
+ * @pdev: PDEV object
+ * @param: Pointer to coex multiple config parameters
+ *
+ * Return: QDF STATUS
+ */
+static QDF_STATUS
+target_if_coex_multi_config_send(struct wlan_objmgr_pdev *pdev,
+				 struct coex_multi_config *param)
+{
+	wmi_unified_t pdev_wmi_handle;
+
+	pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
+	if (!pdev_wmi_handle) {
+		coex_err("Invalid PDEV WMI handle");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return wmi_unified_send_coex_multi_config_cmd(pdev_wmi_handle, param);
+}
+
+/**
+ * target_if_coex_get_multi_config_support() - Function to get coex multiple
+ * config command support
+ * @psoc: PSOC object
+ *
+ * Return: true if target support coex multiple config command
+ */
+static bool
+target_if_coex_get_multi_config_support(struct wlan_objmgr_psoc *psoc)
+{
+	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return false;
+	}
+
+	return wmi_service_enabled(wmi_handle,
+				   wmi_service_multiple_coex_config_support);
+}
+
 QDF_STATUS
 target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 {
@@ -49,6 +100,9 @@ target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 
 	coex_ops = &tx_ops->coex_ops;
 	coex_ops->coex_config_send = target_if_coex_config_send;
+	coex_ops->coex_multi_config_send = target_if_coex_multi_config_send;
+	coex_ops->coex_get_multi_config_support =
+				target_if_coex_get_multi_config_support;
 
 	return QDF_STATUS_SUCCESS;
 }

+ 28 - 0
components/target_if/cp_stats/src/target_if_mc_cp_stats.c

@@ -1673,6 +1673,31 @@ static QDF_STATUS target_if_cp_stats_send_stats_req(
 					      &param);
 }
 
+/**
+ * target_if_set_pdev_stats_update_period(): API to set pdev stats update
+ * period to FW
+ * @psoc: pointer to psoc object
+ * @pdev_id: pdev id
+ * @val: pdev stats update period, 0: disabled periodical stats report.
+ *
+ * Return: status of operation
+ */
+static QDF_STATUS
+target_if_set_pdev_stats_update_period(struct wlan_objmgr_psoc *psoc,
+				       uint8_t pdev_id, uint32_t val)
+{
+	struct wmi_unified *wmi_handle;
+	struct pdev_params pdev_param = {0};
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+
+	pdev_param.param_id = wmi_pdev_param_pdev_stats_update_period;
+	pdev_param.param_value = val;
+	return wmi_unified_pdev_param_send(wmi_handle,
+					   &pdev_param,
+					   pdev_id);
+}
+
 /**
  * target_if_mc_cp_stats_unregister_handlers() - Unregisters wmi event handlers
  * of control plane stats & twt session stats info
@@ -1765,6 +1790,8 @@ target_if_mc_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 	cp_stats_tx_ops->inc_wake_lock_stats =
 		target_if_cp_stats_inc_wake_lock_stats;
 	cp_stats_tx_ops->send_req_stats = target_if_cp_stats_send_stats_req;
+	cp_stats_tx_ops->set_pdev_stats_update_period =
+			target_if_set_pdev_stats_update_period;
 	cp_stats_tx_ops->send_req_peer_stats =
 		target_if_cp_stats_send_peer_stats_req;
 
@@ -1792,6 +1819,7 @@ target_if_mc_cp_stats_unregister_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 	target_if_big_data_stats_unregister_tx_ops(cp_stats_tx_ops);
 	cp_stats_tx_ops->inc_wake_lock_stats = NULL;
 	cp_stats_tx_ops->send_req_stats = NULL;
+	cp_stats_tx_ops->set_pdev_stats_update_period = NULL;
 	cp_stats_tx_ops->send_req_peer_stats = NULL;
 
 	return QDF_STATUS_SUCCESS;

+ 52 - 33
components/tdls/core/src/wlan_tdls_main.c

@@ -1189,8 +1189,13 @@ tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc)
 	}
 
 	if (!tdls_check_is_tdls_allowed(tdls_vdev)) {
-		tdls_disable_offchan_and_teardown_links(tdls_vdev);
 		tdls_debug("Disable the tdls in FW due to concurrency");
+		if (wlan_vdev_mlme_is_mlo_vdev(tdls_vdev))
+			tdls_process_enable_disable_for_ml_vdev(tdls_vdev,
+								false);
+		else
+			tdls_disable_offchan_and_teardown_links(tdls_vdev);
+
 		wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID);
 		return QDF_STATUS_E_NULL_VALUE;
 	}
@@ -1209,11 +1214,7 @@ tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc)
 QDF_STATUS
 tdls_process_decrement_active_session(struct wlan_objmgr_psoc *psoc)
 {
-	struct tdls_soc_priv_obj *tdls_priv_soc;
-	struct tdls_vdev_priv_obj *tdls_priv_vdev;
 	struct wlan_objmgr_vdev *tdls_obj_vdev;
-	uint8_t vdev_id;
-	QDF_STATUS status;
 
 	tdls_debug("Enter");
 	if (!psoc)
@@ -1239,19 +1240,11 @@ tdls_process_decrement_active_session(struct wlan_objmgr_psoc *psoc)
 	 * 4 Port -> 3 Port SCC scenario
 	 * So enable TDLS in firmware
 	 */
-	tdls_debug("Enable TDLS in FW and host as active sta/p2p_cli interface is present");
-	vdev_id = wlan_vdev_get_id(tdls_obj_vdev);
-	status = tdls_get_vdev_objects(tdls_obj_vdev, &tdls_priv_vdev,
-				       &tdls_priv_soc);
-	if (QDF_IS_STATUS_ERROR(status))
-		goto release_ref;
-
-	tdls_send_update_to_fw(tdls_priv_vdev, tdls_priv_soc,
-			       mlme_get_tdls_prohibited(tdls_obj_vdev),
-			       mlme_get_tdls_chan_switch_prohibited(tdls_obj_vdev),
-			       true, vdev_id);
-	if (tdls_priv_soc->connected_peer_count == 1)
-		tdls_set_tdls_offchannelmode(tdls_obj_vdev, ENABLE_CHANSWITCH);
+	tdls_debug("Enable TDLS as active sta/p2p_cli interface is present");
+	if (wlan_vdev_mlme_is_mlo_vdev(tdls_obj_vdev))
+		tdls_process_enable_disable_for_ml_vdev(tdls_obj_vdev, true);
+	else
+		tdls_process_enable_for_vdev(tdls_obj_vdev);
 
 release_ref:
 	wlan_objmgr_vdev_release_ref(tdls_obj_vdev, WLAN_TDLS_NB_ID);
@@ -1546,6 +1539,42 @@ void tdls_process_enable_for_vdev(struct wlan_objmgr_vdev *vdev)
 	tdls_set_ct_mode(tdls_soc_obj->soc, vdev);
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+void tdls_process_enable_disable_for_ml_vdev(struct wlan_objmgr_vdev *vdev,
+					     bool is_enable)
+{
+	struct wlan_mlo_dev_context *ml_dev_ctx;
+	QDF_STATUS status;
+	uint8_t i;
+	struct wlan_objmgr_vdev *vdev_iter;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
+		return;
+
+	ml_dev_ctx = vdev->mlo_dev_ctx;
+	if (!ml_dev_ctx)
+		return;
+
+	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		if (!ml_dev_ctx->wlan_vdev_list[i])
+			continue;
+
+		vdev_iter = ml_dev_ctx->wlan_vdev_list[i];
+		status = wlan_objmgr_vdev_try_get_ref(vdev_iter,
+						      WLAN_TDLS_NB_ID);
+		if (QDF_IS_STATUS_ERROR(status))
+			continue;
+
+		if (is_enable)
+			tdls_process_enable_for_vdev(vdev_iter);
+		else
+			tdls_disable_offchan_and_teardown_links(vdev_iter);
+
+		wlan_objmgr_vdev_release_ref(vdev_iter, WLAN_TDLS_NB_ID);
+	}
+}
+#endif
+
 static QDF_STATUS
 tdls_process_sta_connect(struct tdls_sta_notify_params *notify)
 {
@@ -1619,7 +1648,6 @@ tdls_process_sta_disconnect(struct tdls_sta_notify_params *notify)
 	struct tdls_vdev_priv_obj *tdls_vdev_obj;
 	struct tdls_soc_priv_obj *tdls_soc_obj;
 	struct wlan_objmgr_vdev *temp_vdev = NULL;
-	uint8_t vdev_id;
 	QDF_STATUS status;
 
 	status = tdls_get_vdev_objects(notify->vdev, &tdls_vdev_obj,
@@ -1641,6 +1669,7 @@ tdls_process_sta_disconnect(struct tdls_sta_notify_params *notify)
 			       false, false, notify->session_id);
 
 	tdls_timers_stop(tdls_vdev_obj);
+
 	/*
 	 * If concurrency is not marked, then we have to
 	 * check, whether TDLS could be enabled in the
@@ -1653,21 +1682,11 @@ tdls_process_sta_disconnect(struct tdls_sta_notify_params *notify)
 	if (!temp_vdev)
 		return status;
 
-	vdev_id = wlan_vdev_get_id(temp_vdev);
-	status = tdls_get_vdev_objects(temp_vdev, &tdls_vdev_obj,
-				       &tdls_soc_obj);
-	if (QDF_IS_STATUS_ERROR(status)) {
-		wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_TDLS_NB_ID);
-		return status;
-	}
-
-	tdls_send_update_to_fw(tdls_vdev_obj, tdls_soc_obj,
-			       mlme_get_tdls_prohibited(temp_vdev),
-			       mlme_get_tdls_chan_switch_prohibited(temp_vdev),
-			       true, vdev_id);
+	if (wlan_vdev_mlme_is_mlo_vdev(temp_vdev))
+		tdls_process_enable_disable_for_ml_vdev(temp_vdev, true);
+	else
+		tdls_process_enable_for_vdev(temp_vdev);
 
-	/* Check and set the connection tracker and implicit timers */
-	tdls_set_ct_mode(tdls_soc_obj->soc, temp_vdev);
 	wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_TDLS_NB_ID);
 
 	wlan_vdev_mlme_feat_ext2_cap_clear(notify->vdev,

+ 19 - 0
components/tdls/core/src/wlan_tdls_main.h

@@ -619,6 +619,25 @@ QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify);
  */
 void tdls_process_enable_for_vdev(struct wlan_objmgr_vdev *vdev);
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * tdls_process_enable_disable_for_ml_vdev() - Enable TDLS in firmware & active
+ * connection tracker for all the ML vdevs belonging to same MLD as the
+ * given vdev
+ * @vdev: Pointer to vdev object
+ * @is_enable: Flag to indicate if operation is enable TDLS or disable TDLS
+ *
+ * Return: None
+ */
+void tdls_process_enable_disable_for_ml_vdev(struct wlan_objmgr_vdev *vdev,
+					     bool is_enable);
+#else
+static inline
+void tdls_process_enable_disable_for_ml_vdev(struct wlan_objmgr_vdev *vdev,
+					     bool is_enable)
+{}
+#endif
+
 /**
  * tdls_notify_sta_disconnect() - Update tdls state for every
  * disconnect event.

+ 65 - 19
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c

@@ -49,6 +49,44 @@
 #include "wlan_vdev_mgr_utils_api.h"
 #include "wlan_mlo_link_force.h"
 #include <wlan_psoc_mlme_api.h>
+#include <wma.h>
+
+/*
+ * cm_is_peer_preset_on_other_sta() - Check if peer exists on other STA
+ * @psoc: Pointer to psoc
+ * @vdev: pointer to vdev
+ * @vdev_id: vdev id
+ * @event: Roam sync event pointer
+ *
+ * Return: True is peer found on other STA else return false
+ */
+static bool
+cm_is_peer_preset_on_other_sta(struct wlan_objmgr_psoc *psoc,
+			       struct wlan_objmgr_vdev *vdev,
+			       uint8_t vdev_id, void *event)
+{
+	bool peer_exists_other_sta = false;
+	struct roam_offload_synch_ind *sync_ind;
+	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
+	uint8_t peer_vdev_id;
+
+	sync_ind = (struct roam_offload_synch_ind *)event;
+
+	if (wma_objmgr_peer_exist(wma, sync_ind->bssid.bytes, &peer_vdev_id)) {
+		if ((!wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+		     vdev_id != peer_vdev_id) ||
+		    !mlo_check_is_given_vdevs_on_same_mld(psoc, vdev_id,
+							  peer_vdev_id)) {
+			wma_debug("Peer " QDF_MAC_ADDR_FMT
+				" already exists on vdev %d, current vdev %d",
+				QDF_MAC_ADDR_REF(sync_ind->bssid.bytes),
+				peer_vdev_id, vdev_id);
+			peer_exists_other_sta = true;
+		}
+	}
+
+	return peer_exists_other_sta;
+}
 
 QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 			       void *event, uint32_t event_data_len)
@@ -66,12 +104,16 @@ QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 
 	if (mlo_is_mld_disconnecting_connecting(vdev) ||
 	    cm_is_vdev_connecting(vdev) ||
-	    cm_is_vdev_disconnecting(vdev)) {
+	    cm_is_vdev_disconnecting(vdev) ||
+	    cm_is_peer_preset_on_other_sta(psoc, vdev, vdev_id, event)) {
 		mlme_err("vdev %d Roam sync not handled in connecting/disconnecting state",
 			 vdev_id);
+		status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
+						   vdev_id,
+						   WLAN_ROAM_RSO_STOPPED,
+						   REASON_ROAM_SYNCH_FAILED);
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
-		return cm_roam_stop_req(psoc, vdev_id,
-					REASON_ROAM_SYNCH_FAILED, NULL, false);
+		return status;
 	}
 	mlo_sta_stop_reconfig_timer(vdev);
 	wlan_clear_mlo_sta_link_removed_flag(vdev);
@@ -81,8 +123,9 @@ QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_err("Roam sync was not handled");
-		cm_roam_stop_req(psoc, vdev_id, REASON_ROAM_SYNCH_FAILED,
-				 NULL, false);
+		wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
+					  vdev_id, WLAN_ROAM_RSO_STOPPED,
+					  REASON_ROAM_SYNCH_FAILED);
 	}
 
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
@@ -1265,14 +1308,21 @@ QDF_STATUS cm_fw_roam_complete(struct cnx_mgr *cm_ctx, void *data)
 	if (ucfg_pkt_capture_get_pktcap_mode(psoc))
 		ucfg_pkt_capture_record_channel(cm_ctx->vdev);
 
-	if (WLAN_REG_IS_24GHZ_CH_FREQ(roam_synch_data->chan_freq)) {
-		wlan_cm_set_disable_hi_rssi(pdev,
-					    vdev_id, false);
-	} else {
-		wlan_cm_set_disable_hi_rssi(pdev,
-					    vdev_id, true);
-		mlme_debug("Disabling HI_RSSI, AP freq=%d rssi %d",
-			   roam_synch_data->chan_freq, roam_synch_data->rssi);
+	/*
+	 * Firmware will take care of checking hi_scan rssi delta, take care of
+	 * legacy -> legacy hi-rssi roam also if self mld roam supported.
+	 */
+	if (!wlan_cm_is_self_mld_roam_supported(psoc)) {
+		if (WLAN_REG_IS_24GHZ_CH_FREQ(roam_synch_data->chan_freq)) {
+			wlan_cm_set_disable_hi_rssi(pdev,
+						    vdev_id, false);
+		} else {
+			wlan_cm_set_disable_hi_rssi(pdev,
+						    vdev_id, true);
+			mlme_debug("Disabling HI_RSSI, AP freq=%d rssi %d vdev id %d",
+				   roam_synch_data->chan_freq,
+				   roam_synch_data->rssi, vdev_id);
+		}
 	}
 	policy_mgr_check_n_start_opportunistic_timer(psoc);
 
@@ -1534,7 +1584,7 @@ static QDF_STATUS cm_handle_ho_fail(struct scheduler_msg *msg)
 
 	roam_req = cm_get_first_roam_command(vdev);
 	if (roam_req) {
-		mlme_debug("Roam req found, get cm id to remove it, before disconnect");
+		mlme_debug("Roam req found, get cm id to remove it, after disconnect");
 		cm_id = roam_req->cm_id;
 	}
 	/* CPU freq is boosted during roam sync to improve roam latency,
@@ -1542,9 +1592,6 @@ static QDF_STATUS cm_handle_ho_fail(struct scheduler_msg *msg)
 	 */
 	mlme_cm_osif_perfd_reset_cpufreq();
 
-	cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_HO_FAIL,
-			    sizeof(wlan_cm_id), &cm_id);
-
 	qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info));
 	if (cm_ho_fail_is_avoid_list_candidate(vdev, ind)) {
 		ap_info.bssid = ind->bssid;
@@ -1567,8 +1614,7 @@ static QDF_STATUS cm_handle_ho_fail(struct scheduler_msg *msg)
 			       WLAN_LOG_INDICATOR_HOST_DRIVER,
 			       WLAN_LOG_REASON_ROAM_HO_FAILURE, false, false);
 
-	if (QDF_IS_STATUS_ERROR(status))
-		cm_remove_cmd(cm_ctx, &cm_id);
+	cm_remove_cmd(cm_ctx, &cm_id);
 
 error:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);

+ 55 - 34
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -51,6 +51,7 @@
 #include "wlan_policy_mgr_api.h"
 #include "wlan_mlo_mgr_link_switch.h"
 #include "wlan_mlo_mgr_sta.h"
+#include "wlan_vdev_mgr_api.h"
 
 #ifdef WLAN_FEATURE_SAE
 #define CM_IS_FW_FT_SAE_SUPPORTED(fw_akm_bitmap) \
@@ -2926,6 +2927,44 @@ cm_roam_scan_offload_fill_rso_configs(struct wlan_objmgr_psoc *psoc,
 	cm_roam_scan_offload_add_fils_params(psoc, rso_mode_cfg, vdev_id);
 }
 
+bool cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
+{
+	struct wlan_objmgr_peer *peer;
+	uint8_t bssid[QDF_MAC_ADDR_SIZE];
+	struct cm_roam_values_copy temp;
+	bool is_pmf_enabled, mbo_oce_enabled_ap, is_open_connection;
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev object is NULL for vdev %d", vdev_id);
+		return false;
+	}
+	is_open_connection = cm_is_open_mode(vdev);
+	wlan_vdev_mgr_get_param_bssid(vdev, bssid);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, bssid, WLAN_MLME_CM_ID);
+	if (!peer) {
+		mlme_debug("Peer of peer_mac "QDF_MAC_ADDR_FMT" not found",
+			   QDF_MAC_ADDR_REF(bssid));
+		return false;
+	}
+	is_pmf_enabled = mlme_get_peer_pmf_status(peer);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_MLME_CM_ID);
+
+	wlan_cm_roam_cfg_get_value(psoc, vdev_id, MBO_OCE_ENABLED_AP, &temp);
+	mbo_oce_enabled_ap = !!temp.uint_value;
+
+	mlme_debug("vdev %d, is_pmf_enabled %d mbo_oce_enabled_ap:%d is_open_connection: %d for "QDF_MAC_ADDR_FMT,
+		   vdev_id, is_pmf_enabled, mbo_oce_enabled_ap,
+		   is_open_connection, QDF_MAC_ADDR_REF(bssid));
+
+	return !is_pmf_enabled && mbo_oce_enabled_ap && !is_open_connection;
+}
+
 /**
  * cm_update_btm_offload_config() - Update btm config param to fw
  * @psoc: psoc
@@ -2943,12 +2982,9 @@ cm_update_btm_offload_config(struct wlan_objmgr_psoc *psoc,
 {
 	struct wlan_mlme_psoc_ext_obj *mlme_obj;
 	struct wlan_mlme_btm *btm_cfg;
-	struct wlan_objmgr_peer *peer;
-	uint8_t bssid[QDF_MAC_ADDR_SIZE];
+	bool is_hs_20_ap;
 	struct cm_roam_values_copy temp;
-	bool is_hs_20_ap, is_pmf_enabled, is_open_connection = false;
 	uint8_t vdev_id;
-	uint32_t mbo_oce_enabled_ap;
 	bool abridge_flag;
 
 	mlme_obj = mlme_get_psoc_ext_obj(psoc);
@@ -2983,45 +3019,19 @@ cm_update_btm_offload_config(struct wlan_objmgr_psoc *psoc,
 		return;
 	}
 
-	ucfg_wlan_vdev_mgr_get_param_bssid(vdev, bssid);
-	peer = wlan_objmgr_get_peer(psoc,
-				    wlan_objmgr_pdev_get_pdev_id(
-					wlan_vdev_get_pdev(vdev)),
-				    bssid,
-				    WLAN_MLME_CM_ID);
-	if (!peer) {
-		mlme_debug("Peer of peer_mac "QDF_MAC_ADDR_FMT" not found",
-			   QDF_MAC_ADDR_REF(bssid));
-		return;
-	}
-
-	is_pmf_enabled = mlme_get_peer_pmf_status(peer);
-
-	wlan_objmgr_peer_release_ref(peer, WLAN_MLME_CM_ID);
-
-	if (cm_is_open_mode(vdev))
-		is_open_connection = true;
-
-	wlan_cm_roam_cfg_get_value(psoc, vdev_id, MBO_OCE_ENABLED_AP, &temp);
-	mbo_oce_enabled_ap = temp.uint_value;
-
 	abridge_flag = wlan_mlme_get_btm_abridge_flag(psoc);
 	if (!abridge_flag)
 		MLME_CLEAR_BIT(*btm_offload_config,
 			       BTM_OFFLOAD_CONFIG_BIT_7);
-	mlme_debug("Abridge flag: %d, btm offload: %u", abridge_flag,
-		   *btm_offload_config);
-
 	/*
 	 * If peer does not support PMF in case of OCE/MBO
 	 * Connection, Disable BTM offload to firmware.
 	 */
-	if (mbo_oce_enabled_ap && (!is_pmf_enabled && !is_open_connection))
+	if (cm_is_mbo_ap_without_pmf(psoc, vdev_id))
 		*btm_offload_config = 0;
 
-	mlme_debug("is_open:%d is_pmf_enabled %d btm_offload_cfg:%d for "QDF_MAC_ADDR_FMT,
-		   is_open_connection, is_pmf_enabled, *btm_offload_config,
-		   QDF_MAC_ADDR_REF(bssid));
+	mlme_debug("Abridge flag: %d, btm offload: %u", abridge_flag,
+		   *btm_offload_config);
 }
 
 /**
@@ -6287,7 +6297,8 @@ void cm_roam_scan_info_event(struct wlan_objmgr_psoc *psoc,
 			 ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ)
 			scan_band_mask = BIT(REG_BAND_5G) | BIT(REG_BAND_6G);
 
-		band_mask &= scan_band_mask;
+		if (scan_band_mask)
+			band_mask &= scan_band_mask;
 
 		for (i = 0; i < num_chan; i++) {
 			if (!wlan_is_valid_frequency(chan_freq[i],
@@ -7030,6 +7041,16 @@ cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
 
 	qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event));
 
+	/* The BTM req and BTM candidate event is logged twice
+	 * for both partial and full scan but the OTA frame is received
+	 * is received only once on the device. Restricting the
+	 * BTM req and BTM candidate event to be logged only for partial scan
+	 */
+	if (trigger_info->present &&
+	    trigger_info->scan_type == ROAM_STATS_SCAN_TYPE_FULL &&
+	    btm_data->disassoc_timer)
+		return status;
+
 	populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id,
 			  (uint64_t)btm_data->timestamp,
 			  NULL);

+ 9 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h

@@ -726,4 +726,13 @@ cm_roam_neigh_rpt_resp_event(struct wmi_neighbor_report_data *neigh_rpt,
 {
 }
 #endif /* FEATURE_CONNECTIVITY_LOGGING */
+
+/**
+ * cm_is_mbo_ap_without_pmf() - Check if the connected AP is MBO without PMF
+ * @psoc: PSOC pointer
+ * @vdev_id: vdev id
+ *
+ * Return: True if connected AP is MBO capable without PMF
+ */
+bool cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id);
 #endif /* _WLAN_CM_ROAM_OFFLOAD_H_ */

+ 2 - 3
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c

@@ -577,9 +577,8 @@ QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev,
 	    sync_ind->link_beacon_probe_resp_length) {
 		if (sync_ind->link_beacon_probe_resp_length >
 		    (QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET)) {
-			ie_len = sync_ind->link_beacon_probe_resp_length -
-					(QDF_IEEE80211_3ADDR_HDR_LEN +
-					 MAC_B_PR_SSID_OFFSET);
+			ie_len = MAX_MGMT_MPDU_LEN -
+			(QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET);
 		} else {
 			mlme_err("LFR3: MLO: vdev:%d Invalid link Beacon Length",
 				 vdev_id);

+ 17 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h

@@ -1386,6 +1386,16 @@ QDF_STATUS
 wlan_cm_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc,
 				struct roam_scan_candidate_frame *candidate);
 
+/**
+ * wlan_cm_is_mbo_ap_without_pmf() - Check if the connected AP is MBO without
+ *                                   PMF
+ * @psoc: PSOC pointer
+ * @vdev_id: vdev id
+ *
+ * Return: True if connected AP is MBO capable without PMF
+ */
+bool wlan_cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc,
+				   uint8_t vdev_id);
 #else
 static inline
 void wlan_cm_roam_activate_pcl_per_vdev(struct wlan_objmgr_psoc *psoc,
@@ -1654,6 +1664,13 @@ wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc)
 {
 	return 0;
 }
+
+static inline
+bool wlan_cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc,
+				   uint8_t vdev_id)
+{
+	return false;
+}
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD)

+ 5 - 0
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -4733,6 +4733,11 @@ wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc)
 	return mlme_obj->cfg.lfr.roam_high_rssi_delta;
 }
 
+bool wlan_cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc,
+				   uint8_t vdev_id)
+{
+	return cm_is_mbo_ap_without_pmf(psoc, vdev_id);
+}
 #else
 QDF_STATUS
 cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,

+ 3 - 0
components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c

@@ -1019,6 +1019,9 @@ mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
 		sta_ctx->assoc_rsp.ptr = NULL;
 		sta_ctx->assoc_rsp.len = 0;
 	}
+
+	sta_ctx->ml_partner_info = reassoc_rsp->ml_parnter_info;
+
 	sta_ctx->copied_reassoc_rsp = qdf_mem_malloc(
 			sizeof(struct wlan_cm_connect_resp));
 	if (!sta_ctx->copied_reassoc_rsp)

+ 40 - 23
components/wmi/src/wmi_unified_roam_tlv.c

@@ -2570,6 +2570,14 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	psoc = wmi_handle->soc->wmi_psoc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, synch_event->vdev_id,
+						    WLAN_MLME_SB_ID);
+	if (!vdev) {
+		wmi_err("For vdev:%d object is NULL", synch_event->vdev_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	if (synch_event->bcn_probe_rsp_len >
 		param_buf->num_bcn_probe_rsp_frame ||
 		synch_event->reassoc_req_len >
@@ -2585,19 +2593,10 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 		goto abort_roam;
 	}
 
-	psoc = wmi_handle->soc->wmi_psoc;
-	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, synch_event->vdev_id,
-						    WLAN_MLME_SB_ID);
-	if (!vdev) {
-		wmi_err("For vdev:%d object is NULL", synch_event->vdev_id);
-		status = QDF_STATUS_E_FAILURE;
-		goto abort_roam;
-	}
-
 	rso_cfg = wlan_cm_get_rso_config(vdev);
 	if (!rso_cfg) {
 		status = QDF_STATUS_E_FAILURE;
-		goto end;
+		goto abort_roam;
 	}
 
 	/*
@@ -2642,18 +2641,18 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 
 		if (synch_event->bcn_probe_rsp_len > WMI_SVC_MSG_MAX_SIZE) {
 			status = QDF_STATUS_E_FAILURE;
-			goto end;
+			goto abort_roam;
 		}
 		if (synch_event->reassoc_rsp_len >
 			(WMI_SVC_MSG_MAX_SIZE - synch_event->bcn_probe_rsp_len)) {
 			status = QDF_STATUS_E_FAILURE;
-			goto end;
+			goto abort_roam;
 		}
 		if (synch_event->reassoc_req_len >
 			WMI_SVC_MSG_MAX_SIZE - (synch_event->bcn_probe_rsp_len +
 			synch_event->reassoc_rsp_len)) {
 			status = QDF_STATUS_E_FAILURE;
-			goto end;
+			goto abort_roam;
 		}
 		roam_synch_data_len = bcn_probe_rsp_len +
 			reassoc_rsp_len + reassoc_req_len;
@@ -2666,7 +2665,7 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 			(sizeof(*synch_event) + sizeof(wmi_channel) +
 			 sizeof(wmi_key_material) + sizeof(uint32_t))) {
 			status = QDF_STATUS_E_FAILURE;
-			goto end;
+			goto abort_roam;
 		}
 		roam_synch_data_len += sizeof(struct roam_offload_synch_ind);
 	}
@@ -2675,21 +2674,22 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 	if (!roam_sync) {
 		QDF_ASSERT(roam_sync);
 		status = QDF_STATUS_E_NOMEM;
-		goto end;
+		goto abort_roam;
 	}
 
 	*roam_sync_ind = roam_sync;
 	status = wmi_fill_roam_sync_buffer(wmi_handle, vdev, rso_cfg,
 					   roam_sync, param_buf);
 
-end:
-	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
 abort_roam:
 	if (QDF_IS_STATUS_ERROR(status)) {
 		wmi_err("%d Failed to extract roam sync ind", status);
-		wlan_cm_roam_stop_req(psoc, synch_event->vdev_id,
-				      REASON_ROAM_SYNCH_FAILED);
+		wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
+					  synch_event->vdev_id,
+					  WLAN_ROAM_RSO_STOPPED,
+					  REASON_ROAM_SYNCH_FAILED);
 	}
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
 	return status;
 }
 
@@ -3756,16 +3756,33 @@ enum wlan_crypto_cipher_type wlan_wmi_cipher_to_crypto(uint8_t cipher)
 		return WLAN_CRYPTO_CIPHER_NONE;
 	case WMI_CIPHER_WEP:
 		return WLAN_CRYPTO_CIPHER_WEP;
-	case WMI_CIPHER_WAPI:
-		return WLAN_CRYPTO_CIPHER_WAPI_SMS4;
+	case WMI_CIPHER_TKIP:
+		return WLAN_CRYPTO_CIPHER_TKIP;
+	case WMI_CIPHER_AES_OCB:
+		return WLAN_CRYPTO_CIPHER_AES_OCB;
 	case WMI_CIPHER_AES_CCM:
 		return WLAN_CRYPTO_CIPHER_AES_CCM;
+	case WMI_CIPHER_WAPI:
+		return WLAN_CRYPTO_CIPHER_WAPI_SMS4;
+	case WMI_CIPHER_CKIP:
+		return WLAN_CRYPTO_CIPHER_CKIP;
 	case WMI_CIPHER_AES_CMAC:
 		return WLAN_CRYPTO_CIPHER_AES_CMAC;
-	case WMI_CIPHER_AES_GMAC:
-		return WLAN_CRYPTO_CIPHER_AES_GMAC;
 	case WMI_CIPHER_AES_GCM:
 		return WLAN_CRYPTO_CIPHER_AES_GCM;
+	case WMI_CIPHER_AES_GMAC:
+		return WLAN_CRYPTO_CIPHER_AES_GMAC;
+	case WMI_CIPHER_WAPI_GCM_SM4:
+		return WLAN_CRYPTO_CIPHER_WAPI_GCM4;
+	case WMI_CIPHER_BIP_CMAC_128:
+		return WLAN_CRYPTO_CIPHER_AES_CMAC;
+	case WMI_CIPHER_BIP_CMAC_256:
+		return	WLAN_CRYPTO_CIPHER_AES_CMAC_256;
+	case WMI_CIPHER_BIP_GMAC_128:
+		return	WLAN_CRYPTO_CIPHER_AES_GMAC;
+	case WMI_CIPHER_BIP_GMAC_256:
+		return WLAN_CRYPTO_CIPHER_AES_GMAC_256;
+
 	default:
 		return 0;
 	}

+ 4 - 0
configs/config_to_feature.h

@@ -2965,4 +2965,8 @@
 #define DP_RX_PEEK_MSDU_DONE_WAR (1)
 #endif
 
+#ifdef CONFIG_QDF_MAX_NO_OF_SAP_MODE
+#define QDF_MAX_NO_OF_SAP_MODE CONFIG_QDF_MAX_NO_OF_SAP_MODE
+#endif
+
 #endif /* CONFIG_TO_FEATURE_H */

+ 2 - 2
configs/default_defconfig

@@ -431,9 +431,9 @@ CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y
 
 #Disable the Export Symbol config
 ifeq ($(CONFIG_WLAN_MULTI_CHIP_SUPPORT), y)
-CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := n
-else
 CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y
+else
+CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := n
 endif
 
 CONFIG_QCACLD_FEATURE_GREEN_AP := y

+ 2 - 0
configs/kiwi_v2_defconfig

@@ -95,6 +95,8 @@ CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV := 4
 CONFIG_NUM_IPA_IFACE := 4
 CONFIG_MAX_CLIENTS_ALLOWED := 64
 
+CONFIG_QDF_MAX_NO_OF_SAP_MODE := 4
+
 ifeq ($(CONFIG_IPA_OFFLOAD), y)
 CONFIG_ENABLE_SMMU_S1_TRANSLATION := y
 CONFIG_SMMU_S1_UNMAP := y

+ 2 - 0
core/cds/src/cds_api.c

@@ -126,6 +126,8 @@ static struct ol_if_ops  dp_ol_if_ops = {
 	.peer_set_default_routing = target_if_peer_set_default_routing,
 	.peer_rx_reorder_queue_setup = target_if_peer_rx_reorder_queue_setup,
 	.peer_rx_reorder_queue_remove = target_if_peer_rx_reorder_queue_remove,
+	.peer_multi_rx_reorder_queue_setup =
+		target_if_peer_multi_rx_reorder_queue_setup,
 	.is_hw_dbs_capable = policy_mgr_is_dp_hw_dbs_capable,
 	.lro_hash_config = target_if_lro_hash_config,
 	.rx_invalid_peer = wma_rx_invalid_peer_ind,

+ 3 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -535,6 +535,7 @@ typedef enum {
 	NET_DEV_HOLD_START_PRE_CAC_TRANS = 60,
 	NET_DEV_HOLD_IS_ANY_STA_CONNECTED = 61,
 	NET_DEV_HOLD_GET_ADAPTER_BY_BSSID = 62,
+	NET_DEV_HOLD_ALLOW_NEW_INTF = 63,
 
 	/* Keep it at the end */
 	NET_DEV_HOLD_ID_MAX
@@ -749,6 +750,7 @@ struct hdd_mon_set_ch_info {
  * @ch_info: monitor mode channel information
  * @ap_supports_immediate_power_save: Does the current AP allow our STA
  *    to immediately go into power save?
+ * @user_cfg_chn_width: max channel bandwidth set by user space
  */
 struct hdd_station_ctx {
 	uint32_t reg_phymode;
@@ -757,6 +759,7 @@ struct hdd_station_ctx {
 	struct hdd_connection_info cache_conn_info;
 	struct hdd_mon_set_ch_info ch_info;
 	bool ap_supports_immediate_power_save;
+	uint8_t user_cfg_chn_width;
 };
 
 /**

+ 16 - 0
core/hdd/inc/wlan_hdd_power.h

@@ -362,6 +362,17 @@ void hdd_enable_ns_offload(struct hdd_adapter *adapter,
 void hdd_disable_ns_offload(struct hdd_adapter *adapter,
 			    struct wlan_objmgr_vdev *vdev,
 			    enum pmo_offload_trigger trigger);
+
+/**
+ * hdd_send_ps_config_to_fw() - Check user pwr save config set/reset PS
+ * @adapter: pointer to hdd adapter
+ *
+ * This function checks the power save configuration saved in MAC context
+ * and sends power save config to FW.
+ *
+ * Return: None
+ */
+void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter);
 #else /* WLAN_NS_OFFLOAD */
 static inline
 void hdd_enable_ns_offload(struct hdd_adapter *adapter,
@@ -376,6 +387,11 @@ void hdd_disable_ns_offload(struct hdd_adapter *adapter,
 			    enum pmo_offload_trigger trigger)
 {
 }
+
+static inline
+void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter)
+{
+}
 #endif /* WLAN_NS_OFFLOAD */
 
 /**

+ 89 - 36
core/hdd/src/wlan_hdd_cfg.c

@@ -2610,6 +2610,50 @@ static void hdd_restore_sme_config(struct wlan_hdd_link_info *link_info,
 	}
 }
 
+/**
+ * wlan_update_mlo_link_chn_width() - API to update mlo link chn width
+ * @adapter: the pointer to adapter
+ * @ch_width: channel width to update
+ * @link_id: mlo link id
+ *
+ * Get link id and channel bandwidth from user space and save in link_info.
+ * When link switch happen and host driver connect done, if the link change
+ * from standby to non-standby, ch_width will send to fw again.
+ *
+ * Return: QDF_STATUS
+ */
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+static struct wlan_hdd_link_info *
+wlan_update_mlo_link_chn_width(struct hdd_adapter *adapter,
+			       enum phy_ch_width ch_width,
+			       uint8_t link_id)
+{
+	struct wlan_hdd_link_info *link_info;
+	struct hdd_station_ctx *sta_ctx;
+
+	link_info = hdd_get_link_info_by_ieee_link_id(adapter, link_id);
+	if (!link_info)
+		return NULL;
+
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+
+	sta_ctx->user_cfg_chn_width = ch_width;
+	hdd_debug("save ch_width:%u to link_id:%u vdev_id:%u",
+		  ch_width, link_id, link_info->vdev_id);
+
+	return link_info;
+}
+#else
+static struct wlan_hdd_link_info *
+wlan_update_mlo_link_chn_width(struct hdd_adapter *adapter,
+			       enum phy_ch_width ch_width,
+			       uint8_t link_id)
+{
+	return NULL;
+}
+#endif
+
 int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 			     enum eSirMacHTChannelWidth chwidth,
 			     uint32_t bonding_mode, uint8_t link_id,
@@ -2617,11 +2661,10 @@ int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 {
 	struct hdd_context *hdd_ctx;
 	int ret;
-	enum phy_ch_width ch_width = CH_WIDTH_INVALID;
+	enum phy_ch_width ch_width;
 	struct wlan_objmgr_vdev *link_vdev;
 	struct wlan_objmgr_vdev *vdev;
 	struct wlan_hdd_link_info *link_info_t;
-	bool is_mlo_link = false;
 	uint8_t link_vdev_id;
 	enum QDF_OPMODE op_mode;
 	QDF_STATUS status;
@@ -2634,23 +2677,42 @@ int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 		return -EINVAL;
 	}
 
-	vdev = link_info->vdev;
+	op_mode = link_info->adapter->device_mode;
+	if (op_mode != QDF_STA_MODE) {
+		hdd_debug("vdev %d: op mode %d, CW update not supported",
+			  vdev_id, op_mode);
+		return -EINVAL;
+	}
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
 	if (!vdev) {
-		mlme_legacy_err("vdev %d: vdev not found", vdev_id);
-		return QDF_STATUS_E_FAILURE;
+		hdd_err("vdev %d: vdev not found", vdev_id);
+		return -EINVAL;
 	}
 
-	if (wlan_vdev_mlme_is_mlo_vdev(vdev) && link_id != 0xFF) {
-		link_vdev = mlo_get_vdev_by_link_id(vdev, link_id,
-						    WLAN_MLME_OBJMGR_ID);
-		if (!link_vdev) {
-			mlme_legacy_debug("vdev is null for the link id:%u",
-					  link_id);
-			wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
-			return QDF_STATUS_E_FAILURE;
+	ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth);
+
+	/**
+	 * Link_id check is for disconnect restore process.
+	 * Disconnect will not update channel bandwidth into cache struct.
+	 */
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	    link_id != WLAN_INVALID_LINK_ID) {
+		link_info_t = wlan_update_mlo_link_chn_width(link_info->adapter,
+							     ch_width, link_id);
+		if (!link_info_t) {
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+			return -EINVAL;
 		}
-		is_mlo_link = true;
-		link_vdev_id = wlan_vdev_get_id(link_vdev);
+
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+		link_vdev = hdd_objmgr_get_vdev_by_user(link_info_t,
+							WLAN_OSIF_ID);
+		if (!link_vdev)
+			return 0;
+
+		link_vdev_id = link_info_t->vdev_id;
 		status = wlan_mlme_get_bw_no_punct(hdd_ctx->psoc,
 						   link_vdev,
 						   wlan_vdev_mlme_get_des_chan(link_vdev),
@@ -2660,43 +2722,34 @@ int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 	} else {
 		link_vdev = vdev;
 		link_vdev_id = vdev_id;
-		mlme_legacy_debug("vdev mlme is not mlo vdev");
-	}
-
-	link_info_t = hdd_get_link_info_by_vdev(hdd_ctx, link_vdev_id);
-	if (!link_info_t) {
-		mlme_legacy_debug("vdev mlme is not mlo vdev");
-		return QDF_STATUS_E_FAILURE;
+		link_info_t = link_info;
 	}
 
 	if (ucfg_mlme_is_chwidth_with_notify_supported(hdd_ctx->psoc) &&
 	    hdd_cm_is_vdev_connected(link_info_t)) {
-		op_mode = wlan_vdev_mlme_get_opmode(vdev);
-		if (op_mode != QDF_STA_MODE) {
-			mlme_legacy_debug("vdev %d: op mode %d, CW update not supported",
-				          link_vdev_id, op_mode);
-			wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
-			return QDF_STATUS_E_NOSUPPORT;
-		}
-
 		ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth);
 		hdd_debug("vdev %d : process update ch width request to %d",
 			  link_vdev_id, ch_width);
-
 		status = ucfg_mlme_send_ch_width_update_with_notify(hdd_ctx->psoc,
 								    link_vdev,
 								    ch_width,
 								    link_vdev_id);
-		if (is_mlo_link)
-			wlan_objmgr_vdev_release_ref(link_vdev,
-						     WLAN_MLME_OBJMGR_ID);
-		if (QDF_IS_STATUS_ERROR(status))
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
 			return -EIO;
+		}
 		status = hdd_update_bss_rate_flags(link_info_t, hdd_ctx->psoc,
 						   ch_width);
-		if (QDF_IS_STATUS_ERROR(status))
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
 			return -EIO;
+		}
+
+		hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
+		return 0;
 	}
+	hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
 
 	ret = wma_cli_set_command(link_vdev_id, wmi_vdev_param_chwidth,
 				  chwidth, VDEV_CMD);

+ 76 - 41
core/hdd/src/wlan_hdd_cfg80211.c

@@ -11093,8 +11093,8 @@ static int hdd_set_channel_width(struct wlan_hdd_link_info *link_info,
 				 struct nlattr *tb[])
 {
 	int rem;
-	uint8_t nl80211_chwidth = 0xFF;
-	uint8_t link_id = 0xFF;
+	uint8_t nl80211_chwidth = CH_WIDTH_INVALID;
+	uint8_t link_id = WLAN_INVALID_LINK_ID;
 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1];
 	struct nlattr *curr_attr;
 	struct nlattr *chn_bd = NULL;
@@ -11149,7 +11149,7 @@ static int hdd_set_channel_width(struct wlan_hdd_link_info *link_info,
 		}
 	}
 
-	if (link_id != 0xFF)
+	if (link_id != WLAN_INVALID_LINK_ID)
 		goto set_chan_width;
 
 skip_mlo:
@@ -11166,7 +11166,9 @@ skip_mlo:
 		hdd_err("Invalid channel width %u", chwidth);
 		return -EINVAL;
 	}
+
 set_chan_width:
+	hdd_debug("channel width:%u, link_id:%u", chwidth, link_id);
 	return hdd_set_mac_chan_width(link_info, chwidth, link_id, true);
 }
 
@@ -12581,6 +12583,7 @@ static int hdd_get_channel_width(struct wlan_hdd_link_info *link_info,
  *
  * Return: 0 on success; error number otherwise
  */
+#ifdef WLAN_FEATURE_11BE_MLO
 static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
 				     struct sk_buff *skb,
 				     const struct nlattr *attr)
@@ -12592,7 +12595,10 @@ static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
 	uint32_t link_id = 0;
 	struct wlan_objmgr_vdev *vdev, *link_vdev;
 	struct wlan_channel *bss_chan;
+	struct wlan_hdd_link_info *link_info_t;
+	struct hdd_station_ctx *sta_ctx;
 	uint8_t nl80211_chwidth;
+	uint8_t chn_width;
 	int8_t ret = 0;
 
 	chwidth = wma_cli_get_command(link_info->vdev_id,
@@ -12606,46 +12612,64 @@ static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
 	if (!vdev)
 		return -EINVAL;
 
-	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
-		mlo_bd_info = nla_nest_start(skb, CONFIG_MLO_LINKS);
-		for (link_id = 0; link_id < WLAN_MAX_LINK_ID; link_id++) {
-			link_vdev = mlo_get_vdev_by_link_id(vdev, link_id,
-							    WLAN_OSIF_ID);
-			if (!link_vdev)
-				continue;
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		hdd_err("not mlo vdev");
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+		return -EINVAL;
+	}
 
-			mlo_bd = nla_nest_start(skb, i);
-			if (!mlo_bd) {
-				hdd_err("nla_nest_start fail");
-				ret = -EINVAL;
-				goto end;
-			}
+	mlo_bd_info = nla_nest_start(skb, CONFIG_MLO_LINKS);
+	hdd_adapter_for_each_link_info(link_info->adapter, link_info_t) {
+		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info_t);
+		if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID)
+			continue;
+
+		link_id = sta_ctx->conn_info.ieee_link_id;
+
+		mlo_bd = nla_nest_start(skb, i);
+		if (!mlo_bd) {
+			hdd_err("nla_nest_start fail");
+			ret = -EINVAL;
+			goto end;
+		}
+
+		if (nla_put_u8(skb, CONFIG_MLO_LINK_ID, link_id)) {
+			hdd_err("nla_put failure");
+			ret = -EINVAL;
+			goto end;
+		}
+
+		link_vdev = mlo_get_vdev_by_link_id(vdev, link_id,
+						    WLAN_OSIF_ID);
+
+		if (link_vdev) {
 			bss_chan = wlan_vdev_mlme_get_bss_chan(link_vdev);
 			if (!bss_chan) {
 				hdd_err("fail to get bss_chan info");
 				ret = -EINVAL;
 				goto end;
 			}
-			if (nla_put_u8(skb, CONFIG_MLO_LINK_ID, link_id)) {
-				hdd_err("nla_put failure");
-				ret = -EINVAL;
-				goto end;
-			}
+			chn_width = bss_chan->ch_width;
+		} else if (link_info_t->vdev_id == WLAN_INVALID_VDEV_ID) {
+			chn_width = sta_ctx->user_cfg_chn_width;
+		} else {
+			chn_width = CH_WIDTH_INVALID;
+		}
 
-			nl80211_chwidth = hdd_phy_chwidth_to_nl80211_chwidth(bss_chan->ch_width);
-			if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH,
-				       nl80211_chwidth)) {
-				hdd_err("nla_put failure");
-				ret = -EINVAL;
-				goto end;
-			}
-			nla_nest_end(skb, mlo_bd);
-			i++;
-			hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
+		hdd_debug("get link_id:%u ch width:%u", link_id, chn_width);
+
+		nl80211_chwidth = hdd_phy_chwidth_to_nl80211_chwidth(chn_width);
+		if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH, nl80211_chwidth)) {
+			hdd_err("nla_put failure");
+			ret = -EINVAL;
+			goto end;
 		}
-		nla_nest_end(skb, mlo_bd_info);
-	}
+		nla_nest_end(skb, mlo_bd);
+		i++;
 
+		hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
+	}
+	nla_nest_end(skb, mlo_bd_info);
 end:
 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
 
@@ -12654,6 +12678,14 @@ end:
 
 	return ret;
 }
+#else
+static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
+				     struct sk_buff *skb,
+				     const struct nlattr *attr)
+{
+	return 0;
+}
+#endif
 
 /**
  * hdd_get_dynamic_bw() - Get dynamic bandwidth disabled / enabled
@@ -20852,6 +20884,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	FEATURE_AFC_VENDOR_COMMANDS
 	FEATURE_LL_LT_SAP_VENDOR_COMMANDS
 	FEATURE_TX_LATENCY_STATS_COMMANDS
+	FEATURE_REGULATORY_TPC_INFO_VENDOR_COMMANDS
 };
 
 struct hdd_context *hdd_cfg80211_wiphy_alloc(void)
@@ -21907,20 +21940,22 @@ static char *wlan_hdd_iface_debug_string(uint32_t iface_type)
 static void wlan_hdd_dump_iface_combinations(uint32_t num,
 			const struct ieee80211_iface_combination *combination)
 {
-	int i, j;
+	int i, j, k;
 	char buf[IFACE_DUMP_SIZE] = {0};
 	uint8_t len = 0;
 
 	hdd_debug("max combinations %d", num);
 
 	for (i = 0; i < num; i++) {
-		for (j = 0; j < combination[i].max_interfaces; j++) {
-			if (combination[i].limits[j].types)
-				len += qdf_scnprintf(buf + len,
-						     IFACE_DUMP_SIZE - len,
-						     " + %s",
-					wlan_hdd_iface_debug_string(
-					combination[i].limits[j].types));
+		for (j = 0; j < combination[i].n_limits; j++) {
+			for (k = 0; k < combination[i].limits[j].max; k++) {
+				if (combination[i].limits[j].types)
+					len += qdf_scnprintf(buf + len,
+					       IFACE_DUMP_SIZE - len,
+					       k == 0 && j == 0 ? "%s" : "+%s",
+					       wlan_hdd_iface_debug_string(
+					       combination[i].limits[j].types));
+			}
 		}
 
 		hdd_nofl_debug("iface combination[%d]: %s", i, buf);

+ 65 - 1
core/hdd/src/wlan_hdd_cm_connect.c

@@ -1516,6 +1516,62 @@ static void hdd_set_immediate_power_save(struct hdd_adapter *adapter,
 }
 #endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+static QDF_STATUS
+hdd_cm_mlme_send_standby_link_chn_width(struct hdd_adapter *adapter,
+					struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_hdd_link_info *link_info;
+	struct hdd_station_ctx *sta_ctx;
+	uint8_t link_id = wlan_vdev_get_link_id(vdev);
+	uint8_t ch_width;
+	enum phy_ch_width connection_ch_width = CH_WIDTH_INVALID;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		hdd_err("Failed to get PSOC Object");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	link_info = hdd_get_link_info_by_ieee_link_id(adapter, link_id);
+	if (!link_info) {
+		hdd_err("Link info not found by linkid:%u", link_id);
+		return QDF_STATUS_E_INVAL;
+	}
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+	ch_width = sta_ctx->user_cfg_chn_width;
+
+	wlan_mlme_get_sta_ch_width(vdev, &connection_ch_width);
+
+	if (ch_width == CH_WIDTH_INVALID) {
+		hdd_debug("no cached bandwidth for the link %u", link_id);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (ch_width == connection_ch_width) {
+		hdd_debug("user config max bd same as connection ch bw:%u",
+			  ch_width);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	hdd_debug("send vdev id:%u, chwidth:%u", link_info->vdev_id,
+		  ch_width);
+
+	wlan_mlme_send_ch_width_update_with_notify(psoc, vdev,
+						   link_info->vdev_id,
+						   ch_width);
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS
+hdd_cm_mlme_send_standby_link_chn_width(struct hdd_adapter *adapter,
+					struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 static void
 hdd_cm_connect_success_pre_user_update(struct wlan_objmgr_vdev *vdev,
 				       struct wlan_cm_connect_resp *rsp)
@@ -1537,7 +1593,7 @@ hdd_cm_connect_success_pre_user_update(struct wlan_objmgr_vdev *vdev,
 	struct hdd_adapter *assoc_link_adapter;
 	bool is_immediate_power_save;
 	struct wlan_hdd_link_info *link_info;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_E_INVAL;
 	bool alt_pipe;
 
 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
@@ -1605,6 +1661,11 @@ hdd_cm_connect_success_pre_user_update(struct wlan_objmgr_vdev *vdev,
 
 	hdd_cm_handle_assoc_event(vdev, rsp->bssid.bytes);
 
+	if (ucfg_cm_is_link_switch_connect_resp(rsp)) {
+		if (hdd_cm_mlme_send_standby_link_chn_width(adapter, vdev))
+			hdd_debug("send standby link chn width fail");
+	}
+
 	/*
 	 * check update hdd_send_update_beacon_ies_event,
 	 * hdd_send_ft_assoc_response,
@@ -1773,6 +1834,9 @@ hdd_cm_connect_success_post_user_update(struct wlan_objmgr_vdev *vdev,
 	}
 	ucfg_dp_periodic_sta_stats_start(vdev);
 	wlan_twt_concurrency_update(hdd_ctx);
+
+	if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev))
+		hdd_send_ps_config_to_fw(adapter);
 }
 
 static void hdd_cm_connect_success(struct wlan_objmgr_vdev *vdev,

+ 21 - 12
core/hdd/src/wlan_hdd_hostapd.c

@@ -2060,10 +2060,27 @@ hdd_hostapd_check_channel_post_csa(struct hdd_context *hdd_ctx,
 	struct hdd_ap_ctx *ap_ctx;
 	uint8_t sta_cnt, sap_cnt;
 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	struct sap_context *sap_ctx;
+	bool ch_valid;
 
 	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink);
+	sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink);
+	if (!sap_ctx) {
+		hdd_err("sap ctx is null");
+		return;
+	}
+
+	/*
+	 * During CSA, it might be possible that ch avoidance event to
+	 * avoid the sap frequency is received. So, check after CSA,
+	 * whether sap frequency is safe if not restart sap to a safe
+	 * channel.
+	 */
+	ch_valid =
+	wlansap_validate_channel_post_csa(hdd_ctx->mac_handle,
+					  sap_ctx);
 	if (ap_ctx->sap_context->csa_reason ==
-	    CSA_REASON_UNSAFE_CHANNEL)
+	    CSA_REASON_UNSAFE_CHANNEL || !ch_valid)
 		qdf_status = hdd_unsafe_channel_restart_sap(hdd_ctx);
 	else if (ap_ctx->sap_context->csa_reason == CSA_REASON_DCS)
 		qdf_status = hdd_dcs_hostapd_set_chan(
@@ -7736,16 +7753,6 @@ void wlan_hdd_configure_twt_responder(struct hdd_context *hdd_ctx,
 {}
 #endif
 
-static inline uint32_t
-wlan_util_get_centre_freq(struct wlan_hdd_link_info *link_info)
-{
-	struct wlan_channel *chan;
-
-	chan = wlan_vdev_get_active_channel(link_info->vdev);
-
-	return chan->ch_freq;
-}
-
 #ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT
 static inline struct cfg80211_chan_def
 wlan_util_get_chan_def(struct wireless_dev *wdev, unsigned int link_id)
@@ -7814,6 +7821,8 @@ static void hdd_update_param_chandef(struct wlan_hdd_link_info *link_info,
 	struct wlan_channel *chan;
 
 	chan = wlan_vdev_get_active_channel(link_info->vdev);
+	if (!chan)
+		return;
 
 	hdd_create_chandef(link_info->adapter, chan, chandef);
 }
@@ -8166,7 +8175,7 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 
 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
 
-		if (wlan_util_get_centre_freq(link_info) !=
+		if (wlan_get_operation_chan_freq(link_info->vdev) !=
 				params->chandef.chan->center_freq)
 			hdd_update_param_chandef(link_info, &params->chandef);
 

+ 198 - 10
core/hdd/src/wlan_hdd_main.c

@@ -249,6 +249,7 @@
 #include <wlan_mlo_mgr_link_switch.h>
 #include "cdp_txrx_mon.h"
 #include "os_if_ll_sap.h"
+#include "wlan_p2p_ucfg_api.h"
 
 #ifdef MULTI_CLIENT_LL_SUPPORT
 #define WLAM_WLM_HOST_DRIVER_PORT_ID 0xFFFFFF
@@ -2690,6 +2691,9 @@ static void hdd_lpc_enable_powersave(struct hdd_context *hdd_ctx)
 
 	ucfg_fwol_configure_global_params(hdd_ctx->psoc, hdd_ctx->pdev);
 
+	if (wma_enable_disable_imps(hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id, 1))
+		hdd_err("IMPS feature enable failed");
+
 	sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE);
 	if (!sta_adapter) {
 		hdd_debug("STA adapter does not exist");
@@ -2708,6 +2712,9 @@ static void hdd_lpc_disable_powersave(struct hdd_context *hdd_ctx)
 
 	ucfg_fwol_set_ilp_config(hdd_ctx->psoc, hdd_ctx->pdev, 0);
 
+	if (wma_enable_disable_imps(hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id, 0))
+		hdd_err("IMPS feature disable failed");
+
 	sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE);
 	if (!sta_adapter) {
 		hdd_err("STA adapter does not exist");
@@ -3962,6 +3969,8 @@ static bool hdd_is_chan_switch_in_progress(void)
 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_CHAN_SWITCH_IN_PROGRESS;
 	struct hdd_ap_ctx *ap_ctx;
 	struct wlan_hdd_link_info *link_info;
+	bool is_restart;
+	struct wlan_objmgr_vdev *vdev;
 
 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
 					   dbgid) {
@@ -3971,7 +3980,21 @@ static bool hdd_is_chan_switch_in_progress(void)
 
 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
 			ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
-			if (qdf_atomic_read(&ap_ctx->ch_switch_in_progress)) {
+			vdev = hdd_objmgr_get_vdev_by_user(link_info,
+							   WLAN_OSIF_ID);
+			if (!vdev)
+				continue;
+			is_restart = false;
+			if (wlan_vdev_is_restart_progress(vdev) ==
+			    QDF_STATUS_SUCCESS) {
+				hdd_debug("vdev: %d restart in progress",
+					  wlan_vdev_get_id(vdev));
+				is_restart = true;
+			}
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+			if (is_restart ||
+			    qdf_atomic_read(&ap_ctx->ch_switch_in_progress)) {
 				hdd_debug("channel switch progress for vdev_id %d",
 					  link_info->vdev_id);
 				hdd_adapter_dev_put_debug(adapter, dbgid);
@@ -5760,9 +5783,9 @@ bool hdd_is_dynamic_set_mac_addr_allowed(struct hdd_adapter *adapter)
 			hdd_info_rl("VDEV is not in disconnected state, set mac address isn't supported");
 			return false;
 		}
-		fallthrough;
-	case QDF_P2P_DEVICE_MODE:
 		return true;
+	case QDF_P2P_DEVICE_MODE:
+		return ucfg_is_p2p_device_dynamic_set_mac_addr_supported(adapter->hdd_ctx->psoc);
 	case QDF_SAP_MODE:
 		if (test_bit(SOFTAP_BSS_STARTED,
 			     &adapter->deflink->link_flags)) {
@@ -5787,7 +5810,7 @@ int hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info,
 	void *cookie;
 	bool update_mld_addr;
 	uint32_t fw_resp_status;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct osif_request *request;
 	struct wlan_objmgr_vdev *vdev;
 	struct hdd_adapter *adapter = link_info->adapter;
@@ -5812,6 +5835,8 @@ int hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info,
 	}
 	request = osif_request_alloc(&params);
 	if (!request) {
+		hdd_err("request alloc fail");
+		status = QDF_STATUS_E_NOMEM;
 		ret = -ENOMEM;
 		goto status_ret;
 	}
@@ -5874,12 +5899,8 @@ int hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info,
 					  update_self_peer, update_mld_addr,
 					  ret);
 
-	if (QDF_IS_STATUS_ERROR(status))
-		ret = qdf_status_to_os_return(status);
-
 status_ret:
 	if (QDF_IS_STATUS_ERROR(status)) {
-		hdd_err("Failed to attach CDP vdev. status:%d", status);
 		ret = qdf_status_to_os_return(status);
 		goto allow_suspend;
 	} else if (!ret) {
@@ -7416,9 +7437,12 @@ hdd_vdev_configure_max_tdls_params(struct wlan_objmgr_psoc *psoc,
 	uint16_t max_peer_count;
 	bool target_bigtk_support = false;
 
-	/* Max peer can be tdls peers + self peer + bss peer */
+	/*
+	 * Max peer can be tdls peers + self peer + bss peer +
+	 * temp bss peer for roaming create/delete peer at same time
+	 */
 	max_peer_count = cfg_tdls_get_max_peer_count(psoc);
-	max_peer_count += 2;
+	max_peer_count += 3;
 	wlan_vdev_set_max_peer_count(vdev, max_peer_count);
 
 	ucfg_mlme_get_bigtk_support(psoc, &target_bigtk_support);
@@ -7786,6 +7810,7 @@ static char *net_dev_ref_debug_string_from_id(wlan_net_dev_ref_dbgid dbgid)
 		"NET_DEV_HOLD_START_PRE_CAC_TRANS",
 		"NET_DEV_HOLD_IS_ANY_STA_CONNECTED",
 		"NET_DEV_HOLD_GET_ADAPTER_BY_BSSID",
+		"NET_DEV_HOLD_ALLOW_NEW_INTF",
 		"NET_DEV_HOLD_ID_MAX"};
 	int32_t num_dbg_strings = QDF_ARRAY_SIZE(strings);
 
@@ -8117,6 +8142,166 @@ void hdd_adapter_update_mlo_mgr_mac_addr(struct hdd_adapter *adapter)
 	mlo_mgr_update_link_info_mac_addr(adapter->deflink->vdev, &link_mac);
 }
 
+#ifdef FEATURE_COEX
+/**
+ * hdd_send_coex_config_params() - Send coex config params to FW
+ * @hdd_ctx: HDD context
+ * @adapter: Primary adapter context
+ *
+ * This function is used to send all coex config related params to FW
+ *
+ * Return: 0 on success and -EINVAL on failure
+ */
+static int hdd_send_coex_config_params(struct hdd_context *hdd_ctx,
+				       struct hdd_adapter *adapter)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct coex_config_params coex_cfg_params = {0};
+	struct coex_multi_config *coex_multi_cfg = NULL;
+	struct wlan_fwol_coex_config config = {0};
+	struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc;
+	enum coex_btc_chain_mode btc_chain_mode;
+	QDF_STATUS status;
+	uint32_t i = 0;
+
+	if (!adapter) {
+		hdd_err("adapter is invalid");
+		goto err;
+	}
+
+	if (!psoc) {
+		hdd_err("HDD psoc is invalid");
+		goto err;
+	}
+
+	status = ucfg_fwol_get_coex_config_params(psoc, &config);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Unable to get coex config params");
+		goto err;
+	}
+
+	coex_multi_cfg = qdf_mem_malloc(sizeof(*coex_multi_cfg));
+	if (!coex_multi_cfg)
+		goto err;
+
+	coex_multi_cfg->vdev_id = adapter->deflink->vdev_id;
+
+	coex_multi_cfg->cfg_items[i].config_type = WMI_COEX_CONFIG_TX_POWER;
+	coex_multi_cfg->cfg_items[i].config_arg1 = config.max_tx_power_for_btc;
+
+	wma_nofl_debug("TXP[W][send_coex_cfg]: %d",
+		       config.max_tx_power_for_btc);
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+	coex_multi_cfg->cfg_items[i].config_type =
+					WMI_COEX_CONFIG_HANDOVER_RSSI;
+	coex_multi_cfg->cfg_items[i].config_arg1 =
+					config.wlan_low_rssi_threshold;
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+	coex_multi_cfg->cfg_items[i].config_type = WMI_COEX_CONFIG_BTC_MODE;
+
+	/* Modify BTC_MODE according to BTC_CHAIN_MODE */
+	status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &btc_chain_mode);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to get btc chain mode");
+		btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED;
+	}
+
+	if (btc_chain_mode <= WLAN_COEX_BTC_CHAIN_MODE_HYBRID)
+		coex_multi_cfg->cfg_items[i].config_arg1 = btc_chain_mode;
+	else
+		coex_multi_cfg->cfg_items[i].config_arg1 = config.btc_mode;
+
+	hdd_debug("Configured BTC mode is %d, BTC chain mode is 0x%x, set BTC mode to %d",
+		  config.btc_mode, btc_chain_mode,
+		  coex_multi_cfg->cfg_items[i].config_arg1);
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+	coex_multi_cfg->cfg_items[i].config_type =
+				WMI_COEX_CONFIG_ANTENNA_ISOLATION;
+	coex_multi_cfg->cfg_items[i].config_arg1 = config.antenna_isolation;
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+	coex_multi_cfg->cfg_items[i].config_type =
+				WMI_COEX_CONFIG_BT_LOW_RSSI_THRESHOLD;
+	coex_multi_cfg->cfg_items[i].config_arg1 = config.bt_low_rssi_threshold;
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+	coex_multi_cfg->cfg_items[i].config_type =
+				WMI_COEX_CONFIG_BT_INTERFERENCE_LEVEL;
+	coex_multi_cfg->cfg_items[i].config_arg1 =
+				config.bt_interference_low_ll;
+	coex_multi_cfg->cfg_items[i].config_arg2 =
+				config.bt_interference_low_ul;
+	coex_multi_cfg->cfg_items[i].config_arg3 =
+				config.bt_interference_medium_ll;
+	coex_multi_cfg->cfg_items[i].config_arg4 =
+				config.bt_interference_medium_ul;
+	coex_multi_cfg->cfg_items[i].config_arg5 =
+				config.bt_interference_high_ll;
+	coex_multi_cfg->cfg_items[i].config_arg6 =
+				config.bt_interference_high_ul;
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+	if (wlan_hdd_mpta_helper_enable(&coex_cfg_params, &config))
+		goto err;
+
+	coex_multi_cfg->cfg_items[i].config_type =
+				WMI_COEX_CONFIG_BT_SCO_ALLOW_WLAN_2G_SCAN;
+	coex_multi_cfg->cfg_items[i].config_arg1 =
+				config.bt_sco_allow_wlan_2g_scan;
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+	coex_multi_cfg->cfg_items[i].config_type =
+				WMI_COEX_CONFIG_LE_SCAN_POLICY;
+	coex_multi_cfg->cfg_items[i].config_arg1 = config.ble_scan_coex_policy;
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+
+#ifdef FEATURE_COEX_TPUT_SHAPING_CONFIG
+	coex_multi_cfg->cfg_items[i].config_type =
+				WMI_COEX_CONFIG_ENABLE_TPUT_SHAPING;
+	coex_multi_cfg->cfg_items[i].config_arg1 =
+				config.coex_tput_shaping_enable;
+
+	if (++i > COEX_MULTI_CONFIG_MAX_CNT)
+		goto err;
+#endif
+
+	coex_multi_cfg->num_configs = i;
+
+	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_COEX_ID);
+	if (!vdev) {
+		hdd_err("vdev is null");
+		goto err;
+	}
+
+	ucfg_coex_send_multi_config(vdev, coex_multi_cfg);
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_COEX_ID);
+	qdf_mem_free(coex_multi_cfg);
+
+	return 0;
+err:
+	qdf_mem_free(coex_multi_cfg);
+	return -EINVAL;
+}
+#else
 /**
  * hdd_send_coex_config_params() - Send coex config params to FW
  * @hdd_ctx: HDD context
@@ -8267,6 +8452,7 @@ static int hdd_send_coex_config_params(struct hdd_context *hdd_ctx,
 err:
 	return -EINVAL;
 }
+#endif
 
 /**
  * hdd_send_coex_traffic_shaping_mode() - Send coex traffic shaping mode
@@ -9277,6 +9463,7 @@ static void hdd_stop_and_cleanup_ndi(struct wlan_hdd_link_info *link_info)
 	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
 
+	hdd_destroy_adapter_sysfs_files(adapter);
 	/* For NDI do not use roam_profile */
 	INIT_COMPLETION(adapter->disconnect_comp_var);
 	hdd_peer_cleanup(link_info);
@@ -14739,6 +14926,7 @@ void hdd_adapter_reset_station_ctx(struct hdd_adapter *adapter)
 		qdf_mem_zero(&sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE);
 
 		hdd_cm_clear_ieee_link_id(link_info);
+		sta_ctx->user_cfg_chn_width = CH_WIDTH_INVALID;
 	}
 }
 

+ 2 - 0
core/hdd/src/wlan_hdd_nan_datapath.c

@@ -45,6 +45,7 @@
 #include <cdp_txrx_misc.h>
 #include "wlan_fwol_ucfg_api.h"
 #include "wlan_dp_ucfg_api.h"
+#include "wlan_hdd_sysfs.h"
 
 /**
  * hdd_nan_datapath_target_config() - Configure NAN datapath features
@@ -861,6 +862,7 @@ int hdd_ndi_start(const char *iface_name, uint16_t transaction_id)
 		goto err_handler;
 	}
 
+	hdd_create_adapter_sysfs_files(adapter);
 	hdd_exit();
 	return 0;
 

+ 37 - 0
core/hdd/src/wlan_hdd_p2p.c

@@ -642,6 +642,40 @@ int hdd_set_p2p_ps(struct net_device *dev, void *msgData)
 	return wlan_hdd_set_power_save(adapter, &noa);
 }
 
+/**
+ * hdd_allow_new_intf() - Allow new intf created or not
+ * @hdd_ctx: hdd context
+ * @mode: qdf opmode of new interface
+ *
+ * Return: true if allowed, otherwise false
+ */
+static bool hdd_allow_new_intf(struct hdd_context *hdd_ctx,
+			       enum QDF_OPMODE mode)
+{
+	struct hdd_adapter *adapter = NULL;
+	struct hdd_adapter *next_adapter = NULL;
+	uint8_t num_active_adapter = 0;
+
+	if (mode != QDF_SAP_MODE)
+		return true;
+
+	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
+					   NET_DEV_HOLD_ALLOW_NEW_INTF) {
+		if (hdd_is_interface_up(adapter) &&
+		    adapter->device_mode == mode)
+			num_active_adapter++;
+
+		hdd_adapter_dev_put_debug(adapter,
+					  NET_DEV_HOLD_ALLOW_NEW_INTF);
+	}
+
+	if (num_active_adapter >= QDF_MAX_NO_OF_SAP_MODE)
+		hdd_err("sap max allowed intf %d, curr %d",
+			QDF_MAX_NO_OF_SAP_MODE, num_active_adapter);
+
+	return num_active_adapter < QDF_MAX_NO_OF_SAP_MODE;
+}
+
 /**
  * __wlan_hdd_add_virtual_intf() - Add virtual interface
  * @wiphy: wiphy pointer
@@ -704,6 +738,9 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
 	if (wlan_hdd_is_mon_concurrency())
 		return ERR_PTR(-EINVAL);
 
+	if (!hdd_allow_new_intf(hdd_ctx, mode))
+		return ERR_PTR(-EOPNOTSUPP);
+
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
 		   TRACE_CODE_HDD_ADD_VIRTUAL_INTF,
 		   NO_SESSION, type);

+ 1 - 10
core/hdd/src/wlan_hdd_power.c

@@ -679,16 +679,7 @@ static inline void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter)
 {}
 #endif
 
-/**
- * hdd_send_ps_config_to_fw() - Check user pwr save config set/reset PS
- * @adapter: pointer to hdd adapter
- *
- * This function checks the power save configuration saved in MAC context
- * and sends power save config to FW.
- *
- * Return: None
- */
-static void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter)
+void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter)
 {
 	struct hdd_context *hdd_ctx;
 	bool is_mlo_vdev;

+ 4 - 4
core/hdd/src/wlan_hdd_stats.c

@@ -7458,10 +7458,10 @@ static void wlan_hdd_update_rssi(struct wlan_hdd_link_info *link_info,
 	}
 
 	/* If RSSi is reported as positive then it is invalid */
-	if (link_info->rssi > 0) {
-		hdd_debug_rl("RSSI invalid %d", link_info->rssi);
-		link_info->rssi = 0;
-		link_info->hdd_stats.summary_stat.rssi = 0;
+	if (link_info->rssi >= 0) {
+		hdd_debug_rl("Invalid RSSI %d, reset to -1", link_info->rssi);
+		link_info->rssi = -1;
+		link_info->hdd_stats.summary_stat.rssi = -1;
 	}
 
 	sinfo->signal = link_info->rssi;

+ 20 - 0
core/hdd/src/wlan_hdd_sysfs.c

@@ -1187,6 +1187,20 @@ void hdd_sysfs_create_ftm_adapter_root_obj(struct hdd_adapter *adapter)
 	hdd_sysfs_unit_test_target_create(adapter);
 }
 
+static void
+hdd_sysfs_create_ndi_adapter_root_obj(struct hdd_adapter *adapter)
+{
+	hdd_sysfs_unit_test_target_create(adapter);
+	hdd_sysfs_11be_rate_create(adapter);
+}
+
+static void
+hdd_sysfs_destroy_ndi_adapter_root_obj(struct hdd_adapter *adapter)
+{
+	hdd_sysfs_11be_rate_destroy(adapter);
+	hdd_sysfs_unit_test_target_destroy(adapter);
+}
+
 void hdd_create_adapter_sysfs_files(struct hdd_adapter *adapter)
 {
 	int device_mode = adapter->device_mode;
@@ -1212,6 +1226,9 @@ void hdd_create_adapter_sysfs_files(struct hdd_adapter *adapter)
 	case QDF_FTM_MODE:
 		hdd_sysfs_create_ftm_adapter_root_obj(adapter);
 		break;
+	case QDF_NDI_MODE:
+		hdd_sysfs_create_ndi_adapter_root_obj(adapter);
+		break;
 	default:
 		break;
 	}
@@ -1247,6 +1264,9 @@ void hdd_destroy_adapter_sysfs_files(struct hdd_adapter *adapter)
 	case QDF_FTM_MODE:
 		hdd_sysfs_destroy_ftm_adapter_root_obj(adapter);
 		break;
+	case QDF_NDI_MODE:
+		hdd_sysfs_destroy_ndi_adapter_root_obj(adapter);
+		break;
 	default:
 		break;
 	}

+ 256 - 0
core/hdd/src/wlan_hdd_tx_power.c

@@ -32,6 +32,7 @@
 #include <linux/if_ether.h>
 #include <wma_api.h>
 #include <wlan_hdd_tx_power.h>
+#include "wlan_hdd_object_manager.h"
 
 #define MAX_TXPOWER_SCALE 4
 
@@ -211,3 +212,258 @@ int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy,
 	return errno;
 }
 
+static uint32_t get_default_tpc_info_vendor_sbk_len(void)
+{
+	uint32_t skb_len;
+
+	/* QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY */
+	skb_len = nla_total_size(sizeof(u32));
+	/* QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_TX_POWER */
+	skb_len += nla_total_size(sizeof(s8));
+	skb_len = nla_total_size(skb_len) * MAX_NUM_PWR_LEVEL;
+	skb_len = nla_total_size(skb_len);
+
+	/* QCA_WLAN_VENDOR_ATTR_TPC_BSSID */
+	skb_len += nla_total_size(QDF_MAC_ADDR_SIZE);
+	/* QCA_WLAN_VENDOR_ATTR_TPC_PSD_POWER */
+	skb_len += nla_total_size(sizeof(u8));
+	/* QCA_WLAN_VENDOR_ATTR_TPC_EIRP_POWER */
+	skb_len += nla_total_size(sizeof(s8));
+	/* QCA_WLAN_VENDOR_ATTR_TPC_POWER_TYPE_6GHZ */
+	skb_len += nla_total_size(sizeof(u8));
+	/* QCA_WLAN_VENDOR_ATTR_TPC_AP_CONSTRAINT_POWER */
+	skb_len += nla_total_size(sizeof(u8));
+
+	skb_len = nla_total_size(skb_len) * WLAN_MAX_ML_BSS_LINKS;
+	skb_len = nla_total_size(skb_len) + NLMSG_HDRLEN;
+
+	return skb_len;
+}
+
+static int
+__wlan_hdd_cfg80211_get_reg_tpc_info(struct wiphy *wiphy,
+				     struct wireless_dev *wdev,
+				     const void *data,
+				     int data_len)
+{
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	struct net_device *dev = wdev->netdev;
+	struct hdd_adapter *adapter;
+	int ret;
+	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev;
+	int num_of_links = 0;
+	struct qdf_mac_addr link_bssid[WLAN_MAX_ML_BSS_LINKS];
+	struct reg_tpc_power_info reg_tpc_info[WLAN_MAX_ML_BSS_LINKS];
+	struct sk_buff *reply_skb = NULL;
+	uint32_t skb_len, i, j;
+	struct wlan_hdd_link_info *link_info;
+	struct nlattr *tpc_links_attr, *tpc_attr, *levels_attr, *tpc_level;
+	int attr_id;
+	struct chan_power_info *chan_power_info;
+
+	hdd_enter_dev(dev);
+
+	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
+		hdd_err("Command not allowed in FTM mode");
+		return -EPERM;
+	}
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	if (!adapter) {
+		hdd_err("adapter null");
+		return -EPERM;
+	}
+
+	if (adapter->device_mode != QDF_STA_MODE) {
+		hdd_err("device mode %d not support", adapter->device_mode);
+		return -EPERM;
+	}
+
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		if (num_of_links >= WLAN_MAX_ML_BSS_LINKS)
+			break;
+		if (link_info->vdev_id == WLAN_INVALID_VDEV_ID)
+			continue;
+		if (!hdd_cm_is_vdev_connected(link_info))
+			continue;
+
+		vdev = hdd_objmgr_get_vdev_by_user(link_info,
+						   WLAN_OSIF_POWER_ID);
+		if (!vdev)
+			continue;
+
+		status = wlan_vdev_get_bss_peer_mac(vdev,
+						    &link_bssid[num_of_links]);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("failed to get bssid for vdev %d",
+				link_info->vdev_id);
+			goto next_link;
+		}
+
+		status =
+		ucfg_wlan_mlme_get_reg_tpc_info(vdev,
+						&reg_tpc_info[num_of_links]);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("failed to get tpc info for vdev %d",
+				link_info->vdev_id);
+			goto next_link;
+		}
+
+		num_of_links++;
+next_link:
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
+	}
+
+	if (!num_of_links) {
+		hdd_err("get tpc info failed - nun of links 0");
+		return -EINVAL;
+	}
+
+	skb_len = get_default_tpc_info_vendor_sbk_len();
+
+	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
+						wiphy,
+						skb_len);
+	if (!reply_skb) {
+		hdd_err("alloc reply_skb failed");
+		status = QDF_STATUS_E_NOMEM;
+		goto free_skb;
+	}
+
+	tpc_links_attr = nla_nest_start(reply_skb,
+					QCA_WLAN_VENDOR_ATTR_TPC_LINKS);
+	if (!tpc_links_attr) {
+		hdd_err("failed to add QCA_WLAN_VENDOR_ATTR_TPC_LINKS");
+		status = QDF_STATUS_E_INVAL;
+		goto free_skb;
+	}
+
+	for (i = 0; i < num_of_links; i++) {
+		tpc_attr = nla_nest_start(reply_skb, i);
+
+		if (nla_put(reply_skb, QCA_WLAN_VENDOR_ATTR_TPC_BSSID,
+			    QDF_MAC_ADDR_SIZE, &link_bssid[i])) {
+			hdd_err("failed to put mac_addr");
+			status = QDF_STATUS_E_INVAL;
+			goto free_skb;
+		}
+
+		if (reg_tpc_info[i].is_psd_power &&
+		    nla_put_flag(reply_skb,
+				 QCA_WLAN_VENDOR_ATTR_TPC_PSD_POWER)) {
+			osif_err("failed to put psd flag");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		if (nla_put_s8(reply_skb,
+			       QCA_WLAN_VENDOR_ATTR_TPC_EIRP_POWER,
+			       reg_tpc_info[i].reg_max[0])) {
+			hdd_err("failed to put eirp_power");
+			status = QDF_STATUS_E_INVAL;
+			goto free_skb;
+		}
+
+		chan_power_info = &reg_tpc_info[i].chan_power_info[0];
+		if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_power_info->chan_cfreq) &&
+		    nla_put_u8(reply_skb,
+			       QCA_WLAN_VENDOR_ATTR_TPC_POWER_TYPE_6GHZ,
+			       reg_tpc_info[i].power_type_6g)) {
+			hdd_err("failed to put power_type_6g");
+			status = QDF_STATUS_E_INVAL;
+			goto free_skb;
+		}
+
+		if (nla_put_u8(reply_skb,
+			       QCA_WLAN_VENDOR_ATTR_TPC_AP_CONSTRAINT_POWER,
+			       reg_tpc_info[i].ap_constraint_power)) {
+			hdd_err("failed to put ap_constraint_power");
+			status = QDF_STATUS_E_INVAL;
+			goto free_skb;
+		}
+
+		hdd_debug("%d tpc for bssid "QDF_MAC_ADDR_FMT" is_psd %d reg power %d 6ghz pwr type %d ap_constraint_power %d",
+			  i, link_bssid[i].bytes, reg_tpc_info[i].is_psd_power,
+			  reg_tpc_info[i].reg_max[0],
+			  reg_tpc_info[i].power_type_6g,
+			  reg_tpc_info[i].ap_constraint_power);
+
+		levels_attr = nla_nest_start(
+			reply_skb, QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL);
+		if (!levels_attr) {
+			hdd_err("failed to add QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL");
+			status = QDF_STATUS_E_INVAL;
+			goto free_skb;
+		}
+		for (j = 0; j < reg_tpc_info[i].num_pwr_levels; j++) {
+			tpc_level = nla_nest_start(reply_skb, j);
+			chan_power_info = &reg_tpc_info[i].chan_power_info[j];
+
+			attr_id = QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY;
+			if (nla_put_u32(reply_skb,
+					attr_id,
+					chan_power_info->chan_cfreq)) {
+				hdd_err("failed to put chan_cfreq %d",
+					chan_power_info->chan_cfreq);
+				status = QDF_STATUS_E_INVAL;
+				goto free_skb;
+			}
+
+			attr_id = QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_TX_POWER;
+			if (nla_put_s8(reply_skb,
+				       attr_id,
+				       chan_power_info->tx_power)) {
+				hdd_err("failed to put tx_power %d",
+					chan_power_info->tx_power);
+				status = QDF_STATUS_E_INVAL;
+				goto free_skb;
+			}
+
+			hdd_debug("%d cfreq %d tx_power %d", j,
+				  chan_power_info->chan_cfreq,
+				  chan_power_info->tx_power);
+
+			nla_nest_end(reply_skb, tpc_level);
+		}
+		nla_nest_end(reply_skb, levels_attr);
+
+		nla_nest_end(reply_skb, tpc_attr);
+	}
+
+	nla_nest_end(reply_skb, tpc_links_attr);
+
+	ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
+
+	hdd_exit();
+
+	return ret;
+free_skb:
+	if (reply_skb)
+		wlan_cfg80211_vendor_free_skb(reply_skb);
+	hdd_exit();
+	return qdf_status_to_os_return(status);
+}
+
+int wlan_hdd_cfg80211_get_reg_tpc_info(struct wiphy *wiphy,
+				       struct wireless_dev *wdev,
+				       const void *data,
+				       int data_len)
+{
+	struct osif_vdev_sync *vdev_sync;
+	int errno;
+
+	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_get_reg_tpc_info(wiphy, wdev,
+						     data, data_len);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return errno;
+}

+ 29 - 0
core/hdd/src/wlan_hdd_tx_power.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -61,6 +62,21 @@ int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy,
 					    const void *data,
 					    int data_len);
 
+/**
+ * wlan_hdd_cfg80211_get_reg_tpc_info () - get regulatory tpc information of
+ * connected AP
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int wlan_hdd_cfg80211_get_reg_tpc_info(struct wiphy *wiphy,
+				       struct wireless_dev *wdev,
+				       const void *data,
+				       int data_len);
+
 #define FEATURE_TX_POWER_VENDOR_COMMANDS				\
 {									\
 	.info.vendor_id = QCA_NL80211_VENDOR_ID,			\
@@ -83,8 +99,21 @@ int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy,
 	vendor_command_policy(txpower_scale_decr_db_policy,             \
 			      QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX) \
 },
+
+#define FEATURE_REGULATORY_TPC_INFO_VENDOR_COMMANDS                     \
+{                                                                       \
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,                        \
+	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_REGULATORY_TPC_INFO,   \
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |                           \
+		 WIPHY_VENDOR_CMD_NEED_NETDEV |                         \
+		 WIPHY_VENDOR_CMD_NEED_RUNNING,                         \
+	.doit = wlan_hdd_cfg80211_get_reg_tpc_info,                     \
+	vendor_command_policy(VENDOR_CMD_RAW_DATA, 0)                   \
+},
+
 #else /* FEATURE_TX_POWER */
 #define FEATURE_TX_POWER_VENDOR_COMMANDS
+#define FEATURE_REGULATORY_TPC_INFO_VENDOR_COMMANDS
 #endif /* FEATURE_TX_POWER */
 
 #endif /* __WLAN_HDD_TX_POWER_H */

+ 3 - 3
core/mac/inc/qwlan_version.h

@@ -32,9 +32,9 @@
 #define QWLAN_VERSION_MAJOR            5
 #define QWLAN_VERSION_MINOR            2
 #define QWLAN_VERSION_PATCH            1
-#define QWLAN_VERSION_EXTRA            "J"
-#define QWLAN_VERSION_BUILD            84
+#define QWLAN_VERSION_EXTRA            "K"
+#define QWLAN_VERSION_BUILD            85
 
-#define QWLAN_VERSIONSTR               "5.2.1.84J"
+#define QWLAN_VERSIONSTR               "5.2.1.85K"
 
 #endif /* QWLAN_VERSION_H */

+ 1 - 1
core/mac/src/pe/lim/lim_ft.c

@@ -529,7 +529,7 @@ static QDF_STATUS lim_fill_session_power_info(
 				struct pe_session *pe_session)
 {
 	uint8_t currentBssUapsd;
-	int8_t localPowerConstraint;
+	int8_t localPowerConstraint = 0;
 	int8_t regMax = 0;
 	bool is_pwr_constraint = false;
 	struct vdev_mlme_obj *mlme_obj;

+ 6 - 1
core/mac/src/pe/lim/lim_mlo.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -1065,6 +1065,11 @@ QDF_STATUS lim_fill_complete_mlo_ie(struct pe_session *session,
 	target[consumed++] = buf[index++];
 	target[consumed++] = buf[index++];
 	mlo_ie_total_len = pbuf - buf - MIN_IE_LEN;
+	if (mlo_ie_total_len > total_len - MIN_IE_LEN) {
+		pe_err("Invalid len: %u, %u", mlo_ie_total_len, total_len);
+		qdf_mem_free(buf);
+		return QDF_STATUS_E_INVAL;
+	}
 
 	for (i = 0; i < mlo_ie_total_len; i++) {
 		if (i && (i % WLAN_MAX_IE_LEN) == 0) {

+ 9 - 6
core/mac/src/pe/lim/lim_process_message_queue.c

@@ -1129,12 +1129,14 @@ lim_check_mgmt_registered_frames(struct mac_context *mac_ctx, uint8_t *buff_desc
 		 * userspace after processing the BTM frame from AP so the
 		 * audio glitches are not seen in P2P connection.
 		 */
-		if (cfg_p2p_is_roam_config_disabled(mac_ctx->psoc) &&
-		    session_entry && LIM_IS_STA_ROLE(session_entry) &&
-		    (policy_mgr_mode_specific_connection_count(mac_ctx->psoc,
+		if (session_entry && LIM_IS_STA_ROLE(session_entry) &&
+		    ((cfg_p2p_is_roam_config_disabled(mac_ctx->psoc) &&
+		      (policy_mgr_mode_specific_connection_count(mac_ctx->psoc,
 						PM_P2P_CLIENT_MODE, NULL) ||
-		     policy_mgr_mode_specific_connection_count(mac_ctx->psoc,
-						PM_P2P_GO_MODE, NULL))) {
+		       policy_mgr_mode_specific_connection_count(mac_ctx->psoc,
+						PM_P2P_GO_MODE, NULL))) ||
+		     wlan_cm_is_mbo_ap_without_pmf(mac_ctx->psoc,
+						   session_entry->vdev_id))) {
 			if (frm_len >= sizeof(*action_hdr) && action_hdr &&
 			    fc.type == SIR_MAC_MGMT_FRAME &&
 			    fc.subType == SIR_MAC_MGMT_ACTION) {
@@ -1144,7 +1146,8 @@ lim_check_mgmt_registered_frames(struct mac_context *mac_ctx, uint8_t *buff_desc
 				    (actionID == WNM_BSS_TM_QUERY ||
 				     actionID == WNM_BSS_TM_REQUEST ||
 				     actionID == WNM_BSS_TM_RESPONSE)) {
-					pe_debug("p2p session active drop BTM frame");
+					pe_debug("Drop the BTM frame as p2p session is active or rcvd from MBO AP without PMF, vdev %d",
+						 session_entry->vdev_id);
 					return match;
 				}
 			}

+ 15 - 11
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -3222,7 +3222,7 @@ lim_fill_pe_session(struct mac_context *mac_ctx, struct pe_session *session,
 	ePhyChanBondState cb_mode;
 	const uint8_t *vendor_ie;
 	uint16_t ie_len;
-	int8_t local_power_constraint;
+	int8_t local_power_constraint = 0;
 	struct vdev_mlme_obj *mlme_obj;
 	bool is_pwr_constraint = false;
 	tSirMacCapabilityInfo *ap_cap_info;
@@ -6294,19 +6294,23 @@ void lim_calculate_tpc(struct mac_context *mac,
 
 		/* max tx power calculation */
 		max_tx_power = mlme_obj->reg_tpc_obj.reg_max[i];
-		/* If AP local power constraint is present */
-		if (mlme_obj->reg_tpc_obj.ap_constraint_power) {
-			local_constraint =
-				mlme_obj->reg_tpc_obj.ap_constraint_power;
-			pe_debug("local constraint: %d power constraint absolute %d",
-				 local_constraint,
-				 mlme_obj->reg_tpc_obj.is_power_constraint_abs);
-			if (mlme_obj->reg_tpc_obj.is_power_constraint_abs)
+
+		local_constraint = mlme_obj->reg_tpc_obj.ap_constraint_power;
+		pe_debug("local constraint: %d power constraint absolute %d",
+			 local_constraint,
+			 mlme_obj->reg_tpc_obj.is_power_constraint_abs);
+		if (mlme_obj->reg_tpc_obj.is_power_constraint_abs) {
+			if (!local_constraint) {
+				pe_debug("ignore abs ap constraint power 0!");
+				max_tx_power = reg_max;
+			} else {
 				max_tx_power = QDF_MIN(reg_max,
 						       local_constraint);
-			else
-				max_tx_power = reg_max - local_constraint;
+			}
+		} else {
+			max_tx_power = reg_max - local_constraint;
 		}
+
 		/* If TPE is present */
 		if (is_tpe_present && !skip_tpe) {
 			if (!is_psd_power && mlme_obj->reg_tpc_obj.eirp_power)

+ 4 - 0
core/mac/src/pe/lim/lim_process_tdls.c

@@ -4178,6 +4178,7 @@ QDF_STATUS lim_process_sme_tdls_del_sta_req(struct mac_context *mac,
 	struct pe_session *pe_session;
 	uint8_t session_id;
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	tSirMacAddr peer;
 
 	pe_debug("TDLS Delete STA Request Received");
 	pe_session =
@@ -4220,6 +4221,9 @@ QDF_STATUS lim_process_sme_tdls_del_sta_req(struct mac_context *mac,
 		goto lim_tdls_del_sta_error;
 	}
 
+	qdf_mem_copy(peer, del_sta_req->peermac.bytes, sizeof(tSirMacAddr));
+	lim_send_deauth_mgmt_frame(mac, REASON_DEAUTH_NETWORK_LEAVING,
+				   peer, pe_session, false);
 	status = lim_tdls_del_sta(mac, del_sta_req->peermac,
 				  pe_session, true);
 	if (status == QDF_STATUS_SUCCESS)

+ 21 - 2
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -7496,8 +7496,10 @@ static QDF_STATUS lim_update_mld_to_link_address(struct mac_context *mac_ctx,
 	struct qdf_mac_addr *self_link_addr;
 	struct tLimPreAuthNode *pre_auth_node;
 	struct qdf_mac_addr peer_link_addr;
+	struct wlan_objmgr_peer *bss_peer = NULL;
 	struct qdf_mac_addr *peer_roaming_link_addr;
 	enum QDF_OPMODE opmode;
+	uint8_t *peer_mld_addr = NULL;
 	QDF_STATUS status;
 
 	if (!wlan_cm_is_sae_auth_addr_conversion_required(vdev))
@@ -7539,16 +7541,33 @@ static QDF_STATUS lim_update_mld_to_link_address(struct mac_context *mac_ctx,
 							    &peer_link_addr);
 			if (QDF_IS_STATUS_ERROR(status))
 				return status;
+			bss_peer = wlan_objmgr_vdev_try_get_bsspeer(
+						vdev, WLAN_MLME_OBJMGR_ID);
+			if (bss_peer) {
+				peer_mld_addr =
+					wlan_peer_mlme_get_mldaddr(bss_peer);
+				wlan_objmgr_peer_release_ref(
+						bss_peer, WLAN_MLME_OBJMGR_ID);
+			}
 		} else {
 			peer_roaming_link_addr =
 				wlan_cm_roaming_get_peer_link_addr(vdev);
 			if (!peer_roaming_link_addr)
 				return QDF_STATUS_E_FAILURE;
 			peer_link_addr = *peer_roaming_link_addr;
+			peer_mld_addr = (uint8_t *)
+					wlan_cm_roaming_get_peer_mld_addr(vdev);
 		}
+		if (!peer_mld_addr)
+			return QDF_STATUS_SUCCESS;
+
+		pe_debug("dest address"QDF_MAC_ADDR_FMT"mld addr"QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(mac_hdr->da),
+			 QDF_MAC_ADDR_REF(peer_mld_addr));
+		if (!qdf_mem_cmp(mac_hdr->da, peer_mld_addr, QDF_MAC_ADDR_SIZE))
+			qdf_mem_copy(mac_hdr->da, peer_link_addr.bytes,
+				     QDF_MAC_ADDR_SIZE);
 
-		qdf_mem_copy(mac_hdr->da, peer_link_addr.bytes,
-			     QDF_MAC_ADDR_SIZE);
 		qdf_mem_copy(mac_hdr->bssId, peer_link_addr.bytes,
 			     QDF_MAC_ADDR_SIZE);
 		break;

+ 7 - 0
core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

@@ -1981,6 +1981,7 @@ void lim_handle_sta_csa_param(struct mac_context *mac_ctx,
 			      struct csa_offload_params *csa_params)
 {
 	struct pe_session *session_entry;
+	struct mlme_legacy_priv *mlme_priv;
 	tpDphHashNode sta_ds = NULL;
 	uint8_t session_id;
 	uint16_t aid = 0;
@@ -2297,6 +2298,12 @@ void lim_handle_sta_csa_param(struct mac_context *mac_ctx,
 	if (wlan_vdev_mlme_is_mlo_vdev(session_entry->vdev)) {
 		link_id = wlan_vdev_get_link_id(session_entry->vdev);
 		update_csa_link_info(session_entry->vdev, link_id, csa_params);
+	} else {
+		mlme_priv = wlan_vdev_mlme_get_ext_hdl(session_entry->vdev);
+		if (!mlme_priv)
+			return;
+		mlme_priv->connect_info.assoc_chan_info.assoc_ch_width =
+						csa_params->new_ch_width;
 	}
 
 	if (WLAN_REG_IS_24GHZ_CH_FREQ(csa_params->csa_chan_freq) &&

+ 12 - 6
core/mac/src/pe/lim/lim_utils.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -5352,7 +5352,6 @@ static void lim_check_conc_and_send_edca(struct mac_context *mac,
 	bool params_update_required = false;
 	uint8_t i;
 	tpDphHashNode sta_ds = NULL;
-	QDF_STATUS status;
 	uint16_t assoc_id;
 
 	if (sta_session && sap_session &&
@@ -5419,10 +5418,7 @@ static void lim_check_conc_and_send_edca(struct mac_context *mac,
 				     sap_session->vdev_id, false);
 
 		sap_session->gLimEdcaParamSetCount++;
-		status = sch_set_fixed_beacon_fields(mac, sap_session);
-		if (QDF_IS_STATUS_ERROR(status))
-			pe_debug("Unable to set beacon fields!");
-
+		csr_update_beacon(mac);
 	} else if (!sap_session && sta_session) {
 	/*
 	 * Enable A-EDCA for standalone STA. The original EDCA parameters are
@@ -7085,6 +7081,7 @@ void lim_intersect_sta_he_caps(struct mac_context *mac_ctx,
 {
 	tDot11fIEhe_cap *rcvd_he = &assoc_req->he_cap;
 	tDot11fIEhe_cap *peer_he = &sta_ds->he_config;
+	struct wlan_mlme_cfg *mlme_cfg = mac_ctx->mlme_cfg;
 
 	if (!sta_ds->mlmStaContext.he_capable)
 		return;
@@ -7095,6 +7092,15 @@ void lim_intersect_sta_he_caps(struct mac_context *mac_ctx,
 
 	lim_intersect_he_caps(rcvd_he, peer_he, session);
 
+	if ((mlme_cfg->he_caps.disable_sap_mcs_12_13 &
+	     BIT(DISABLE_MCS_12_13_2G_40M)) &&
+	    LIM_IS_AP_ROLE(session) &&
+	    wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) &&
+	    session->ch_width == CH_WIDTH_40MHZ) {
+		sta_ds->he_mcs_12_13_map = 0;
+		return;
+	}
+
 	/* If MCS 12/13 is supported from assoc QCN IE */
 	if (assoc_req->qcn_ie.present &&
 	    assoc_req->qcn_ie.he_mcs13_attr.present) {

+ 6 - 5
core/mac/src/pe/sch/sch_beacon_process.c

@@ -602,6 +602,7 @@ static void __sch_beacon_process_for_session(struct mac_context *mac_ctx,
 	struct vdev_mlme_obj *mlme_obj;
 	struct wlan_lmac_if_reg_tx_ops *tx_ops;
 	bool ap_constraint_change = false, tpe_change = false;
+	bool allow_tpc = false;
 	int8_t regMax = 0, maxTxPower = 0;
 	QDF_STATUS status;
 	bool skip_tpe = false, is_sap_go_switched_ch;
@@ -714,10 +715,11 @@ static void __sch_beacon_process_for_session(struct mac_context *mac_ctx,
 				bcn->localPowerConstraint.localPowerConstraints;
 				is_power_constraint_abs = false;
 			}
+			allow_tpc = true;
 		}
 
-		if (local_constraint !=
-				mlme_obj->reg_tpc_obj.ap_constraint_power) {
+		if (allow_tpc && local_constraint !=
+		    mlme_obj->reg_tpc_obj.ap_constraint_power) {
 			mlme_obj->reg_tpc_obj.ap_constraint_power =
 							local_constraint;
 			mlme_obj->reg_tpc_obj.is_power_constraint_abs =
@@ -725,15 +727,14 @@ static void __sch_beacon_process_for_session(struct mac_context *mac_ctx,
 			ap_constraint_change = true;
 		}
 
-		if ((ap_constraint_change && local_constraint) ||
-		    (tpe_change && !skip_tpe)) {
+		if (ap_constraint_change || (tpe_change && !skip_tpe)) {
 			lim_calculate_tpc(mac_ctx, session);
 
 			if (tx_ops->set_tpc_power)
 				tx_ops->set_tpc_power(mac_ctx->psoc,
 						      session->vdev_id,
 						      &mlme_obj->reg_tpc_obj);
-			}
+		}
 	} else if (!session->sta_follows_sap_power) {
 		/* Obtain the Max Tx power for the current regulatory  */
 		regMax = wlan_reg_get_channel_reg_power_for_freq(

+ 10 - 4
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -1651,7 +1651,7 @@ static void populate_dot11f_qcn_ie_he_params(struct mac_context *mac,
 					     tDot11fIEqcn_ie *qcn_ie,
 					     uint8_t attr_id)
 {
-	uint16_t mcs_12_13_supp;
+	uint16_t mcs_12_13_supp = 0;
 
 	if (!lim_is_session_he_capable(pe_session))
 		return;
@@ -1659,10 +1659,16 @@ static void populate_dot11f_qcn_ie_he_params(struct mac_context *mac,
 	/* To fix WAPI IoT issue.*/
 	if (pe_session->encryptType == eSIR_ED_WPI)
 		return;
-	if (wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq))
-		mcs_12_13_supp = mac->mlme_cfg->he_caps.he_mcs_12_13_supp_2g;
-	else
+
+	if (wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq)) {
+		if (!(LIM_IS_AP_ROLE(pe_session) &&
+		      pe_session->ch_width == CH_WIDTH_40MHZ &&
+		      (mac->mlme_cfg->he_caps.disable_sap_mcs_12_13 &
+		       BIT(DISABLE_MCS_12_13_2G_40M))))
+			mcs_12_13_supp = mac->mlme_cfg->he_caps.he_mcs_12_13_supp_2g;
+	} else {
 		mcs_12_13_supp = mac->mlme_cfg->he_caps.he_mcs_12_13_supp_5g;
+	}
 
 	if (!mcs_12_13_supp)
 		return;

+ 13 - 0
core/sap/inc/sap_api.h

@@ -59,7 +59,9 @@ extern "C" {
 #define       SAP_WPS_ENABLED_CONFIGURED   2
 
 #define       MAX_CHANNEL_LIST_LEN         256
+#ifndef QDF_MAX_NO_OF_SAP_MODE
 #define       QDF_MAX_NO_OF_SAP_MODE       2    /* max # of SAP */
+#endif
 #define       SAP_MAX_NUM_SESSION          5
 #define       SAP_MAX_OBSS_STA_CNT         1    /* max # of OBSS STA */
 #define       SAP_ACS_WEIGHT_MAX           (26664)
@@ -1635,6 +1637,17 @@ wlansap_override_csa_strict_for_sap(mac_handle_t mac_handle,
 				    uint32_t target_chan_freq,
 				    bool strict);
 
+/**
+ * wlansap_validate_channel_post_csa() - Check SAP channel unsafe or not
+ * after CSA
+ * @mac_handle: global MAC context
+ * @sap_ctx: SAP context
+ *
+ * Return: bool
+ */
+bool wlansap_validate_channel_post_csa(mac_handle_t mac_handle,
+				       struct sap_context *sap_ctx);
+
 /**
  * sap_get_csa_reason_str() - Get csa reason in string
  * @reason: sap reason enum value

+ 3 - 3
core/sap/src/sap_api_link_cntl.c

@@ -463,12 +463,12 @@ wlansap_roam_process_ch_change_success(struct mac_context *mac_ctx,
 	 * Channel change is successful. If the new channel is a DFS channel,
 	 * then we will to perform channel availability check for 60 seconds
 	 */
-	sap_nofl_debug("sap_fsm: vdev %d: sapdfs: SAP CSA: freq %d state %d",
+	sap_nofl_debug("sap_fsm: vdev %d: sapdfs: SAP CSA: freq %d state %d evt freq %d",
 		       sap_ctx->vdev_id,
 		       mac_ctx->sap.SapDfsInfo.target_chan_freq,
-		       sap_ctx->fsm_state);
+		       sap_ctx->fsm_state,
+		       csr_roam_info->channelChangeRespEvent->new_op_freq);
 	target_chan_freq = mac_ctx->sap.SapDfsInfo.target_chan_freq;
-
 	/* If SAP is not in starting or started state don't proceed further */
 	if (sap_ctx->fsm_state == SAP_INIT ||
 	    sap_ctx->fsm_state == SAP_STOPPING) {

+ 7 - 54
core/sap/src/sap_fsm.c

@@ -3679,22 +3679,6 @@ static void sap_check_and_update_vdev_ch_params(struct sap_context *sap_ctx)
 		  sap_ctx->ch_params.ch_width);
 }
 
-static qdf_freq_t sap_get_safe_channel_freq(struct sap_context *sap_ctx)
-{
-	qdf_freq_t freq;
-
-	freq = wlan_pre_cac_get_freq_before_pre_cac(sap_ctx->vdev);
-	if (!freq)
-		freq = wlansap_get_safe_channel_from_pcl_and_acs_range(
-								sap_ctx,
-								NULL);
-
-	sap_debug("new selected freq %d as target chan as current freq unsafe %d",
-		  freq, sap_ctx->chan_freq);
-
-	return freq;
-}
-
 /**
  * sap_fsm_send_csa_restart_req() - send csa start event
  * @mac_ctx: mac ctx
@@ -3737,21 +3721,10 @@ sap_fsm_send_csa_restart_req(struct mac_context *mac_ctx,
 	return sme_csa_restart(mac_ctx, sap_ctx->sessionId);
 }
 
-/**
- * sap_fsm_validate_and_change_channel() - handle channel Avoid event event
- *                                         or channel list update during cac
- * @mac_ctx: global MAC context
- * @sap_ctx: SAP context
- *
- * Return: QDF_STATUS
- */
-static void sap_fsm_validate_and_change_channel(struct mac_context *mac_ctx,
-						struct sap_context *sap_ctx)
+bool wlansap_validate_channel_post_csa(mac_handle_t mac_handle,
+				       struct sap_context *sap_ctx)
 {
-	qdf_freq_t target_chan_freq;
-	struct ch_params ch_params = {0};
-	QDF_STATUS status;
-	enum phy_ch_width target_bw = sap_ctx->ch_params.ch_width;
+	struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle);
 
 	if (((!sap_ctx->acs_cfg || !sap_ctx->acs_cfg->acs_mode) &&
 	     (!policy_mgr_restrict_sap_on_unsafe_chan(mac_ctx->psoc) ||
@@ -3760,24 +3733,11 @@ static void sap_fsm_validate_and_change_channel(struct mac_context *mac_ctx,
 	    (policy_mgr_is_sap_freq_allowed(mac_ctx->psoc, sap_ctx->chan_freq) &&
 	     !wlan_reg_is_disable_for_pwrmode(mac_ctx->pdev, sap_ctx->chan_freq,
 					      REG_CURRENT_PWR_MODE)))
-		return;
+		return true;
+	sap_debug("sap vdev %d on unsafe ch freq %d",
+		  sap_ctx->sessionId, sap_ctx->chan_freq);
 
-	/*
-	 * The selected channel is not safe channel. Hence,
-	 * change the sap channel to a safe channel.
-	 */
-	target_chan_freq = sap_get_safe_channel_freq(sap_ctx);
-	ch_params.ch_width = target_bw;
-	target_bw = wlansap_get_csa_chanwidth_from_phymode(
-			sap_ctx, target_chan_freq, &ch_params);
-	sap_debug("sap vdev %d change to safe ch freq %d bw %d from unsafe %d",
-		  sap_ctx->sessionId, target_chan_freq, target_bw,
-		  sap_ctx->chan_freq);
-	status = wlansap_set_channel_change_with_csa(
-			sap_ctx, target_chan_freq, target_bw, false);
-	if (QDF_IS_STATUS_ERROR(status))
-		sap_err("SAP set channel failed for freq: %d, bw: %d",
-			target_chan_freq, target_bw);
+	return false;
 }
 
 /**
@@ -3924,13 +3884,6 @@ static QDF_STATUS sap_fsm_state_starting(struct sap_context *sap_ctx,
 				wlansap_start_beacon_req(sap_ctx);
 			}
 		}
-		/*
-		 * During CSA, it might be possible that ch avoidance event to
-		 * avoid the sap frequency is received. So, check after CSA,
-		 * whether sap frequency is safe if not restart sap to a safe
-		 * channel.
-		 */
-		sap_fsm_validate_and_change_channel(mac_ctx, sap_ctx);
 	} else if (msg == eSAP_MAC_START_FAILS ||
 		 msg == eSAP_HDD_STOP_INFRA_BSS) {
 			qdf_status = sap_fsm_handle_start_failure(sap_ctx, msg,

+ 47 - 9
core/sme/src/common/sme_api.c

@@ -4402,6 +4402,7 @@ sme_store_nss_chains_cfg_in_vdev(struct wlan_objmgr_vdev *vdev,
 static void
 sme_populate_user_config(struct wlan_mlme_nss_chains *dynamic_cfg,
 			 struct wlan_mlme_nss_chains *user_cfg,
+			 struct wlan_mlme_nss_chains *ini_cfg,
 			 enum nss_chains_band_info band)
 {
 	if (!user_cfg->num_rx_chains[band])
@@ -4420,17 +4421,23 @@ sme_populate_user_config(struct wlan_mlme_nss_chains *dynamic_cfg,
 		user_cfg->tx_nss[band] =
 			dynamic_cfg->tx_nss[band];
 
-	if (!user_cfg->num_tx_chains_11a)
+	if (!user_cfg->num_tx_chains_11a) {
 		user_cfg->num_tx_chains_11a =
-			dynamic_cfg->num_tx_chains_11a;
+			QDF_MIN(user_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ],
+				ini_cfg->num_tx_chains_11a);
+	}
 
-	if (!user_cfg->num_tx_chains_11b)
+	if (!user_cfg->num_tx_chains_11b) {
 		user_cfg->num_tx_chains_11b =
-			dynamic_cfg->num_tx_chains_11b;
+			QDF_MIN(user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ],
+				ini_cfg->num_tx_chains_11b);
+	}
 
-	if (!user_cfg->num_tx_chains_11g)
+	if (!user_cfg->num_tx_chains_11g) {
 		user_cfg->num_tx_chains_11g =
-			dynamic_cfg->num_tx_chains_11g;
+			QDF_MIN(user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ],
+				ini_cfg->num_tx_chains_11g);
+	}
 
 	if (!user_cfg->disable_rx_mrc[band])
 		user_cfg->disable_rx_mrc[band] =
@@ -4543,7 +4550,7 @@ sme_validate_nss_chains_config(struct wlan_objmgr_vdev *vdev,
 
 	for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) {
 		sme_populate_user_config(dynamic_cfg,
-					 user_cfg, band);
+					 user_cfg, ini_cfg, band);
 		status = sme_validate_from_ini_config(user_cfg,
 						      ini_cfg,
 						      band);
@@ -4742,6 +4749,30 @@ sme_update_nss_in_mlme_cfg(mac_handle_t mac_handle,
 					   vdev_op_mode, band);
 }
 
+static void sme_dump_nss_cfg(struct wlan_mlme_nss_chains *user_cfg)
+{
+	sme_debug("num_tx_chains 2g %d 5g %d",
+		  user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ],
+		  user_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ]);
+
+	sme_debug("num_rx_chains 2g %d 5g %d",
+		  user_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ],
+		  user_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ]);
+
+	sme_debug("tx_nss 2g %d 5g %d",
+		  user_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ],
+		  user_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ]);
+	sme_debug("rx_nss 2g %d 5g %d",
+		  user_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ],
+		  user_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ]);
+	sme_debug("num_tx_chains_11b %d",
+		  user_cfg->num_tx_chains_11b);
+	sme_debug("num_tx_chains_11g %d",
+		  user_cfg->num_tx_chains_11g);
+	sme_debug("num_tx_chains_11a %d",
+		  user_cfg->num_tx_chains_11a);
+}
+
 QDF_STATUS
 sme_nss_chains_update(mac_handle_t mac_handle,
 		      struct wlan_mlme_nss_chains *user_cfg,
@@ -4782,6 +4813,11 @@ sme_nss_chains_update(mac_handle_t mac_handle,
 
 	status = sme_validate_nss_chains_config(vdev, user_cfg,
 						dynamic_cfg);
+	sme_debug("dynamic_cfg");
+	sme_dump_nss_cfg(dynamic_cfg);
+	sme_debug("user_cfg");
+	sme_dump_nss_cfg(user_cfg);
+
 	if (QDF_IS_STATUS_ERROR(status))
 		goto release_lock;
 
@@ -14952,8 +14988,10 @@ void sme_set_bss_max_idle_period(mac_handle_t mac_handle, uint16_t cfg_val)
 #ifdef WLAN_FEATURE_11BE
 static void sme_set_eht_mcs_info(struct mac_context *mac_ctx)
 {
-	mac_ctx->eht_cap_2g.bw_le_80_rx_max_nss_for_mcs_0_to_9 = 1;
-	mac_ctx->eht_cap_2g.bw_le_80_tx_max_nss_for_mcs_0_to_9 = 1;
+	if (mac_ctx->usr_eht_testbed_cfg) {
+		mac_ctx->eht_cap_2g.bw_le_80_rx_max_nss_for_mcs_0_to_9 = 1;
+		mac_ctx->eht_cap_2g.bw_le_80_tx_max_nss_for_mcs_0_to_9 = 1;
+	}
 }
 #else
 #ifdef WLAN_FEATURE_11AX

+ 1 - 0
core/wma/inc/wma_api.h

@@ -288,6 +288,7 @@ QDF_STATUS wma_send_dbs_scan_selection_params(WMA_HANDLE handle,
 			struct wmi_dbs_scan_sel_params *dbs_scan_params);
 QDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value);
 QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value);
+QDF_STATUS wma_enable_disable_imps(uint32_t pdev_id, uint32_t param_val);
 
 bool wma_is_csa_offload_enabled(void);
 /**

+ 8 - 2
core/wma/src/wma_data.c

@@ -2333,6 +2333,7 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
 	uint8_t *mld_addr = NULL;
 	bool is_5g = false;
 	uint8_t pdev_id;
+	bool mlo_link_agnostic;
 
 	if (wma_validate_handle(wma_handle)) {
 		cds_packet_free((void *)tx_frame);
@@ -2713,6 +2714,11 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
 	if (wlan_reg_is_5ghz_ch_freq(wma_handle->interfaces[vdev_id].ch_freq))
 		is_5g = true;
 
+	wh = (struct ieee80211_frame *)(qdf_nbuf_data(tx_frame));
+
+	mlo_link_agnostic =
+		wlan_get_mlo_link_agnostic_flag(iface->vdev, wh->i_addr1);
+
 	mgmt_param.tx_frame = tx_frame;
 	mgmt_param.frm_len = frmLen;
 	mgmt_param.vdev_id = vdev_id;
@@ -2729,7 +2735,8 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
 	    pFc->subType != SIR_MAC_MGMT_PROBE_REQ &&
 	    pFc->subType != SIR_MAC_MGMT_AUTH &&
 	    action != (ACTION_CATEGORY_PUBLIC << 8 | TDLS_DISCOVERY_RESPONSE) &&
-	    action != (ACTION_CATEGORY_BACK << 8 | ADDBA_RESPONSE))
+	    action != (ACTION_CATEGORY_BACK << 8 | ADDBA_RESPONSE) &&
+	    mlo_link_agnostic)
 		mgmt_param.mlo_link_agnostic = true;
 
 	if (tx_flag & HAL_USE_INCORRECT_KEY_PMF)
@@ -2760,7 +2767,6 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
 	}
 
 	pdev_id = wlan_objmgr_pdev_get_pdev_id(wma_handle->pdev);
-	wh = (struct ieee80211_frame *)(qdf_nbuf_data(tx_frame));
 	mac_addr = wh->i_addr1;
 	peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_MGMT_NB_ID);
 	if (!peer) {

+ 2 - 2
core/wma/src/wma_main.c

@@ -449,8 +449,8 @@ static void wma_set_feature_set_info(tp_wma_handle wma_handle,
 					mlme_feature_set.roaming_ctrl_get_cu;
 	feature_set->vendor_req_2_version =
 			mlme_feature_set.vendor_req_2_version;
-	feature_set->sta_dual_p2p_support =
-					mlme_feature_set.sta_dual_p2p_support;
+	feature_set->iface_combinations = mlme_feature_set.iface_combinations;
+
 	if (mlme_feature_set.enable2x2)
 		feature_set->num_antennas = WMI_HOST_MIMO_2X2;
 	else

+ 30 - 0
core/wma/src/wma_power.c

@@ -1696,5 +1696,35 @@ QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value)
 
 	return ret;
 }
+
+/**
+ * wma_enable_disable_imps() - enable/disable FW IMPS feature
+ * @pdev_id: pdev id
+ * @param_val: value
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code.
+ */
+QDF_STATUS wma_enable_disable_imps(uint32_t pdev_id, uint32_t param_val)
+{
+	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
+	struct pdev_params pparam = {0};
+	QDF_STATUS status;
+
+	if (!wma)
+		return QDF_STATUS_E_FAILURE;
+
+	pparam.is_host_pdev_id = false;
+
+	/* Enable-disable IMPS */
+	pparam.param_id = WMI_PDEV_PARAM_IDLE_PS_CONFIG;
+	pparam.param_value = param_val;
+	status = wmi_unified_pdev_param_send(wma->wmi_handle,
+					     &pparam, pdev_id);
+	if (QDF_IS_STATUS_ERROR(status))
+		wma_err("Unable to enable/disable:(%d) IMPS",
+			param_val);
+
+	return status;
+}
 #endif /* FEATURE_TX_POWER */