Bläddra i källkod

Merge c37ebe5212862f0cfecf828bad1a541b97f5f418 on remote branch

Change-Id: I3e50e79829bd1f4bb7c3f8d3b87baee384dae1e5
Linux Build Service Account 1 år sedan
förälder
incheckning
4f70759d48
100 ändrade filer med 3737 tillägg och 680 borttagningar
  1. 6 5
      Android.mk
  2. 13 0
      Kbuild
  3. 9 1
      Kconfig
  4. 9 0
      components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c
  5. 52 2
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
  6. 3 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h
  7. 281 10
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  8. 14 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h
  9. 58 1
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c
  10. 1 1
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c
  11. 8 8
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_sbs_i.h
  12. 4 4
      components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h
  13. 9 1
      components/dp/core/src/wlan_dp_main.c
  14. 0 4
      components/mlme/core/inc/wlan_mlme_main.h
  15. 38 44
      components/mlme/core/src/wlan_mlme_main.c
  16. 32 4
      components/mlme/dispatcher/inc/cfg_mlme_sta.h
  17. 60 0
      components/mlme/dispatcher/inc/wlan_mlme_api.h
  18. 2 0
      components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
  19. 55 0
      components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
  20. 222 0
      components/mlme/dispatcher/src/wlan_mlme_api.c
  21. 13 0
      components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
  22. 16 0
      components/nan/core/inc/nan_public_structs.h
  23. 5 0
      components/pmo/core/inc/wlan_pmo_priv.h
  24. 42 0
      components/pmo/core/inc/wlan_pmo_static_config.h
  25. 2 0
      components/pmo/core/src/wlan_pmo_main.c
  26. 20 6
      components/pmo/core/src/wlan_pmo_suspend_resume.c
  27. 29 3
      components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h
  28. 20 1
      components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h
  29. 32 0
      components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h
  30. 21 0
      components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h
  31. 21 0
      components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c
  32. 13 0
      components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c
  33. 174 1
      components/target_if/connection_mgr/src/target_if_cm_roam_event.c
  34. 4 1
      components/target_if/pmo/src/target_if_pmo_suspend_resume.c
  35. 5 0
      components/tdls/core/src/wlan_tdls_ct.c
  36. 77 8
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c
  37. 29 3
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c
  38. 19 0
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c
  39. 9 3
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c
  40. 10 7
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c
  41. 24 1
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h
  42. 8 5
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h
  43. 11 3
      components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h
  44. 3 2
      components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h
  45. 13 4
      components/umac/mlme/mlo_mgr/inc/wlan_t2lm_api.h
  46. 217 34
      components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c
  47. 18 8
      components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c
  48. 26 9
      components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c
  49. 13 0
      components/umac/twt/core/src/wlan_twt_cfg.c
  50. 14 0
      components/umac/twt/core/src/wlan_twt_cfg.h
  51. 15 1
      components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h
  52. 6 0
      components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c
  53. 31 0
      components/wmi/inc/wmi_unified_roam_api.h
  54. 19 1
      components/wmi/src/wmi_unified_roam_api.c
  55. 446 25
      components/wmi/src/wmi_unified_roam_tlv.c
  56. 12 0
      configs/config_to_feature.h
  57. 9 4
      configs/default_defconfig
  58. 1 0
      configs/pineapple_consolidate_kiwi-v2_defconfig
  59. 0 1
      configs/pineapple_gki_kiwi-v2_defconfig
  60. 2 0
      configs/qca6174_defconfig
  61. 0 1
      configs/wcn6450_defconfig
  62. 2 2
      core/dp/htt/htt_t2h.c
  63. 3 1
      core/hdd/inc/wlan_hdd_assoc.h
  64. 9 4
      core/hdd/inc/wlan_hdd_mlo.h
  65. 15 2
      core/hdd/inc/wlan_hdd_power.h
  66. 35 0
      core/hdd/inc/wlan_hdd_twt.h
  67. 35 0
      core/hdd/src/wlan_hdd_cfg.c
  68. 74 11
      core/hdd/src/wlan_hdd_cfg80211.c
  69. 10 0
      core/hdd/src/wlan_hdd_cm_connect.c
  70. 17 22
      core/hdd/src/wlan_hdd_hostapd.c
  71. 25 5
      core/hdd/src/wlan_hdd_ioctl.c
  72. 19 7
      core/hdd/src/wlan_hdd_main.c
  73. 196 188
      core/hdd/src/wlan_hdd_medium_assess.c
  74. 3 11
      core/hdd/src/wlan_hdd_medium_assess.h
  75. 17 7
      core/hdd/src/wlan_hdd_mlo.c
  76. 53 9
      core/hdd/src/wlan_hdd_power.c
  77. 1 9
      core/hdd/src/wlan_hdd_pre_cac.c
  78. 8 1
      core/hdd/src/wlan_hdd_regulatory.c
  79. 163 91
      core/hdd/src/wlan_hdd_stats.c
  80. 8 0
      core/hdd/src/wlan_hdd_sysfs.c
  81. 26 2
      core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.c
  82. 148 0
      core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.c
  83. 60 0
      core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.h
  84. 147 0
      core/hdd/src/wlan_hdd_sysfs_wds_mode.c
  85. 58 0
      core/hdd/src/wlan_hdd_sysfs_wds_mode.h
  86. 22 1
      core/hdd/src/wlan_hdd_twt.c
  87. 3 3
      core/mac/inc/qwlan_version.h
  88. 0 5
      core/mac/inc/sir_api.h
  89. 34 6
      core/mac/src/pe/lim/lim_api.c
  90. 7 1
      core/mac/src/pe/lim/lim_mlo.c
  91. 0 1
      core/mac/src/pe/lim/lim_mlo.h
  92. 4 3
      core/mac/src/pe/lim/lim_process_action_frame.c
  93. 63 0
      core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
  94. 22 0
      core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
  95. 1 1
      core/mac/src/pe/lim/lim_process_probe_rsp_frame.c
  96. 6 12
      core/mac/src/pe/lim/lim_process_sme_req_messages.c
  97. 5 0
      core/mac/src/pe/lim/lim_prop_exts_utils.c
  98. 31 6
      core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
  99. 41 33
      core/mac/src/pe/lim/lim_utils.c
  100. 41 19
      core/mac/src/pe/lim/lim_utils.h

+ 6 - 5
Android.mk

@@ -13,12 +13,12 @@ $(strip \
 )
 endef
 
+LOCAL_MODULE_DDK_BUILD := false
+LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := false
+
+ifeq ($(TARGET_BOARD_PLATFORM), pineapple)
 LOCAL_MODULE_DDK_BUILD := true
 LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := true
-
-ifeq ($(shell test $(PLATFORM_VERSION) -lt 14; echo $$?),0)
-    LOCAL_MODULE_DDK_BUILD := false
-    LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := false
 endif
 
 LOCAL_PATH := $(call my-dir)
@@ -207,7 +207,8 @@ LOCAL_MOD_NAME := $(LOCAL_DEV_NAME)
 endif
 
 ifeq ($(TARGET_SECONDARY_WLAN), true)
-LOCAL_MOD_NAME := $(LOCAL_CHIP_NAME)
+TARGET_SECONDARY_WLAN_NUMBER := 2
+LOCAL_MOD_NAME := $(LOCAL_CHIP_NAME)_$(TARGET_SECONDARY_WLAN_NUMBER)
 DYNAMIC_SINGLE_CHIP := $(LOCAL_CHIP_NAME)
 endif
 

+ 13 - 0
Kbuild

@@ -467,6 +467,14 @@ ifeq ($(CONFIG_WLAN_SYSFS_DFSNOL), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dfsnol.o
 endif
 
+ifeq ($(CONFIG_WLAN_SYSFS_WDS_MODE), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_wds_mode.o
+endif
+
+ifeq ($(CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_roam_trigger_bitmap.o
+endif
+
 endif # CONFIG_WLAN_SYSFS
 
 ifeq ($(CONFIG_QCACLD_FEATURE_FW_STATE), y)
@@ -3366,6 +3374,7 @@ endif
 
 ifeq ($(CONFIG_RHINE), y)
 ccflags-y += -DCONFIG_RHINE
+ccflags-y += -DDP_OFFLOAD_FRAME_WITH_SW_EXCEPTION
 endif
 
 ccflags-$(CONFIG_TALLOC_DEBUG) += -DWLAN_TALLOC_DEBUG
@@ -3648,6 +3657,8 @@ ccflags-$(CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM) += -DWLAN_PDEV_VDEV_SEND_MULTI
 ccflags-$(CONFIG_WLAN_SYSFS_LOG_BUFFER) += -DFEATURE_SYSFS_LOG_BUFFER
 ccflags-$(CONFIG_ENABLE_VALLOC_REPLACE_MALLOC) += -DENABLE_VALLOC_REPLACE_MALLOC
 ccflags-$(CONFIG_WLAN_SYSFS_DFSNOL) += -DCONFIG_WLAN_SYSFS_DFSNOL
+ccflags-$(CONFIG_WLAN_SYSFS_WDS_MODE) += -DFEATURE_SYSFS_WDS_MODE
+ccflags-$(CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP) += -DFEATURE_SYSFS_ROAM_TRIGGER_BITMAP
 
 ifeq ($(CONFIG_LEAK_DETECTION), y)
 ccflags-y += \
@@ -3662,6 +3673,8 @@ ccflags-y += \
 	-DWLAN_PERIODIC_WORK_DEBUG
 endif
 
+cppflags-$(CONFIG_ALLOC_CONTIGUOUS_MULTI_PAGE) += -DALLOC_CONTIGUOUS_MULTI_PAGE
+
 ifeq ($(CONFIG_QCOM_VOWIFI_11R), y)
 ccflags-y += -DKERNEL_SUPPORT_11R_CFG80211
 ccflags-y += -DUSE_80211_WMMTSPEC_FOR_RIC

+ 9 - 1
Kconfig

@@ -1659,7 +1659,7 @@ config WLAN_WBUFF
 
 config WLAN_WEXT_SUPPORT_ENABLE
 	bool "Enable WLAN_WEXT_SUPPORT_ENABLE"
-	depends on WIRELESS_EXT
+	depends on CFG80211_WEXT
 	default n
 
 config WLAN_WOW_ITO
@@ -1726,6 +1726,10 @@ config CFG80211_MLO_KEY_OPERATION_SUPPORT
 	bool "Enable CFG80211_MLO_KEY_OPERATION_SUPPORT"
 	default n
 
+config CFG80211_WEXT
+	bool "Enable CFG80211_WEXT"
+	default n
+
 config FEATURE_PKTLOG
 	bool "Enable CONFIG_FEATURE_PKTLOG"
 	default n
@@ -1857,4 +1861,8 @@ config FEATURE_WLAN_CH_AVOID_EXT
 	bool "enable FEATURE_WLAN_CH_AVOID_EXT"
 	default n
 
+config WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE
+	bool "enable CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE"
+	default n
+
 endif # QCA_CLD_WLAN

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

@@ -37,6 +37,7 @@
 #include "wlan_scan_api.h"
 #include "wlan_mlo_mgr_roam.h"
 #include "wlan_mlo_mgr_sta.h"
+#include "wlan_mlo_mgr_link_switch.h"
 
 #ifdef WLAN_FEATURE_11BE_MLO
 static inline bool
@@ -169,6 +170,14 @@ if_mgr_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev,
 	struct wlan_objmgr_psoc *psoc;
 	uint8_t vdev_id;
 
+	/*
+	 * When link switch is in progress, don't send RSO Enable before vdev
+	 * is up. RSO Enable will be sent as part of install keys once
+	 * link switch connect sequence is complete.
+	 */
+	if (mlo_mgr_is_link_switch_in_progress(vdev))
+		return QDF_STATUS_SUCCESS;
+
 	psoc = wlan_vdev_get_psoc(vdev);
 	if (!psoc)
 		return QDF_STATUS_E_FAILURE;

+ 52 - 2
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -1879,7 +1879,7 @@ policy_mgr_is_vdev_ll_sap(struct wlan_objmgr_psoc *psoc,
 			  uint32_t vdev_id);
 
 /**
- * policy_mgr_is_vdev_ht_ll_sap() - Check whether given vdev is HT LL SAP or not
+ * policy_mgr_is_vdev_ll_ht_sap() - Check whether given vdev is HT LL SAP or not
  * @psoc: psoc object
  * @vdev_id: vdev id
  *
@@ -1889,7 +1889,7 @@ policy_mgr_is_vdev_ll_sap(struct wlan_objmgr_psoc *psoc,
  * Return: true if it's present otherwise false
  */
 bool
-policy_mgr_is_vdev_ht_ll_sap(struct wlan_objmgr_psoc *psoc,
+policy_mgr_is_vdev_ll_ht_sap(struct wlan_objmgr_psoc *psoc,
 			     uint32_t vdev_id);
 
 /**
@@ -5478,4 +5478,54 @@ bool policy_mgr_get_nan_sap_scc_on_lte_coex_chnl(struct wlan_objmgr_psoc *psoc);
  */
 QDF_STATUS
 policy_mgr_reset_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_sap_mode_count() - Get SAP interface counts
+ * @psoc: psoc object
+ * @list: To provide the indices on pm_conc_connection_list
+ *	(optional)
+ *
+ * Return: No of SAP interface counts
+ */
+uint32_t policy_mgr_get_sap_mode_count(struct wlan_objmgr_psoc *psoc,
+				       uint32_t *list);
+
+/**
+ * policy_mgr_get_beaconing_mode_count() - Get Beaconing interface counts
+ * @psoc: psoc object
+ * @list: To provide the indices on pm_conc_connection_list
+ *	(optional)
+ *
+ * Return: No of Beaconing interface counts
+ */
+uint32_t policy_mgr_get_beaconing_mode_count(struct wlan_objmgr_psoc *psoc,
+					     uint32_t *list);
+
+/**
+ * policy_mgr_get_sap_mode_info() - Get active SAP channels and vdev ids
+ * @psoc: PSOC object information
+ * @ch_freq_list: Mode specific channel freq list
+ * @vdev_id: Mode specific vdev id (list)
+ *
+ * Get active SAP channel and vdev id
+ *
+ * Return: number of SAP connections found
+ */
+uint32_t policy_mgr_get_sap_mode_info(struct wlan_objmgr_psoc *psoc,
+				      uint32_t *ch_freq_list, uint8_t *vdev_id);
+
+/**
+ * policy_mgr_get_beaconing_mode_info() - Get active beaconing entity
+ * channels and vdev ids
+ * @psoc: PSOC object information
+ * @ch_freq_list: Mode specific channel freq list
+ * @vdev_id: Mode specific vdev id (list)
+ *
+ * Get active beaconing entity channels and vdev ids
+ *
+ * Return: number of beaconing entities found
+ */
+uint32_t policy_mgr_get_beaconing_mode_info(struct wlan_objmgr_psoc *psoc,
+					    uint32_t *ch_freq_list,
+					    uint8_t *vdev_id);
 #endif /* __WLAN_POLICY_MGR_API_H */

+ 3 - 0
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h

@@ -129,11 +129,14 @@ enum sap_csa_reason_code {
  * @link_ctrl_f_dynamic_force_link_num: indicate fw to use force link number
  * instead of force link bitmaps. Used with MLO_LINK_FORCE_MODE_ACTIVE_NUM.
  * MLO_LINK_FORCE_MODE_INACTIVE_NUM, MLO_LINK_FORCE_MODE_NO_FORCE.
+ * @link_ctrl_f_post_re_evaluate: run link state check again after command
+ * response handled.
  */
 enum link_control_flags {
 	link_ctrl_f_overwrite_active_bitmap =   1 << 0,
 	link_ctrl_f_overwrite_inactive_bitmap = 1 << 1,
 	link_ctrl_f_dynamic_force_link_num =    1 << 2,
+	link_ctrl_f_post_re_evaluate =          1 << 3,
 };
 
 /**

+ 281 - 10
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -3231,6 +3231,35 @@ uint32_t policy_mgr_mode_specific_connection_count(
 	return count;
 }
 
+uint32_t policy_mgr_get_sap_mode_count(struct wlan_objmgr_psoc *psoc,
+				       uint32_t *list)
+{
+	uint32_t count;
+
+	count = policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE,
+							  list);
+
+	count += policy_mgr_mode_specific_connection_count(
+						psoc,
+						PM_LL_LT_SAP_MODE,
+						list ? &list[count] : NULL);
+	return count;
+}
+
+uint32_t policy_mgr_get_beaconing_mode_count(struct wlan_objmgr_psoc *psoc,
+					     uint32_t *list)
+{
+	uint32_t count;
+
+	count = policy_mgr_get_sap_mode_count(psoc, list);
+
+	count += policy_mgr_mode_specific_connection_count(
+						psoc,
+						PM_P2P_GO_MODE,
+						list ? &list[count] : NULL);
+	return count;
+}
+
 QDF_STATUS policy_mgr_check_conn_with_mode_and_vdev_id(
 		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode,
 		uint32_t vdev_id)
@@ -4714,6 +4743,7 @@ policy_mgr_handle_link_enable_disable_resp(struct wlan_objmgr_vdev *vdev,
 	struct mlo_link_set_active_req *req = arg;
 	struct wlan_objmgr_psoc *psoc;
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	psoc = wlan_vdev_get_psoc(vdev);
 	if (!psoc) {
@@ -4776,10 +4806,17 @@ policy_mgr_handle_link_enable_disable_resp(struct wlan_objmgr_vdev *vdev,
 
 complete_evnt:
 	policy_mgr_set_link_in_progress(pm_ctx, false);
+	if (ml_is_nlink_service_supported(psoc) &&
+	    req && resp && !resp->status &&
+	    req->param.control_flags.post_re_evaluate)
+		status = ml_nlink_conn_change_notify(
+			psoc, wlan_vdev_get_id(vdev),
+			ml_nlink_connection_updated_evt, NULL);
 	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 
 	/* reschedule force scc workqueue after link state changes */
-	if (req && resp && !resp->status)
+	if (req && resp && !resp->status &&
+	    status == QDF_STATUS_SUCCESS)
 		policy_mgr_check_concurrent_intf_and_restart_sap(psoc, false);
 }
 #else
@@ -5334,6 +5371,38 @@ uint32_t policy_mgr_get_mode_specific_conn_info(
 	return count;
 }
 
+uint32_t policy_mgr_get_sap_mode_info(struct wlan_objmgr_psoc *psoc,
+				      uint32_t *ch_freq_list, uint8_t *vdev_id)
+{
+	uint32_t count;
+
+	count = policy_mgr_get_mode_specific_conn_info(psoc, ch_freq_list,
+						       vdev_id, PM_SAP_MODE);
+
+	count += policy_mgr_get_mode_specific_conn_info(
+				psoc,
+				ch_freq_list ? &ch_freq_list[count] : NULL,
+				vdev_id ? &vdev_id[count] : NULL,
+				PM_LL_LT_SAP_MODE);
+	return count;
+}
+
+uint32_t policy_mgr_get_beaconing_mode_info(struct wlan_objmgr_psoc *psoc,
+					    uint32_t *ch_freq_list,
+					    uint8_t *vdev_id)
+{
+	uint32_t count;
+
+	count = policy_mgr_get_sap_mode_info(psoc, ch_freq_list, vdev_id);
+
+	count += policy_mgr_get_mode_specific_conn_info(
+				psoc,
+				ch_freq_list ? &ch_freq_list[count] : NULL,
+				vdev_id ? &vdev_id[count] : NULL,
+				PM_P2P_GO_MODE);
+	return count;
+}
+
 void policy_mgr_get_ml_and_non_ml_sta_count(struct wlan_objmgr_psoc *psoc,
 					    uint8_t *num_ml, uint8_t *ml_idx,
 					    uint8_t *num_non_ml,
@@ -6019,6 +6088,104 @@ policy_mgr_get_active_vdev_bitmap(struct wlan_objmgr_psoc *psoc)
 	return pm_ctx->active_vdev_bitmap;
 }
 
+/**
+ * policy_mgr_mlo_sta_set_link_by_linkid() - wrapper API to call set link
+ * by link id bitmap API
+ * @psoc: psoc object
+ * @vdev: vdev object
+ * @reason: Reason for which link is forced
+ * @mode: Force reason
+ * @link_num: valid for MLO_LINK_FORCE_MODE_ACTIVE_NUM and
+ *  MLO_LINK_FORCE_MODE_INACTIVE_NUM.
+ * @num_mlo_vdev: number of mlo vdev in array mlo_vdev_lst
+ * @mlo_vdev_lst: MLO STA vdev list
+ * @num_mlo_inactive_vdev: number of mlo vdev in array mlo_inactive_vdev_lst
+ * @mlo_inactive_vdev_lst: MLO STA vdev list
+ *
+ * This is internal wrapper of policy_mgr_mlo_sta_set_nlink to convert
+ * vdev based set link to link id based API for being compatible with old code.
+ * New code to use policy_mgr_mlo_sta_set_nlink directly as much as possible.
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+policy_mgr_mlo_sta_set_link_by_linkid(struct wlan_objmgr_psoc *psoc,
+				      struct wlan_objmgr_vdev *vdev,
+				      enum mlo_link_force_reason reason,
+				      enum mlo_link_force_mode mode,
+				      uint8_t link_num,
+				      uint8_t num_mlo_vdev,
+				      uint8_t *mlo_vdev_lst,
+				      uint8_t num_mlo_inactive_vdev,
+				      uint8_t *mlo_inactive_vdev_lst)
+{
+	uint32_t link_bitmap = 0;
+	uint32_t link_bitmap2 = 0;
+	uint32_t assoc_bitmap = 0;
+	uint32_t vdev_bitmap[MLO_VDEV_BITMAP_SZ];
+	uint32_t vdev_bitmap2[MLO_VDEV_BITMAP_SZ];
+	uint8_t i, idx;
+	uint32_t link_control_flags = 0;
+
+	qdf_mem_zero(vdev_bitmap, sizeof(vdev_bitmap));
+	qdf_mem_zero(vdev_bitmap2, sizeof(vdev_bitmap2));
+
+	for (i = 0; i < num_mlo_vdev; i++) {
+		idx = mlo_vdev_lst[i] / 32;
+		if (idx >= MLO_VDEV_BITMAP_SZ)
+			return QDF_STATUS_E_INVAL;
+		vdev_bitmap[idx] |= 1 << (mlo_vdev_lst[i] % 32);
+	}
+
+	for (i = 0; i < num_mlo_inactive_vdev; i++) {
+		idx = mlo_inactive_vdev_lst[i] / 32;
+		if (idx >= MLO_VDEV_BITMAP_SZ)
+			return QDF_STATUS_E_INVAL;
+		vdev_bitmap2[idx] |= 1 << (mlo_inactive_vdev_lst[i] % 32);
+	}
+
+	ml_nlink_convert_vdev_bitmap_to_linkid_bitmap(
+		psoc, vdev, MLO_VDEV_BITMAP_SZ, vdev_bitmap,
+		&link_bitmap, &assoc_bitmap);
+
+	ml_nlink_convert_vdev_bitmap_to_linkid_bitmap(
+		psoc, vdev, MLO_VDEV_BITMAP_SZ, vdev_bitmap2,
+		&link_bitmap2, &assoc_bitmap);
+
+	switch (mode) {
+	case MLO_LINK_FORCE_MODE_ACTIVE:
+		link_control_flags = link_ctrl_f_overwrite_active_bitmap;
+		break;
+	case MLO_LINK_FORCE_MODE_INACTIVE:
+		if (reason != MLO_LINK_FORCE_REASON_LINK_REMOVAL)
+			link_control_flags =
+				link_ctrl_f_overwrite_inactive_bitmap;
+		break;
+	case MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE:
+		if (reason != MLO_LINK_FORCE_REASON_LINK_REMOVAL)
+			link_control_flags =
+				link_ctrl_f_overwrite_active_bitmap |
+				link_ctrl_f_overwrite_inactive_bitmap;
+		break;
+	case MLO_LINK_FORCE_MODE_ACTIVE_NUM:
+		link_control_flags = link_ctrl_f_dynamic_force_link_num;
+		break;
+	case MLO_LINK_FORCE_MODE_INACTIVE_NUM:
+		link_control_flags = link_ctrl_f_dynamic_force_link_num;
+		break;
+	case MLO_LINK_FORCE_MODE_NO_FORCE:
+		link_control_flags = 0;
+		break;
+	default:
+		policy_mgr_err("Invalid force mode: %d", mode);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return policy_mgr_mlo_sta_set_nlink(psoc, vdev, reason, mode,
+					    link_num, link_bitmap,
+					    link_bitmap2, link_control_flags);
+}
+
 /**
  * policy_mgr_mlo_sta_set_link_ext() - Set links for MLO STA
  * @psoc: psoc object
@@ -6074,8 +6241,6 @@ policy_mgr_mlo_sta_set_link_ext(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	policy_mgr_set_link_in_progress(pm_ctx, true);
-
 	policy_mgr_debug("vdev %d: mode %d num_mlo_vdev %d reason %d",
 			 wlan_vdev_get_id(vdev), mode, num_mlo_vdev, reason);
 
@@ -6108,6 +6273,28 @@ policy_mgr_mlo_sta_set_link_ext(struct wlan_objmgr_psoc *psoc,
 		req->param.link_num[0].num_of_link = num_mlo_vdev - 1;
 	}
 
+	if (ml_is_nlink_service_supported(psoc)) {
+		status =
+		policy_mgr_mlo_sta_set_link_by_linkid(psoc, vdev, reason,
+						      mode,
+						      req->param.link_num[0].
+						      num_of_link,
+						      num_mlo_vdev,
+						      mlo_vdev_lst,
+						      num_mlo_inactive_vdev,
+						      mlo_inactive_vdev_lst);
+		qdf_mem_free(req);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+
+		if (status != QDF_STATUS_E_PENDING) {
+			policy_mgr_err("set_link_by_linkid status %d", status);
+			return status;
+		}
+		return QDF_STATUS_SUCCESS;
+	}
+
+	policy_mgr_set_link_in_progress(pm_ctx, true);
+
 	status = mlo_ser_set_link_req(req);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		policy_mgr_err("vdev %d: Failed to set link mode %d num_mlo_vdev %d reason %d",
@@ -6141,7 +6328,7 @@ policy_mgr_mlo_sta_set_nlink(struct wlan_objmgr_psoc *psoc,
 			     uint32_t link_control_flags)
 {
 	struct mlo_link_set_active_req *req;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
 
 	pm_ctx = policy_mgr_get_context(psoc);
@@ -6162,9 +6349,11 @@ policy_mgr_mlo_sta_set_nlink(struct wlan_objmgr_psoc *psoc,
 
 	policy_mgr_set_link_in_progress(pm_ctx, true);
 
-	policy_mgr_debug("vdev %d: mode %d %s reason %d",
+	policy_mgr_debug("vdev %d: mode %d %s reason %d bitmap 0x%x 0x%x ctrl 0x%x",
 			 wlan_vdev_get_id(vdev), mode,
-			 force_mode_to_string(mode), reason);
+			 force_mode_to_string(mode), reason,
+			 link_bitmap, link_bitmap2,
+			 link_control_flags);
 
 	req->ctx.vdev = vdev;
 	req->param.reason = reason;
@@ -6180,6 +6369,8 @@ policy_mgr_mlo_sta_set_nlink(struct wlan_objmgr_psoc *psoc,
 									true;
 	if (link_control_flags & link_ctrl_f_dynamic_force_link_num)
 		req->param.control_flags.dynamic_force_link_num = true;
+	if (link_control_flags & link_ctrl_f_post_re_evaluate)
+		req->param.control_flags.post_re_evaluate = true;
 
 	status =
 	wlan_vdev_get_bss_peer_mld_mac(vdev,
@@ -6383,6 +6574,66 @@ policy_mgr_is_mlo_sap_concurrency_allowed(struct wlan_objmgr_psoc *psoc,
 	return ret;
 }
 
+QDF_STATUS
+policy_mgr_link_switch_notifier_cb(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_mlo_link_switch_req *req)
+{
+	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint8_t vdev_id = req->vdev_id;
+	uint8_t curr_ieee_link_id = req->curr_ieee_link_id;
+	uint8_t new_ieee_link_id = req->new_ieee_link_id;
+	uint32_t new_primary_freq = req->new_primary_freq;
+	QDF_STATUS status;
+	union conc_ext_flag conc_ext_flags;
+	struct policy_mgr_conc_connection_info
+			info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} };
+	uint8_t num_del = 0;
+	struct ml_nlink_change_event data;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	policy_mgr_debug("target link %d freq %d curr link %d vdev %d",
+			 new_ieee_link_id, new_primary_freq,
+			 curr_ieee_link_id, vdev_id);
+	qdf_mem_zero(&data, sizeof(data));
+	data.evt.link_switch.curr_ieee_link_id = curr_ieee_link_id;
+	data.evt.link_switch.new_ieee_link_id = new_ieee_link_id;
+	data.evt.link_switch.new_primary_freq = new_primary_freq;
+	status = ml_nlink_conn_change_notify(psoc, vdev_id,
+					     ml_nlink_link_switch_start_evt,
+					     &data);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+
+	policy_mgr_store_and_del_conn_info_by_vdev_id(
+		psoc, vdev_id, info, &num_del);
+	conc_ext_flags.value =
+	policy_mgr_get_conc_ext_flags(vdev, true);
+	if (!policy_mgr_is_concurrency_allowed(psoc, PM_STA_MODE,
+					       new_primary_freq,
+					       HW_MODE_20_MHZ,
+					       conc_ext_flags.value,
+					       NULL)) {
+		status = QDF_STATUS_E_INVAL;
+		policy_mgr_debug("target link %d freq %d not allowed by conc rule",
+				 new_ieee_link_id, new_primary_freq);
+	}
+
+	if (num_del > 0)
+		policy_mgr_restore_deleted_conn_info(psoc, info, num_del);
+
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+
 bool policy_mgr_is_non_ml_sta_present(struct wlan_objmgr_psoc *psoc)
 {
 	uint32_t conn_index = 0;
@@ -8058,7 +8309,7 @@ void policy_mgr_activate_mlo_links(struct wlan_objmgr_psoc *psoc,
 	if (active_vdev_cnt &&
 	    policy_mgr_is_emlsr_sta_concurrency_present(psoc)) {
 		policy_mgr_debug("Concurrency exists, cannot enter EMLSR mode");
-		goto done;
+		goto ref_release;
 	}
 
 	/*
@@ -8078,7 +8329,7 @@ void policy_mgr_activate_mlo_links(struct wlan_objmgr_psoc *psoc,
 					    MLO_LINK_FORCE_REASON_DISCONNECT,
 					    MLO_LINK_FORCE_MODE_ACTIVE,
 					    active_vdev_cnt, active_vdev_lst);
-
+ref_release:
 	for (idx = 0; idx < ml_vdev_cnt; idx++)
 		mlo_release_vdev_ref(tmp_vdev_lst[idx]);
 done:
@@ -8311,8 +8562,6 @@ policy_mgr_process_mlo_sta_dynamic_force_num_link(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	policy_mgr_set_link_in_progress(pm_ctx, true);
-
 	policy_mgr_debug("vdev %d: mode %d num_mlo_vdev %d reason %d",
 			 wlan_vdev_get_id(vdev), mode, num_mlo_vdev, reason);
 
@@ -8341,6 +8590,28 @@ policy_mgr_process_mlo_sta_dynamic_force_num_link(struct wlan_objmgr_psoc *psoc,
 	req->param.link_num[0].num_of_link = force_active_cnt;
 	req->param.control_flags.dynamic_force_link_num = 1;
 
+	if (ml_is_nlink_service_supported(psoc)) {
+		status =
+		policy_mgr_mlo_sta_set_link_by_linkid(psoc, vdev, reason,
+						      mode,
+						      req->param.link_num[0].
+						      num_of_link,
+						      num_mlo_vdev,
+						      mlo_vdev_lst,
+						      0,
+						      NULL);
+		qdf_mem_free(req);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+
+		if (status != QDF_STATUS_E_PENDING) {
+			policy_mgr_err("set_link_by_linkid status %d", status);
+			return status;
+		}
+		return QDF_STATUS_SUCCESS;
+	}
+
+	policy_mgr_set_link_in_progress(pm_ctx, true);
+
 	status = mlo_ser_set_link_req(req);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		policy_mgr_err("vdev %d: Failed to set link mode %d num_mlo_vdev %d force_active_cnt: %d, reason %d",

+ 14 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h

@@ -787,6 +787,20 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status,
 #ifdef WLAN_FEATURE_11BE_MLO
 void
 policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx);
+
+/**
+ * policy_mgr_link_switch_notifier_cb() - link switch notifier callback
+ * @vdev: vdev object
+ * @req: link switch request
+ *
+ * This API will be registered to mlo link switch, to be invoked before
+ * do link switch process.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+policy_mgr_link_switch_notifier_cb(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_mlo_link_switch_req *req);
 #else
 static inline void
 policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx) {}

+ 58 - 1
components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c

@@ -140,6 +140,49 @@ static void policy_mgr_vdev_obj_status_cb(struct wlan_objmgr_vdev *vdev,
 	return;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static QDF_STATUS policy_mgr_register_link_switch_notifier(void)
+{
+	QDF_STATUS status;
+
+	status = mlo_mgr_register_link_switch_notifier(
+			WLAN_UMAC_COMP_POLICY_MGR,
+			policy_mgr_link_switch_notifier_cb);
+	if (status == QDF_STATUS_E_NOSUPPORT) {
+		status = QDF_STATUS_SUCCESS;
+		policy_mgr_debug("Link switch not supported");
+	} else if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register link switch notifier for policy mgr!");
+	}
+
+	return status;
+}
+
+static QDF_STATUS policy_mgr_unregister_link_switch_notifier(void)
+{
+	QDF_STATUS status;
+
+	status = mlo_mgr_unregister_link_switch_notifier(
+			WLAN_UMAC_COMP_POLICY_MGR);
+	if (status == QDF_STATUS_E_NOSUPPORT)
+		status = QDF_STATUS_SUCCESS;
+	else if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to unregister link switch notifier for policy mgr!");
+
+	return status;
+}
+#else
+static QDF_STATUS policy_mgr_register_link_switch_notifier(void)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_unregister_link_switch_notifier(void)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 QDF_STATUS policy_mgr_init(void)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -215,10 +258,20 @@ QDF_STATUS policy_mgr_init(void)
 		goto err_vdev_status;
 	}
 
+	status = policy_mgr_register_link_switch_notifier();
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register link switch cback");
+		goto err_link_switch;
+	}
+
 	policy_mgr_notice("Callbacks registered with obj mgr");
 
 	return QDF_STATUS_SUCCESS;
-
+err_link_switch:
+	wlan_objmgr_unregister_vdev_status_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_vdev_obj_status_cb,
+				NULL);
 err_vdev_status:
 	wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_POLICY_MGR,
 						policy_mgr_vdev_obj_destroy_cb,
@@ -255,6 +308,10 @@ QDF_STATUS policy_mgr_deinit(void)
 {
 	QDF_STATUS status;
 
+	status = policy_mgr_unregister_link_switch_notifier();
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister link switch cback");
+
 	status = wlan_objmgr_unregister_psoc_status_handler(
 				WLAN_UMAC_COMP_POLICY_MGR,
 				policy_mgr_psoc_obj_status_cb,

+ 1 - 1
components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -4396,7 +4396,7 @@ policy_mgr_is_vdev_ll_sap(struct wlan_objmgr_psoc *psoc,
 }
 
 bool
-policy_mgr_is_vdev_ht_ll_sap(struct wlan_objmgr_psoc *psoc,
+policy_mgr_is_vdev_ll_ht_sap(struct wlan_objmgr_psoc *psoc,
 			     uint32_t vdev_id)
 {
 	return _policy_mgr_is_vdev_ll_sap(psoc, vdev_id, LL_AP_TYPE_HT);

+ 8 - 8
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_sbs_i.h

@@ -278,7 +278,7 @@ static pm_dbs_pcl_third_connection_table_type
 pm_third_connection_pcl_dbs_sbs_2x2_table = {
 	[PM_STA_SAP_SCC_24_1x1] = {
 	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
-	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
 	[PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G},
 	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
 	[PM_NAN_DISC_MODE] = {
@@ -289,7 +289,7 @@ pm_third_connection_pcl_dbs_sbs_2x2_table = {
 
 	[PM_STA_SAP_SCC_24_2x2] = {
 	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
-	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
 	[PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G},
 	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
 	[PM_NAN_DISC_MODE] = {
@@ -440,7 +440,7 @@ pm_third_connection_pcl_dbs_sbs_2x2_table = {
 
 	[PM_SAP_SAP_SCC_24_1x1] = {
 	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
-	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
 	[PM_P2P_CLIENT_MODE] = {
 		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
 	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
@@ -452,7 +452,7 @@ pm_third_connection_pcl_dbs_sbs_2x2_table = {
 
 	[PM_SAP_SAP_SCC_24_2x2] = {
 	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
-	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
 	[PM_P2P_CLIENT_MODE] = {
 		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
 	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
@@ -1503,7 +1503,7 @@ pm_third_connection_pcl_dbs_sbs_2x2_table = {
 
 	[PM_STA_P2P_CLI_SCC_5_1x1] = {
 	[PM_STA_MODE] = {
-		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+		PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G},
 	[PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G},
 	[PM_P2P_CLIENT_MODE] = {
 		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
@@ -1517,7 +1517,7 @@ pm_third_connection_pcl_dbs_sbs_2x2_table = {
 
 	[PM_STA_P2P_CLI_SCC_5_2x2] = {
 	[PM_STA_MODE] = {
-		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+		PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G},
 	[PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G},
 	[PM_P2P_CLIENT_MODE] = {
 		PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G},
@@ -1531,7 +1531,7 @@ pm_third_connection_pcl_dbs_sbs_2x2_table = {
 
 	[PM_STA_P2P_CLI_MCC_5_1x1] = {
 	[PM_STA_MODE] = {
-		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+		PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G},
 	[PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G},
 	[PM_P2P_CLIENT_MODE] = {
 		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
@@ -1545,7 +1545,7 @@ pm_third_connection_pcl_dbs_sbs_2x2_table = {
 
 	[PM_STA_P2P_CLI_MCC_5_2x2] = {
 	[PM_STA_MODE] = {
-		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+		PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G},
 	[PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G},
 	[PM_P2P_CLIENT_MODE] = {
 		PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G},

+ 4 - 4
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -269,12 +269,12 @@ QDF_STATUS ucfg_mc_cp_stats_cca_stats_get(struct wlan_objmgr_vdev *vdev,
 /**
  * ucfg_mc_cp_stats_set_rate_flags() - API to set rate flags
  * @vdev: pointer to vdev object
- * @flags: value to set (enum tx_rate_info)
+ * @flags: value to set
  *
  * Return: status of operation
  */
 QDF_STATUS ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev,
-					   enum tx_rate_info flags);
+					   uint32_t flags);
 
 /**
  * ucfg_mc_cp_stats_register_lost_link_info_cb() - API to register lost link
@@ -425,7 +425,7 @@ static inline QDF_STATUS ucfg_mc_cp_stats_send_stats_request(
 
 static inline QDF_STATUS ucfg_mc_cp_stats_set_rate_flags(
 				struct wlan_objmgr_vdev *vdev,
-				enum tx_rate_info flags)
+				uint32_t flags)
 {
 	return QDF_STATUS_SUCCESS;
 }

+ 9 - 1
components/dp/core/src/wlan_dp_main.c

@@ -1881,6 +1881,10 @@ wlan_dp_rx_fisa_attach_target(struct wlan_dp_psoc_context *dp_ctx)
 		return status;
 	}
 
+	/* return success to let init process go */
+	if (status == QDF_STATUS_E_NOSUPPORT)
+		return QDF_STATUS_SUCCESS;
+
 	if (status == QDF_STATUS_SUCCESS) {
 		status = dp_rx_fisa_config(dp_ctx);
 		if (QDF_IS_STATUS_ERROR(status)) {
@@ -2147,7 +2151,7 @@ QDF_STATUS wlan_dp_txrx_pdev_attach(ol_txrx_soc_handle soc)
 	struct cdp_pdev_attach_params pdev_params = { 0 };
 	QDF_STATUS qdf_status;
 
-	dp_ctx =  dp_get_context();
+	dp_ctx = dp_get_context();
 
 	pdev_params.htc_handle = cds_get_context(QDF_MODULE_ID_HTC);
 	pdev_params.qdf_osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
@@ -2161,6 +2165,10 @@ QDF_STATUS wlan_dp_txrx_pdev_attach(ol_txrx_soc_handle soc)
 	/* FISA Attach */
 	qdf_status = wlan_dp_rx_fisa_attach(dp_ctx);
 	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		/* return success to let init process go */
+		if (qdf_status == QDF_STATUS_E_NOSUPPORT)
+			return QDF_STATUS_SUCCESS;
+
 		wlan_dp_txrx_pdev_detach(cds_get_context(QDF_MODULE_ID_SOC),
 					 OL_TXRX_PDEV_ID, false);
 		return qdf_status;

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

@@ -759,7 +759,6 @@ struct enhance_roam_info {
  * @connect_info: mlme connect information
  * @wait_key_timer: wait key timer
  * @eht_config: Eht capability configuration
- * @is_mlo_sta_link_removed: link on vdev has been removed by AP
  * @last_delba_sent_time: Last delba sent time to handle back to back delba
  *			  requests from some IOT APs
  * @ba_2k_jump_iot_ap: This is set to true if connected to the ba 2k jump IOT AP
@@ -827,9 +826,6 @@ struct mlme_legacy_priv {
 	struct wait_for_key_timer wait_key_timer;
 #ifdef WLAN_FEATURE_11BE
 	tDot11fIEeht_cap eht_config;
-#endif
-#if defined(WLAN_FEATURE_11BE_MLO)
-	bool is_mlo_sta_link_removed;
 #endif
 	qdf_time_t last_delba_sent_time;
 	bool ba_2k_jump_iot_ap;

+ 38 - 44
components/mlme/core/src/wlan_mlme_main.c

@@ -2405,27 +2405,28 @@ static void mlme_init_sta_mlo_cfg(struct wlan_objmgr_psoc *psoc,
 		cfg_default(CFG_MLO_MAX_SIMULTANEOUS_LINKS);
 	sta->mlo_prefer_percentage =
 		cfg_get(psoc, CFG_MLO_PREFER_PERCENTAGE);
+	sta->mlo_same_link_mld_address =
+		cfg_default(CFG_MLO_SAME_LINK_MLD_ADDR);
 }
 
 static bool
 wlan_get_vdev_link_removed_flag(struct wlan_objmgr_vdev *vdev)
 {
-	struct mlme_legacy_priv *mlme_priv;
-	bool is_mlo_link_removed;
+	bool is_mlo_link_removed = false;
+	uint8_t link_id;
+	struct mlo_link_info *link_info;
 
 	if (!mlo_is_mld_sta(vdev))
 		return false;
 
-	wlan_vdev_obj_lock(vdev);
-	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
-	if (!mlme_priv) {
-		wlan_vdev_obj_unlock(vdev);
-		mlme_legacy_err("vdev legacy private object is NULL");
-		return false;
-	}
-
-	is_mlo_link_removed = mlme_priv->is_mlo_sta_link_removed;
-	wlan_vdev_obj_unlock(vdev);
+	link_id = wlan_vdev_get_link_id(vdev);
+	link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id);
+	if (link_info)
+		is_mlo_link_removed =
+			!!qdf_atomic_test_bit(LS_F_AP_REMOVAL_BIT,
+					      &link_info->link_status_flags);
+	else
+		mlme_legacy_err("link info null, id %d", link_id);
 
 	return is_mlo_link_removed;
 }
@@ -2452,7 +2453,9 @@ bool wlan_get_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc,
 static QDF_STATUS
 wlan_set_vdev_link_removed_flag(struct wlan_objmgr_vdev *vdev, bool removed)
 {
-	struct mlme_legacy_priv *mlme_priv;
+	uint8_t link_id;
+	struct mlo_link_info *link_info;
+	bool is_mlo_link_removed;
 
 	if (!vdev) {
 		mlme_legacy_err("vdev NULL");
@@ -2464,23 +2467,26 @@ wlan_set_vdev_link_removed_flag(struct wlan_objmgr_vdev *vdev, bool removed)
 		return QDF_STATUS_E_INVAL;
 	}
 
-	wlan_vdev_obj_lock(vdev);
-	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
-	if (!mlme_priv) {
-		wlan_vdev_obj_unlock(vdev);
-		mlme_legacy_err("vdev legacy private object is NULL");
+	link_id = wlan_vdev_get_link_id(vdev);
+	link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id);
+	if (!link_info) {
+		mlme_legacy_err("link info null, id %d", link_id);
 		return QDF_STATUS_E_INVAL;
 	}
-
-	if (removed == mlme_priv->is_mlo_sta_link_removed) {
-		wlan_vdev_obj_unlock(vdev);
+	is_mlo_link_removed =
+		!!qdf_atomic_test_bit(LS_F_AP_REMOVAL_BIT,
+				      &link_info->link_status_flags);
+	if (removed == is_mlo_link_removed)
 		return QDF_STATUS_SUCCESS;
-	}
 
-	mlme_legacy_debug("mlo sta vdev %d link removed flag %d",
-			  wlan_vdev_get_id(vdev), removed);
-	mlme_priv->is_mlo_sta_link_removed = removed;
-	wlan_vdev_obj_unlock(vdev);
+	mlme_legacy_debug("mlo sta vdev %d link %d link removed flag %d",
+			  wlan_vdev_get_id(vdev), link_id, removed);
+	if (removed)
+		qdf_atomic_set_bit(LS_F_AP_REMOVAL_BIT,
+				   &link_info->link_status_flags);
+	else
+		qdf_atomic_clear_bit(LS_F_AP_REMOVAL_BIT,
+				     &link_info->link_status_flags);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -2514,31 +2520,19 @@ wlan_set_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc,
 
 void wlan_clear_mlo_sta_link_removed_flag(struct wlan_objmgr_vdev *vdev)
 {
-	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
-	uint16_t vdev_count = 0;
 	uint8_t i;
+	struct mlo_link_info *link_info;
 
 	if (!vdev || !mlo_is_mld_sta(vdev))
 		return;
 
-	mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
-	if (!vdev_count) {
-		mlme_legacy_err("vdev num 0 in mld dev");
+	link_info = mlo_mgr_get_ap_link(vdev);
+	if (!link_info)
 		return;
-	}
-
-	for (i = 0; i < vdev_count; i++) {
-		if (!wlan_vdev_list[i]) {
-			mlme_legacy_err("vdev is null in mld");
-			goto release_ref;
-		}
-
-		wlan_set_vdev_link_removed_flag(wlan_vdev_list[i], false);
-	}
 
-release_ref:
-	for (i = 0; i < vdev_count; i++)
-		mlo_release_vdev_ref(wlan_vdev_list[i]);
+	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++)
+		qdf_atomic_clear_bit(LS_F_AP_REMOVAL_BIT,
+				     &link_info[i].link_status_flags);
 }
 
 bool wlan_drop_mgmt_frame_on_link_removal(struct wlan_objmgr_vdev *vdev)

+ 32 - 4
components/mlme/dispatcher/inc/cfg_mlme_sta.h

@@ -573,7 +573,7 @@
  * mlo_support_link_num - Set number of link mlo connection supports for sta
  * @Min: 1
  * @Max: 3
- * @Default: 2
+ * @Default: 3
  *
  * This cfg is used to configure the number of link mlo connection supports
  *
@@ -589,7 +589,7 @@
 			"mlo_support_link_num", \
 			1, \
 			3, \
-			2, \
+			3, \
 			CFG_VALUE_OR_DEFAULT, \
 			"supported mlo link number")
 
@@ -690,6 +690,34 @@
 #define CFG_MLO_MAX_SIMULTANEOUS_LINKS_CFG
 #define CFG_MLO_PREFER_PERCENTAGE_CFG
 #endif
+
+/*
+ * <cfg>
+ * mlo_same_link_mld_addr - Use one of the links address as same mld address
+ * @Default: false
+ *
+ * This cfg is used to configure the one of link address as same mld address
+ *
+ * Related: None
+ *
+ * Supported Feature: STA
+ *
+ * Usage: Internal
+ *
+ *
+ * </cfg>
+ */
+#define CFG_MLO_SAME_LINK_MLD_ADDR CFG_BOOL( \
+			"mlo_same_link_mld_addr",\
+			0, \
+			"same address for mlo link/mld")
+
+#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+#define CFG_MLO_SAME_LINK_MLD_ADDR_CFG CFG(CFG_MLO_SAME_LINK_MLD_ADDR)
+#else
+#define CFG_MLO_SAME_LINK_MLD_ADDR_CFG
+#endif
+
 #define CFG_STA_ALL \
 	CFG(CFG_INFRA_STA_KEEP_ALIVE_PERIOD) \
 	CFG(CFG_STA_BSS_MAX_IDLE_PERIOD) \
@@ -714,6 +742,6 @@
 	CFG_MLO_SUPPORT_LINK_NUM_CFG \
 	CFG_MLO_MAX_SIMULTANEOUS_LINKS_CFG \
 	CFG_MLO_SUPPORT_LINK_BAND_CFG \
-	CFG_MLO_PREFER_PERCENTAGE_CFG
-
+	CFG_MLO_PREFER_PERCENTAGE_CFG \
+	CFG_MLO_SAME_LINK_MLD_ADDR_CFG
 #endif /* CFG_MLME_STA_H__ */

+ 60 - 0
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -1157,6 +1157,27 @@ wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 					   uint8_t vdev_id,
 					   enum phy_ch_width ch_width);
 
+/**
+ * wlan_mlme_update_bss_rate_flags() - update bss rate flag as per new channel
+ * width
+ * @psoc: pointer to psoc object
+ * @vdev_id: Vdev id
+ * @cw: channel width to update
+ * @eht_present: connected bss is eht capable or not
+ * @he_present: connected bss is he capable or not
+ * @vht_present: connected bss is vht capable or not
+ * @ht_present: connected bss is ht capable or not
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id,
+					   enum phy_ch_width cw,
+					   uint8_t eht_present,
+					   uint8_t he_present,
+					   uint8_t vht_present,
+					   uint8_t ht_present);
+
 #ifdef WLAN_FEATURE_11BE
 /**
  * mlme_update_tgt_eht_caps_in_cfg() - Update tgt eht cap in mlme component
@@ -3310,6 +3331,16 @@ wlan_mlme_set_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc,
  */
 uint32_t wlan_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * wlan_mlme_set_roaming_triggers() - Set the roaming triggers bitmap
+ * @psoc: Pointer to PSOC object
+ * @trigger_bitmap: Roaming triggers bitmap to set
+ *
+ * Return: void
+ */
+void wlan_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc,
+				    uint32_t trigger_bitmap);
+
 /**
  * wlan_mlme_get_roaming_offload() - Get roaming offload setting
  * @psoc: pointer to psoc object
@@ -3437,6 +3468,12 @@ uint32_t wlan_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc)
 	return 0xFFFF;
 }
 
+static inline
+void wlan_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc,
+				    uint32_t trigger_bitmap)
+{
+}
+
 static inline QDF_STATUS
 wlan_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc,
 			      bool *val)
@@ -3936,12 +3973,27 @@ bool wlan_mlme_is_multipass_sap(struct wlan_objmgr_psoc *psoc);
  */
 enum wlan_wds_mode
 wlan_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_mlme_set_wds_mode() - Set wds mode
+ * @psoc: pointer to psoc object
+ * @mode: wds mode to set
+ *
+ * Return: void
+ */
+void wlan_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc,
+			    enum wlan_wds_mode mode);
 #else
 static inline enum wlan_wds_mode
 wlan_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc)
 {
 	return WLAN_WDS_MODE_DISABLED;
 }
+
+static inline void wlan_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc,
+					  enum wlan_wds_mode mode)
+{
+}
 #endif
 
 #ifdef WLAN_SUPPORT_TWT
@@ -4086,6 +4138,14 @@ uint8_t wlan_mlme_get_sta_mlo_simultaneous_links(struct wlan_objmgr_psoc *psoc);
  */
 QDF_STATUS wlan_mlme_set_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc,
 					       uint8_t value);
+
+/**
+ * wlan_mlme_get_sta_same_link_mld_addr() - check if mld/link use same address
+ * @psoc: pointer to psoc object
+ *
+ * Return: bool to check if the mld/link use same mac address
+ */
+bool wlan_mlme_get_sta_same_link_mld_addr(struct wlan_objmgr_psoc *psoc);
 #else
 static inline QDF_STATUS
 wlan_mlme_set_user_set_link_num(struct wlan_objmgr_psoc *psoc,

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

@@ -1791,6 +1791,7 @@ enum station_prefer_bw {
  * @usr_scan_probe_unicast_ra:      User config unicast probe req in scan
  * @event_payload:                  Diagnostic event payload
  * @max_li_modulated_dtim_time_ms:  Max modulated DTIM time in ms.
+ * @mlo_same_link_mld_address:      Use one of the links same as mld address
  * @user_set_link_num:              save link num set by vendor command
  * @mlo_support_link_num:           max number of links that sta mlo supports
  * @mlo_support_link_band:          band bitmap that sta mlo supports
@@ -1826,6 +1827,7 @@ struct wlan_mlme_sta_cfg {
 #endif
 	uint16_t max_li_modulated_dtim_time_ms;
 #ifdef WLAN_FEATURE_11BE_MLO
+	bool mlo_same_link_mld_address;
 	uint8_t user_set_link_num;
 	uint8_t mlo_support_link_num;
 	uint8_t mlo_support_link_band;

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

@@ -1162,6 +1162,21 @@ ucfg_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc)
 {
 	return wlan_mlme_get_roaming_triggers(psoc);
 }
+
+/**
+ * ucfg_mlme_set_roaming_triggers() - Set roaming triggers bitmap
+ * value
+ * @psoc: pointer to psoc object
+ * @trigger_bitmap: Roaming triggers bitmap to set
+ *
+ * Return: void
+ */
+static inline void
+ucfg_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc,
+			       uint32_t trigger_bitmap)
+{
+	wlan_mlme_set_roaming_triggers(psoc, trigger_bitmap);
+}
 #else
 static inline QDF_STATUS
 ucfg_mlme_get_roam_disable_config(struct wlan_objmgr_psoc *psoc,
@@ -1191,6 +1206,12 @@ ucfg_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc)
 {
 	return 0xffff;
 }
+
+static inline void
+ucfg_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc,
+			       uint32_t trigger_bitmap)
+{
+}
 #endif
 
 /**
@@ -4728,6 +4749,27 @@ QDF_STATUS
 ucfg_mlme_set_vdev_traffic_low_latency(struct wlan_objmgr_psoc *psoc,
 				       uint8_t vdev_id, bool set);
 
+/**
+ * ucfg_mlme_update_bss_rate_flags() - update bss rate flag as per new channel
+ * width
+ * @psoc: pointer to psoc object
+ * @vdev_id: Vdev id
+ * @ch_width: channel width to update
+ * @eht_present: connected bss is eht capable or not
+ * @he_present: connected bss is he capable or not
+ * @vht_present: connected bss is vht capable or not
+ * @ht_present: connected bss is ht capable or not
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id,
+					   enum phy_ch_width ch_width,
+					   uint8_t eht_present,
+					   uint8_t he_present,
+					   uint8_t vht_present,
+					   uint8_t ht_present);
+
 /**
  * ucfg_mlme_send_ch_width_update_with_notify() - Send chwidth with notify
  * capability of FW
@@ -4982,6 +5024,19 @@ ucfg_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc)
 	return wlan_mlme_get_wds_mode(psoc);
 }
 
+/**
+ * ucfg_mlme_set_wds_mode() - Set the configured WDS mode
+ * @psoc: pointer to psoc object
+ * @mode: wds mode to set
+ *
+ * Return: void
+ */
+static inline void
+ucfg_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc, uint32_t mode)
+{
+	wlan_mlme_set_wds_mode(psoc, mode);
+}
+
 #ifdef WLAN_FEATURE_SON
 /**
  * ucfg_mlme_get_vdev_max_mcs_idx() - Get max mcs idx of given vdev

+ 222 - 0
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -37,6 +37,7 @@
 #include "target_if.h"
 #include "wlan_vdev_mgr_tgt_if_tx_api.h"
 #include "wmi_unified_vdev_api.h"
+#include "../../core/src/wlan_cp_stats_defs.h"
 
 /* quota in milliseconds */
 #define MCC_DUTY_CYCLE 70
@@ -1499,6 +1500,17 @@ wlan_mlme_get_mlo_prefer_percentage(struct wlan_objmgr_psoc *psoc,
 	*mlo_prefer_percentage = mlme_obj->cfg.sta.mlo_prefer_percentage;
 	mlme_legacy_debug("mlo_prefer_percentage %d", *mlo_prefer_percentage);
 }
+
+bool wlan_mlme_get_sta_same_link_mld_addr(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return false;
+
+	return mlme_obj->cfg.sta.mlo_same_link_mld_address;
+}
 #endif
 
 QDF_STATUS wlan_mlme_get_num_11b_tx_chains(struct wlan_objmgr_psoc *psoc,
@@ -5210,6 +5222,18 @@ uint32_t wlan_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc)
 	return mlme_obj->cfg.lfr.roam_trigger_bitmap;
 }
 
+void wlan_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc,
+				    uint32_t trigger_bitmap)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return;
+
+	mlme_obj->cfg.lfr.roam_trigger_bitmap = trigger_bitmap;
+}
+
 QDF_STATUS
 wlan_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc,
 			      bool *val)
@@ -6111,6 +6135,18 @@ wlan_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc)
 
 	return mlme_obj->cfg.gen.wds_mode;
 }
+
+void wlan_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc,
+			    enum wlan_wds_mode mode)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return;
+	if (mode <= WLAN_WDS_MODE_MAX)
+		mlme_obj->cfg.gen.wds_mode = mode;
+}
 #endif
 
 bool wlan_mlme_is_sta_mon_conc_supported(struct wlan_objmgr_psoc *psoc)
@@ -7025,6 +7061,192 @@ static QDF_STATUS wlan_mlme_update_ch_width(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+static uint32_t
+wlan_mlme_get_vht_rate_flags(enum phy_ch_width ch_width)
+{
+	uint32_t rate_flags = 0;
+
+	if (ch_width == CH_WIDTH_80P80MHZ || ch_width == CH_WIDTH_160MHZ)
+		rate_flags |= TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 |
+				TX_RATE_VHT20;
+	if (ch_width == CH_WIDTH_80MHZ)
+		rate_flags |= TX_RATE_VHT80 | TX_RATE_VHT40 | TX_RATE_VHT20;
+	else if (ch_width)
+		rate_flags |= TX_RATE_VHT40 | TX_RATE_VHT20;
+	else
+		rate_flags |= TX_RATE_VHT20;
+	return rate_flags;
+}
+
+static uint32_t wlan_mlme_get_ht_rate_flags(enum phy_ch_width ch_width)
+{
+	uint32_t rate_flags = 0;
+
+	if (ch_width)
+		rate_flags |= TX_RATE_HT40 | TX_RATE_HT20;
+	else
+		rate_flags |= TX_RATE_HT20;
+
+	return rate_flags;
+}
+
+#ifdef WLAN_FEATURE_11BE
+static uint32_t
+wlan_mlme_get_eht_rate_flags(enum phy_ch_width ch_width)
+{
+	uint32_t rate_flags = 0;
+
+	if (ch_width == CH_WIDTH_320MHZ)
+		rate_flags |= TX_RATE_EHT320 | TX_RATE_EHT160 |
+				TX_RATE_EHT80 | TX_RATE_EHT40 | TX_RATE_EHT20;
+	else if (ch_width == CH_WIDTH_160MHZ || ch_width == CH_WIDTH_80P80MHZ)
+		rate_flags |= TX_RATE_EHT160 | TX_RATE_EHT80 | TX_RATE_EHT40 |
+				TX_RATE_EHT20;
+	else if (ch_width == CH_WIDTH_80MHZ)
+		rate_flags |= TX_RATE_EHT80 | TX_RATE_EHT40 | TX_RATE_EHT20;
+	else if (ch_width)
+		rate_flags |= TX_RATE_EHT40 | TX_RATE_EHT20;
+	else
+		rate_flags |= TX_RATE_EHT20;
+
+	return rate_flags;
+}
+
+static QDF_STATUS
+wlan_mlme_set_bss_rate_flags_eht(uint32_t *rate_flags, uint8_t eht_present,
+				 enum phy_ch_width ch_width)
+{
+	if (!eht_present)
+		return QDF_STATUS_E_NOSUPPORT;
+
+	*rate_flags |= wlan_mlme_get_eht_rate_flags(ch_width);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static inline QDF_STATUS
+wlan_mlme_set_bss_rate_flags_eht(uint32_t *rate_flags, uint8_t eht_present,
+				 enum phy_ch_width ch_width)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
+#ifdef WLAN_FEATURE_11AX
+static uint32_t wlan_mlme_get_he_rate_flags(enum phy_ch_width ch_width)
+{
+	uint32_t rate_flags = 0;
+
+	if (ch_width == CH_WIDTH_160MHZ ||
+	    ch_width == CH_WIDTH_80P80MHZ)
+		rate_flags |= TX_RATE_HE160 | TX_RATE_HE80 | TX_RATE_HE40 |
+				TX_RATE_HE20;
+	else if (ch_width == CH_WIDTH_80MHZ)
+		rate_flags |= TX_RATE_HE80 | TX_RATE_HE40 | TX_RATE_HE20;
+	else if (ch_width)
+		rate_flags |= TX_RATE_HE40 | TX_RATE_HE20;
+	else
+		rate_flags |= TX_RATE_HE20;
+
+	return rate_flags;
+}
+
+static QDF_STATUS wlan_mlme_set_bss_rate_flags_he(uint32_t *rate_flags,
+						  uint8_t he_present,
+						  enum phy_ch_width ch_width)
+{
+	if (!he_present)
+		return QDF_STATUS_E_NOSUPPORT;
+
+	*rate_flags |= wlan_mlme_get_he_rate_flags(ch_width);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#else
+static inline QDF_STATUS
+wlan_mlme_set_bss_rate_flags_he(uint32_t *rate_flags,
+				uint8_t he_present,
+				enum phy_ch_width ch_width)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
+static QDF_STATUS
+wlan_mlme_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev,
+				  uint32_t flags)
+{
+	struct vdev_mc_cp_stats *vdev_mc_stats;
+	struct vdev_cp_stats *vdev_cp_stats_priv;
+
+	vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev);
+	if (!vdev_cp_stats_priv) {
+		cp_stats_err("vdev cp stats object is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv);
+	vdev_mc_stats = vdev_cp_stats_priv->vdev_stats;
+	vdev_mc_stats->tx_rate_flags = flags;
+	wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
+				enum phy_ch_width cw, uint8_t eht_present,
+				uint8_t he_present, uint8_t vht_present,
+				uint8_t ht_present)
+{
+	uint32_t *rate_flags;
+	struct vdev_mlme_obj *vdev_mlme;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	if (!eht_present && !he_present && !vht_present && !ht_present)
+		return QDF_STATUS_E_INVAL;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_HDD_ID_OBJ_MGR);
+	if (!vdev) {
+		mlme_debug("vdev: %d vdev not found", vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_debug("vdev: %d mlme obj not found", vdev_id);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	rate_flags = &vdev_mlme->mgmt.rate_info.rate_flags;
+	*rate_flags = 0;
+
+	status = wlan_mlme_set_bss_rate_flags_eht(rate_flags, eht_present, cw);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		status = wlan_mlme_set_bss_rate_flags_he(rate_flags,
+							 he_present, cw);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			if (vht_present)
+				*rate_flags = wlan_mlme_get_vht_rate_flags(cw);
+			else if (ht_present)
+				*rate_flags |= wlan_mlme_get_ht_rate_flags(cw);
+		}
+	}
+
+	mlme_debug("vdev:%d, eht:%u, he:%u, vht:%u, ht:%u, flag:%x, cw:%d",
+		   vdev_id, eht_present, he_present, vht_present, ht_present,
+		   *rate_flags, cw);
+
+	status = wlan_mlme_cp_stats_set_rate_flags(vdev, *rate_flags);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
+	return status;
+}
+
 QDF_STATUS
 wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 					   struct wlan_objmgr_vdev *vdev,

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

@@ -380,6 +380,19 @@ ucfg_mlme_is_chwidth_with_notify_supported(struct wlan_objmgr_psoc *psoc)
 				WLAN_VDEV_PARAM_CHWIDTH_WITH_NOTIFY_SUPPORT);
 }
 
+QDF_STATUS ucfg_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id,
+					   enum phy_ch_width ch_width,
+					   uint8_t eht_present,
+					   uint8_t he_present,
+					   uint8_t vht_present,
+					   uint8_t ht_present)
+{
+	return wlan_mlme_update_bss_rate_flags(psoc, vdev_id, ch_width,
+					       eht_present, he_present,
+					       vht_present, ht_present);
+}
+
 QDF_STATUS
 ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 					   uint8_t vdev_id,

+ 16 - 0
components/nan/core/inc/nan_public_structs.h

@@ -367,6 +367,16 @@ struct nan_datapath_inf_delete_rsp {
 	uint32_t reason;
 };
 
+/**
+ * struct ndp_additional_params - NDP parameters
+ * @csid_cap: NAN Cipher Suite Capability field
+ * @gtk: GTK protection is required for the NDP
+ */
+struct ndp_additional_params {
+	uint32_t csid_cap;
+	uint32_t gtk;
+};
+
 /**
  * struct nan_datapath_initiator_req - ndp initiator request params
  * @vdev: pointer to vdev object
@@ -384,6 +394,7 @@ struct nan_datapath_inf_delete_rsp {
  * @service_name: service name
  * @is_ipv6_addr_present: indicates if following ipv6 address is valid
  * @ipv6_addr: ipv6 address address used by ndp
+ * @ndp_add_params: NDP additional parameters
  */
 struct nan_datapath_initiator_req {
 	struct wlan_objmgr_vdev *vdev;
@@ -401,6 +412,7 @@ struct nan_datapath_initiator_req {
 	struct ndp_service_name service_name;
 	bool is_ipv6_addr_present;
 	uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE];
+	struct ndp_additional_params ndp_add_params;
 };
 
 /**
@@ -438,6 +450,7 @@ struct nan_datapath_initiator_rsp {
  * @port: port specified by for this NDP
  * @is_protocol_present: indicates if following protocol is valid
  * @protocol: protocol used by this NDP
+ * @ndp_add_params: NDP additional parameters
  */
 struct nan_datapath_responder_req {
 	struct wlan_objmgr_vdev *vdev;
@@ -456,6 +469,7 @@ struct nan_datapath_responder_req {
 	uint16_t port;
 	bool is_protocol_present;
 	uint8_t protocol;
+	struct ndp_additional_params ndp_add_params;
 };
 
 /**
@@ -717,6 +731,7 @@ struct nan_datapath_confirm_event {
  * @ipv6_addr: ipv6 address address used by ndp
  * @is_service_id_present: indicates if service id is present
  * @service_id: NDP service id
+ * @ndp_add_params: NDP additional parameters
  */
 struct nan_datapath_indication_event {
 	struct wlan_objmgr_vdev *vdev;
@@ -734,6 +749,7 @@ struct nan_datapath_indication_event {
 	uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE];
 	bool is_service_id_present;
 	uint8_t service_id[NDP_SERVICE_ID_LEN];
+	struct ndp_additional_params ndp_add_params;
 };
 
 /**

+ 5 - 0
components/pmo/core/inc/wlan_pmo_priv.h

@@ -35,6 +35,9 @@
 #include "wlan_pmo_wow_public_struct.h"
 #include "wlan_pmo_mc_addr_filtering_public_struct.h"
 
+#define PMO_PS_DATA_INACTIVITY_TIMEOUT (200)
+#define PMO_PS_DATA_SPEC_WAKE (0)
+
 /**
  * struct pmo_psoc_priv_obj - psoc related data require for pmo
  * @psoc_cfg: place holder for psoc configuration
@@ -100,6 +103,7 @@ struct wlan_pmo_ctx {
  * @addr_filter_pattern: addr filter pattern for vdev
  * @vdev_gtk_req: place holder for gtk request for vdev
  * @vdev_gtk_rsp_req: place holder for gtk response request for vdev
+ * @ps_params: OPM params
  * @gtk_err_enable: gtk error is enabled or not
  * @vdev_bpf_req: place holder for apf/bpf for vdev
  * @vdev_pkt_filter: place holder for vdev packet filter
@@ -130,6 +134,7 @@ struct pmo_vdev_priv_obj {
 	uint8_t addr_filter_pattern;
 	struct pmo_gtk_req vdev_gtk_req;
 	struct pmo_gtk_rsp_req vdev_gtk_rsp_req;
+	struct pmo_ps_params ps_params;
 	qdf_atomic_t gtk_err_enable;
 	bool magic_ptrn_enable;
 	bool ptrn_match_enable;

+ 42 - 0
components/pmo/core/inc/wlan_pmo_static_config.h

@@ -106,6 +106,48 @@ void pmo_set_sta_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size);
  */
 void pmo_set_sap_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size);
 
+/**
+ * pmo_core_vdev_set_ps_params() - set vdev ps_params
+ * @vdev: objmgr vdev handle
+ * @ps_params: vdev OPM parameters
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_vdev_set_ps_params(struct wlan_objmgr_vdev *vdev,
+				 struct pmo_ps_params *ps_params)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->ps_params = *ps_params;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+
+/**
+ * pmo_core_vdev_get_ps_params() - get vdev ps_params
+ * @vdev: objmgr vdev handle
+ * @ps_params: pointer to get vdev ps_params
+ *
+ * Return: QDF_STATUS
+ */
+static inline
+QDF_STATUS pmo_core_vdev_get_ps_params(struct wlan_objmgr_vdev *vdev,
+				       struct pmo_ps_params *ps_params)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	if (!vdev_ctx)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	*ps_params = vdev_ctx->ps_params;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+	return QDF_STATUS_SUCCESS;
+}
+
 #ifdef WLAN_FEATURE_NAN
 /**
  * pmo_set_ndp_wow_bitmask() - set predefined NDP wow wakeup events

+ 2 - 0
components/pmo/core/src/wlan_pmo_main.c

@@ -281,6 +281,8 @@ static void wlan_pmo_init_cfg(struct wlan_objmgr_psoc *psoc,
 	psoc_cfg->enable_sap_suspend = cfg_get(psoc, CFG_ENABLE_SAP_SUSPEND);
 	psoc_cfg->wow_data_inactivity_timeout =
 			cfg_get(psoc, CFG_PMO_WOW_DATA_INACTIVITY_TIMEOUT);
+	psoc_cfg->wow_spec_wake_interval =
+			cfg_get(psoc, CFG_PMO_WOW_SPEC_WAKE_INTERVAL);
 	psoc_cfg->active_uc_apf_mode =
 			cfg_get(psoc, CFG_ACTIVE_UC_APF_MODE);
 	psoc_cfg->active_mc_bc_apf_mode =

+ 20 - 6
components/pmo/core/src/wlan_pmo_suspend_resume.c

@@ -196,11 +196,18 @@ static void pmo_configure_vdev_suspend_params(
 					pmo_sta_ps_param_inactivity_time,
 					psoc_cfg->wow_data_inactivity_timeout);
 	if (QDF_IS_STATUS_ERROR(ret)) {
-		pmo_debug("Failed to Set wow inactivity timeout vdevId %d",
-			  vdev_id);
+		pmo_err("Failed to Set wow inactivity timeout vdevId %d",
+			vdev_id);
+	}
+	ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
+					     pmo_sta_ps_param_spec_wake_interval,
+					     psoc_cfg->wow_spec_wake_interval);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		pmo_err("Failed to Set wow spec wake interval vdevId %d",
+			vdev_id);
 	}
 
-	non_wow_inactivity_time = PS_DATA_INACTIVITY_TIMEOUT;
+	non_wow_inactivity_time = PMO_PS_DATA_INACTIVITY_TIMEOUT;
 	wow_inactivity_time = psoc_cfg->wow_data_inactivity_timeout;
 	/*
 	 * To keep ito repeat count same in wow mode as in non wow mode,
@@ -237,10 +244,17 @@ static void pmo_configure_vdev_resume_params(
 		return;
 	ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
 					 pmo_sta_ps_param_inactivity_time,
-					 PS_DATA_INACTIVITY_TIMEOUT);
+					 vdev_ctx->ps_params.ps_ito);
 	if (QDF_IS_STATUS_ERROR(ret)) {
-		pmo_debug("Failed to Set inactivity timeout vdevId %d",
-			  vdev_id);
+		pmo_err("Failed to Set inactivity timeout vdevId %d",
+			vdev_id);
+	}
+	ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
+					     pmo_sta_ps_param_spec_wake_interval,
+					     vdev_ctx->ps_params.spec_wake);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		pmo_err("Failed to Set wow spec wake interval vdevId %d",
+			vdev_id);
 	}
 }
 

+ 29 - 3
components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h

@@ -250,13 +250,14 @@
  * <ini>
  * gOptimizedPowerManagement - Optimized Power Management
  * @Min: 0
- * @Max: 1
+ * @Max: 2
  * @Default: 1
  *
  * This ini is used to set Optimized Power Management configuration:
  * Current values of gOptimizedPowerManagement:
  * 0 -> Disable optimized power management
  * 1 -> Enable optimized power management
+ * 2 -> User Defined
  *
  * Related: None
  *
@@ -269,7 +270,7 @@
 #define CFG_PMO_POWERSAVE_MODE CFG_INI_UINT( \
 	"gOptimizedPowerManagement", \
 	0, \
-	1, \
+	2, \
 	1, \
 	CFG_VALUE_OR_DEFAULT, \
 	"Optimized Power Management")
@@ -472,7 +473,8 @@
  * @Max: 255
  * @Default: 50
  *
- * This ini is used to set data inactivity timeout in wow mode.
+ * This ini is used to set data inactivity timeout in wow mode and
+ * the value is honored in firmware when User defined OPM is set
  *
  * Supported Feature: inactivity timeout in wow mode
  *
@@ -487,6 +489,29 @@
 		50, \
 		CFG_VALUE_OR_DEFAULT, \
 		"Data activity timeout in wow mode")
+/*
+ * <ini>
+ * g_wow_spec_wake_interval - OPM Speculative wake interval in wow mode.
+ * @Min: 0
+ * @Max: 255
+ * @Default: 0
+ *
+ * This ini is used to set OPM speculative wake interval in wow mode and
+ * the value is honored in firmware when User defined OPM is set
+ *
+ * Supported Feature: OPM Speculative wake interval in wow mode
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_PMO_WOW_SPEC_WAKE_INTERVAL CFG_INI_UINT( \
+		"g_wow_spec_wake_interval", \
+		0, \
+		255, \
+		0, \
+		CFG_VALUE_OR_DEFAULT, \
+		"Speculative wake interval in wow mode")
 /*
  * <ini>
  * gRArateLimitInterval - RA rate limit interval
@@ -757,6 +782,7 @@
 	CFG(CFG_PMO_ACTIVE_MODE) \
 	CFG(CFG_PMO_PWR_FAILURE) \
 	CFG(CFG_PMO_WOW_DATA_INACTIVITY_TIMEOUT) \
+	CFG(CFG_PMO_WOW_SPEC_WAKE_INTERVAL) \
 	CFG(CFG_RA_RATE_LIMIT_INTERVAL) \
 	CFG(CFG_PMO_MOD_DTIM_ON_SYS_SUSPEND) \
 	CFG(CFG_ENABLE_BUS_SUSPEND_IN_SAP_MODE) \

+ 20 - 1
components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h

@@ -102,6 +102,7 @@ enum pmo_beacon_dtim_policy {
  * @pmo_sta_ps_param_advanced_power_max_tx_before_wake: Number of TX frames
  *  before the entering the Active state
  * @pmo_sta_ps_param_ito_repeat_count: Indicates ito repeated count
+ * @pmo_sta_ps_param_spec_wake_interval: OPM speculative wake interval
  */
 enum pmo_sta_powersave_param {
 	pmo_sta_ps_param_rx_wake_policy = 0,
@@ -113,6 +114,7 @@ enum pmo_sta_powersave_param {
 	pmo_sta_ps_enable_advanced_power = 6,
 	pmo_sta_ps_param_advanced_power_max_tx_before_wake = 7,
 	pmo_sta_ps_param_ito_repeat_count = 8,
+	pmo_sta_ps_param_spec_wake_interval = 9,
 };
 
 /**
@@ -167,10 +169,12 @@ enum pmo_wow_enable_type {
  * enum powersave_mode - powersave_mode
  * @PMO_PS_ADVANCED_POWER_SAVE_DISABLE: Disable advanced power save mode
  * @PMO_PS_ADVANCED_POWER_SAVE_ENABLE: Enable power save mode
+ * @PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED: User Defined
  */
 enum powersave_mode {
 	PMO_PS_ADVANCED_POWER_SAVE_DISABLE = 0,
-	PMO_PS_ADVANCED_POWER_SAVE_ENABLE = 1
+	PMO_PS_ADVANCED_POWER_SAVE_ENABLE = 1,
+	PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED = 2
 };
 
 /**
@@ -380,6 +384,7 @@ struct pmo_icmp_offload {
  * @enable_sap_suspend: enable SoftAP suspend
  * @wow_data_inactivity_timeout: power save wow data inactivity timeout
  *  wow mode
+ * @wow_spec_wake_interval: OPM speculatvie wkae interval in wow mode
  * @active_uc_apf_mode: Setting that determines how APF is applied in active
  *	mode for uc packets
  * @active_mc_bc_apf_mode: Setting that determines how APF is applied in
@@ -465,6 +470,7 @@ struct pmo_psoc_cfg {
 #endif
 	bool enable_sap_suspend;
 	uint8_t wow_data_inactivity_timeout;
+	uint8_t wow_spec_wake_interval;
 	enum active_apf_mode active_uc_apf_mode;
 	enum active_apf_mode active_mc_bc_apf_mode;
 	uint8_t ito_repeat_count;
@@ -526,4 +532,17 @@ struct pmo_igmp_offload_req {
 	uint32_t num_grp_ip_address;
 	uint32_t grp_ip_address[MAX_MC_IP_ADDR];
 };
+
+/**
+ * struct pmo_ps_params - structure to hold OPM params
+ *
+ * @opm_mode: OPM mode
+ * @ps_ito: power save inactivity timeout
+ * @spec_wake: OPM speculative wake interval
+ */
+struct pmo_ps_params {
+	enum powersave_mode opm_mode;
+	uint16_t ps_ito;
+	uint16_t spec_wake;
+};
 #endif /* end  of _WLAN_PMO_COMMONP_STRUCT_H_ */

+ 32 - 0
components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h

@@ -325,6 +325,26 @@ wlan_pmo_get_interval_for_pagefault_wakeup_counts(
 QDF_STATUS wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev,
 					uint32_t *listen_interval);
 
+/**
+ * wlan_pmo_set_ps_params() - Set vdev OPM params
+ * @vdev: pointer to vdev object
+ * @ps_params: pointer to OPM params
+ *
+ * Return: None
+ */
+void wlan_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev,
+			    struct pmo_ps_params *ps_params);
+
+/**
+ * wlan_pmo_get_ps_params() - Get vdev OPM params
+ * @vdev: pointer to vdev object
+ * @ps_params: Pointer to get OPM params
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
+				  struct pmo_ps_params *ps_params);
+
 #else /* WLAN_POWER_MANAGEMENT_OFFLOAD */
 
 static inline QDF_STATUS pmo_init(void)
@@ -512,6 +532,18 @@ static QDF_STATUS wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline
+void wlan_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev,
+			    struct pmo_ps_params *ps_params)
+{
+}
+
+static inline QDF_STATUS
+wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
+		       struct pmo_ps_params *ps_params)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */
 
 #endif /* end  of _WLAN_PMO_OBJ_MGMT_API_H_ */

+ 21 - 0
components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h

@@ -808,6 +808,27 @@ void
 ucfg_pmo_set_wow_enable(struct wlan_objmgr_psoc *psoc,
 			enum pmo_wow_enable_type val);
 
+/**
+ * ucfg_pmo_set_ps_params() - Set vdev OPM params
+ * @vdev: pointer to vdev object
+ * @ps_params: pointer to OPM params
+ *
+ * Return: None
+ */
+void
+ucfg_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev,
+		       struct pmo_ps_params *ps_params);
+
+/**
+ * ucfg_pmo_get_ps_params() - Get vdev OPM params
+ * @vdev: pointer to vdev object
+ * @ps_params: Pointer to get OPM params
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS ucfg_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
+				  struct pmo_ps_params *ps_params);
+
 /**
  * ucfg_pmo_get_gtk_rsp(): API to send gtk response request to fwr
  * @vdev: objmgr vdev handle

+ 21 - 0
components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c

@@ -285,6 +285,15 @@ QDF_STATUS pmo_vdev_object_created_notification(
 	vdev_ctx->pmo_psoc_ctx = psoc_ctx;
 	qdf_atomic_init(&vdev_ctx->gtk_err_enable);
 	pmo_vdev_dynamic_arp_ns_offload_init(vdev_ctx);
+	/*
+	 * Update Powersave mode
+	 * 0 - PMO_PS_ADVANCED_POWER_SAVE_DISABLE
+	 * 1 - PMO_PS_ADVANCED_POWER_SAVE_ENABLE
+	 * 2 - PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED
+	 */
+	vdev_ctx->ps_params.opm_mode = psoc_ctx->psoc_cfg.power_save_mode;
+	vdev_ctx->ps_params.ps_ito = PMO_PS_DATA_INACTIVITY_TIMEOUT;
+	vdev_ctx->ps_params.spec_wake = PMO_PS_DATA_SPEC_WAKE;
 
 out:
 	pmo_exit();
@@ -906,3 +915,15 @@ QDF_STATUS wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev,
 {
 	return pmo_core_get_listen_interval(vdev, listen_interval);
 }
+
+void wlan_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev,
+			    struct pmo_ps_params *ps_params)
+{
+	pmo_core_vdev_set_ps_params(vdev, ps_params);
+}
+
+QDF_STATUS wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
+				  struct pmo_ps_params *ps_params)
+{
+	return pmo_core_vdev_get_ps_params(vdev, ps_params);
+}

+ 13 - 0
components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c

@@ -594,6 +594,19 @@ ucfg_pmo_set_wow_enable(struct wlan_objmgr_psoc *psoc,
 	pmo_psoc_ctx->psoc_cfg.wow_enable = val;
 }
 
+void
+ucfg_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev,
+		       struct pmo_ps_params *ps_params)
+{
+	pmo_core_vdev_set_ps_params(vdev, ps_params);
+}
+
+QDF_STATUS ucfg_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
+				  struct pmo_ps_params *ps_params)
+{
+	return pmo_core_vdev_get_ps_params(vdev, ps_params);
+}
+
 bool
 ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc)
 {

+ 174 - 1
components/target_if/connection_mgr/src/target_if_cm_roam_event.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -33,6 +33,8 @@
 #include "target_if_cm_roam_offload.h"
 #include <target_if_vdev_mgr_rx_ops.h>
 #include <target_if_psoc_wake_lock.h>
+#include "wlan_mlo_mgr_peer.h"
+#include "wlan_crypto_global_api.h"
 
 struct wlan_cm_roam_rx_ops *
 target_if_cm_get_roam_rx_ops(struct wlan_objmgr_psoc *psoc)
@@ -74,6 +76,7 @@ target_if_cm_roam_register_rx_ops(struct wlan_cm_roam_rx_ops *rx_ops)
 {
 	rx_ops->roam_sync_event = cm_roam_sync_event_handler;
 	rx_ops->roam_sync_frame_event = cm_roam_sync_frame_event_handler;
+	rx_ops->roam_sync_key_event = cm_roam_sync_key_event_handler;
 	rx_ops->roam_event_rx = cm_roam_event_handler;
 	rx_ops->btm_denylist_event = cm_btm_denylist_event_handler;
 	rx_ops->vdev_disconnect_event = cm_vdev_disconnect_event_handler;
@@ -727,6 +730,174 @@ target_if_register_roam_vendor_control_param_event(wmi_unified_t handle)
 }
 #endif
 
+#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
+static void
+target_if_update_pairwise_key_peer_mac(struct wlan_crypto_key_entry *crypto_entry,
+				       struct qdf_mac_addr *ap_link_addr)
+{
+	uint8_t i;
+
+	if (crypto_entry->link_id == MLO_INVALID_LINK_IDX)
+		return;
+
+	for (i = 0; i < WLAN_CRYPTO_MAX_VLANKEYIX; i++) {
+		if (!crypto_entry->keys.key[i])
+			continue;
+
+		if (crypto_entry->keys.key[i]->key_type ==
+		    WLAN_CRYPTO_KEY_TYPE_UNICAST)
+			qdf_copy_macaddr((struct qdf_mac_addr *)crypto_entry->keys.key[i]->macaddr,
+					 ap_link_addr);
+	}
+}
+
+static int
+target_if_roam_synch_key_event_handler(ol_scn_t scn, uint8_t *event,
+				       uint32_t len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct wlan_cm_roam_rx_ops *roam_rx_ops;
+	struct wlan_crypto_key_entry *keys;
+	struct qdf_mac_addr mld_addr;
+	struct wlan_mlo_dev_context *ml_ctx = NULL;
+	struct wlan_objmgr_vdev *vdev_list;
+	struct mlo_link_info *link_info;
+	uint8_t num_keys = 0;
+	int ret = 0;
+	QDF_STATUS status;
+	uint8_t i, j;
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	status = wmi_extract_roam_synch_key_event(wmi_handle, event, len, &keys,
+						  &num_keys, &mld_addr);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		target_if_err("parsing of roam sync key event failed");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	wlan_mlo_get_mlpeer_by_peer_mladdr(&mld_addr, &ml_ctx);
+	if (!ml_ctx) {
+		target_if_err("ML context is not found mld addr: "
+			      QDF_MAC_ADDR_FMT,
+			      QDF_MAC_ADDR_REF(mld_addr.bytes));
+		ret = -EINVAL;
+		goto done;
+	}
+
+	target_if_debug("num_keys:%d ML context is found mld addr: "
+			QDF_MAC_ADDR_FMT, num_keys,
+			QDF_MAC_ADDR_REF(mld_addr.bytes));
+
+	/*
+	 * Fill VDEV ID & AP mac address for the pairwise keys
+	 * from link id received in the key event
+	 */
+	for (i = 0; i < num_keys; i++) {
+		keys[i].vdev_id = WLAN_INVALID_VDEV_ID;
+		for (j = 0; j < WLAN_UMAC_MLO_MAX_VDEVS; j++) {
+			vdev_list = ml_ctx->wlan_vdev_list[j];
+			if (!vdev_list)
+				continue;
+
+			if (keys[i].link_id ==
+			    wlan_vdev_get_link_id(vdev_list)) {
+				keys[i].vdev_id = wlan_vdev_get_id(vdev_list);
+				qdf_copy_macaddr((struct qdf_mac_addr *)keys[i].mac_addr.raw,
+						 (struct qdf_mac_addr *)vdev_list->vdev_mlme.linkaddr);
+				link_info = mlo_mgr_get_ap_link_by_link_id(vdev_list,
+									   keys[i].link_id);
+				if (!link_info) {
+					target_if_err("Link info not found for link_id:%d",
+						      keys[i].link_id);
+					break;
+				}
+				target_if_debug("i:%d link_id:%d vdev_id:%d self link_addr: " QDF_MAC_ADDR_FMT " AP link addr: " QDF_MAC_ADDR_FMT,
+						i, keys[i].link_id, keys[i].vdev_id,
+						QDF_MAC_ADDR_REF(keys[i].mac_addr.raw),
+						QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
+
+				target_if_update_pairwise_key_peer_mac(&keys[i], &link_info->ap_link_addr);
+				break;
+			}
+		}
+
+		/* update for standby vdev also here from link_switch context*/
+		if (keys[i].vdev_id == WLAN_INVALID_VDEV_ID &&
+		    keys[i].link_id != MLO_INVALID_LINK_IDX &&
+		    ml_ctx->link_ctx) {
+			for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) {
+				link_info = &ml_ctx->link_ctx->links_info[j];
+				if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
+					continue;
+
+				if (qdf_is_macaddr_zero(&link_info->link_addr))
+					continue;
+
+				if (link_info->link_id == keys[i].link_id) {
+					target_if_debug("i:%d Standby vdev: link_id:%d ap_link_addr: " QDF_MAC_ADDR_FMT,
+							i, keys[i].link_id,
+							QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
+					qdf_copy_macaddr((struct qdf_mac_addr *)keys[i].mac_addr.raw,
+							 &link_info->link_addr);
+					target_if_update_pairwise_key_peer_mac(&keys[i],
+									       &link_info->ap_link_addr);
+				}
+			}
+		}
+	}
+
+	roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc);
+	if (!roam_rx_ops || !roam_rx_ops->roam_sync_key_event) {
+		target_if_err("No valid roam rx ops");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	status = roam_rx_ops->roam_sync_key_event(psoc, keys, num_keys);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		target_if_err("Add keys failed");
+		ret = 0;
+	}
+done:
+	qdf_mem_zero(keys, WLAN_MAX_ML_BSS_LINKS * sizeof(*keys));
+	qdf_mem_free(keys);
+
+	return ret;
+}
+#endif
+
+#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
+static void target_if_register_mlo_roam_events(wmi_unified_t handle)
+{
+	QDF_STATUS status;
+
+	status = wmi_unified_register_event_handler(
+				handle,
+				wmi_roam_synch_key_event_id,
+				target_if_roam_synch_key_event_handler,
+				WMI_RX_SERIALIZER_CTX);
+	if (QDF_IS_STATUS_ERROR(status))
+		target_if_err("wmi event(%u) registration failed, status: %d",
+			      wmi_roam_synch_key_event_id, status);
+}
+#else
+static inline void target_if_register_mlo_roam_events(wmi_unified_t handle)
+{}
+#endif
+
 QDF_STATUS
 target_if_roam_offload_register_events(struct wlan_objmgr_psoc *psoc)
 {
@@ -829,6 +1000,8 @@ target_if_roam_offload_register_events(struct wlan_objmgr_psoc *psoc)
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	target_if_register_mlo_roam_events(handle);
+
 	return QDF_STATUS_SUCCESS;
 }
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */

+ 4 - 1
components/target_if/pmo/src/target_if_pmo_suspend_resume.c

@@ -154,7 +154,7 @@ QDF_STATUS target_if_pmo_send_vdev_ps_param_req(
 	 */
 	switch (param_id) {
 	case pmo_sta_ps_enable_advanced_power:
-		param_id = WMI_STA_PS_ENABLE_QPOWER;
+		param_id = WMI_STA_PS_ENABLE_OPM;
 		break;
 	case pmo_sta_ps_param_inactivity_time:
 		param_id = WMI_STA_PS_PARAM_INACTIVITY_TIME;
@@ -162,6 +162,9 @@ QDF_STATUS target_if_pmo_send_vdev_ps_param_req(
 	case pmo_sta_ps_param_ito_repeat_count:
 		param_id = WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX;
 		break;
+	case pmo_sta_ps_param_spec_wake_interval:
+		param_id = WMI_STA_PS_PARAM_SPEC_WAKE_INTERVAL;
+		break;
 	default:
 		target_if_err("invalid vdev param id %d", param_id);
 		return QDF_STATUS_E_INVAL;

+ 5 - 0
components/tdls/core/src/wlan_tdls_ct.c

@@ -108,6 +108,11 @@ void tdls_discovery_timeout_peer_cb(void *user_data)
 	if (!tdls_soc)
 		return;
 
+	/* timer_cnt is reset when link switch happens */
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	    qdf_atomic_read(&tdls_soc->timer_cnt) == 0)
+		return;
+
 	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
 	    qdf_atomic_dec_and_test(&tdls_soc->timer_cnt)) {
 		tdls_process_mlo_cal_tdls_link_score(vdev);

+ 77 - 8
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c

@@ -427,6 +427,30 @@ cm_fils_update_erp_seq_num(struct wlan_objmgr_vdev *vdev,
 #endif
 
 #ifdef WLAN_FEATURE_11BE_MLO
+static void
+cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev,
+			    struct roam_offload_synch_ind *roam_synch_data)
+{
+	struct wlan_channel channel = {0};
+	struct ml_setup_link_param *ml_link;
+	uint8_t i;
+
+	if (!is_multi_link_roam(roam_synch_data))
+		return;
+
+	for (i = 0; i < roam_synch_data->num_setup_links; i++) {
+		ml_link = &roam_synch_data->ml_link[i];
+
+		channel.ch_freq = ml_link->channel.mhz;
+		channel.ch_cfreq1 = ml_link->channel.band_center_freq1;
+		channel.ch_cfreq1 = ml_link->channel.band_center_freq2;
+
+		mlo_mgr_roam_update_ap_link_info(vdev, ml_link->link_id,
+						 ml_link->link_addr.bytes,
+						 channel);
+	}
+}
+
 static QDF_STATUS
 cm_fill_bssid_freq_info(uint8_t vdev_id,
 			struct roam_offload_synch_ind *roam_synch_data,
@@ -468,9 +492,14 @@ cm_mlo_roam_copy_partner_info(struct wlan_cm_connect_resp *connect_rsp,
 			      struct roam_offload_synch_ind *roam_synch_data)
 {
 	mlo_roam_copy_partner_info(&connect_rsp->ml_parnter_info,
-				   roam_synch_data, WLAN_INVALID_VDEV_ID);
+				   roam_synch_data, WLAN_INVALID_VDEV_ID,
+				   true);
 }
 #else
+static inline void
+cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev,
+			    struct roam_offload_synch_ind *roam_synch_data)
+{}
 static QDF_STATUS
 cm_fill_bssid_freq_info(uint8_t vdev_id,
 			struct roam_offload_synch_ind *roam_synch_data,
@@ -536,7 +565,8 @@ cm_fill_roam_info(struct wlan_objmgr_vdev *vdev,
 
 	rsp->connect_rsp.roaming_info = qdf_mem_malloc(sizeof(*roaming_info));
 	if (!rsp->connect_rsp.roaming_info)
-			return QDF_STATUS_E_NOMEM;
+		return QDF_STATUS_E_NOMEM;
+
 	rsp->connect_rsp.vdev_id = wlan_vdev_get_id(vdev);
 	status = cm_fill_bssid_freq_info(wlan_vdev_get_id(vdev),
 					 roam_synch_data, rsp);
@@ -920,6 +950,38 @@ cm_update_scan_db_on_roam_success(struct wlan_objmgr_vdev *vdev,
 				    SCAN_ENTRY_CON_STATE_ASSOC);
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static void
+cm_roam_ml_clear_prev_ap_keys(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct mlo_link_info *link_info;
+	uint8_t i;
+
+	ml_dev = vdev->mlo_dev_ctx;
+	if (!ml_dev || !ml_dev->link_ctx)
+		return;
+
+	link_info = &ml_dev->link_ctx->links_info[0];
+	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
+		if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
+			continue;
+
+		if (qdf_is_macaddr_zero(&link_info->link_addr))
+			continue;
+
+		wlan_crypto_free_key_by_link_id(wlan_vdev_get_psoc(vdev),
+						&link_info->link_addr,
+						link_info->link_id);
+		link_info++;
+	}
+}
+#else
+static void
+cm_roam_ml_clear_prev_ap_keys(struct wlan_objmgr_vdev *vdev)
+{}
+#endif
+
 QDF_STATUS
 cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 			    struct roam_offload_synch_ind *roam_synch_data)
@@ -963,6 +1025,9 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	wlan_rec_conn_info(vdev_id, DEBUG_CONN_ROAMING,
 			   roam_synch_data->bssid.bytes, 0, 0);
 
+	cm_roam_update_mlo_mgr_info(vdev, roam_synch_data);
+	cm_roam_ml_clear_prev_ap_keys(vdev);
+
 	cm_id = roam_req->cm_id;
 	rsp = qdf_mem_malloc(sizeof(struct cm_vdev_join_rsp));
 	if (!rsp) {
@@ -1004,9 +1069,6 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	 */
 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
 		cm_inform_dlm_connect_complete(cm_ctx->vdev, connect_rsp);
-		wlan_tdls_notify_sta_connect(vdev_id,
-					mlme_get_tdls_chan_switch_prohibited(vdev),
-					mlme_get_tdls_prohibited(vdev), vdev);
 		wlan_p2p_status_connect(vdev);
 
 		if (!cm_csr_is_ss_wait_for_key(vdev_id)) {
@@ -1023,6 +1085,9 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	}
 	cm_connect_info(vdev, true, &connect_rsp->bssid, &connect_rsp->ssid,
 			connect_rsp->freq);
+	wlan_tdls_notify_sta_connect(vdev_id,
+				     mlme_get_tdls_chan_switch_prohibited(vdev),
+				     mlme_get_tdls_prohibited(vdev), vdev);
 
 	cm_update_associated_ch_info(vdev, true);
 
@@ -1034,6 +1099,9 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 			 CM_PREFIX_REF(vdev_id, cm_id));
 		goto error;
 	}
+
+	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev))
+		mlo_roam_update_connected_links(vdev, connect_rsp);
 	mlme_cm_osif_connect_complete(vdev, connect_rsp);
 	mlme_cm_osif_roam_complete(vdev);
 
@@ -1067,8 +1135,9 @@ cm_get_and_disable_link_from_roam_ind(struct wlan_objmgr_psoc *psoc,
 	for (i = 0; i < synch_data->num_setup_links; i++) {
 		if (synch_data->ml_link[i].vdev_id == vdev_id &&
 		    synch_data->ml_link[i].flags & CM_ROAM_LINK_FLAG_DISABLE) {
-			mlme_info("Vdev %d: link flags 0x%x, indicate link disable",
-				  vdev_id, synch_data->ml_link[i].flags);
+			mlme_info("Vdev %d: link id %d flags 0x%x, indicate link disable",
+				  vdev_id, synch_data->ml_link[i].link_id,
+				  synch_data->ml_link[i].flags);
 			policy_mgr_move_vdev_from_connection_to_disabled_tbl(
 								psoc, vdev_id);
 
@@ -1080,7 +1149,7 @@ cm_get_and_disable_link_from_roam_ind(struct wlan_objmgr_psoc *psoc,
 				break;
 			}
 			ml_nlink_set_curr_force_inactive_state(
-				psoc, vdev, synch_data->ml_link[i].link_id,
+				psoc, vdev, 1 << synch_data->ml_link[i].link_id,
 				LINK_ADD);
 			wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
 			break;

+ 29 - 3
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -3032,6 +3032,7 @@ cm_roam_mlo_config(struct wlan_objmgr_psoc *psoc,
 		   struct wlan_roam_start_config *start_req)
 {
 	struct wlan_roam_mlo_config *roam_mlo_params;
+	struct rso_config *rso_cfg;
 
 	roam_mlo_params = &start_req->roam_mlo_params;
 	roam_mlo_params->vdev_id = wlan_vdev_get_id(vdev);
@@ -3039,6 +3040,18 @@ cm_roam_mlo_config(struct wlan_objmgr_psoc *psoc,
 		wlan_mlme_get_sta_mlo_conn_max_num(psoc);
 	roam_mlo_params->support_link_band =
 		wlan_mlme_get_sta_mlo_conn_band_bmp(psoc);
+
+	/*
+	 * Update the supported link band based on roam_band_bitmap
+	 * Roam band bitmap is modified during NCHO mode enable, disable and
+	 * regulatory supported band changes.
+	 */
+	rso_cfg = wlan_cm_get_rso_config(vdev);
+	if (!rso_cfg)
+		return;
+
+	roam_mlo_params->support_link_band &=
+					rso_cfg->roam_band_bitmask;
 }
 #else
 static void
@@ -4666,8 +4679,21 @@ cm_mlo_roam_switch_for_link(struct wlan_objmgr_pdev *pdev,
 	enum roam_offload_state cur_state = mlme_get_roam_state(psoc, vdev_id);
 
 	if (reason != REASON_ROAM_HANDOFF_DONE &&
-	    reason != REASON_ROAM_ABORT)
+	    reason != REASON_ROAM_ABORT &&
+	    reason != REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE) {
+		mlo_debug("CM_RSO: link vdev:%d state switch received with invalid reason:%d",
+			  vdev_id, reason);
 		return QDF_STATUS_E_FAILURE;
+	}
+
+	/*
+	 * change roam state to deinit for assoc vdev that has now changed to
+	 * link vdev
+	 */
+	if (reason == REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE) {
+		mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_DEINIT);
+		return QDF_STATUS_SUCCESS;
+	}
 
 	switch (cur_state) {
 	case WLAN_ROAM_DEINIT:
@@ -4678,8 +4704,8 @@ cm_mlo_roam_switch_for_link(struct wlan_objmgr_pdev *pdev,
 		mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_DEINIT);
 		break;
 	default:
-		mlme_err("ROAM: MLO Roam synch not allowed in [%d] state",
-			 cur_state);
+		mlme_err("ROAM: vdev:%d MLO Roam synch not allowed in [%d] state reason:%d",
+			 vdev_id, cur_state, reason);
 		return QDF_STATUS_E_FAILURE;
 	}
 

+ 19 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c

@@ -468,6 +468,25 @@ err:
 	return status;
 }
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
+QDF_STATUS cm_roam_sync_key_event_handler(struct wlan_objmgr_psoc *psoc,
+					  struct wlan_crypto_key_entry *keys,
+					  uint8_t num_keys)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint8_t i;
+
+	for (i = 0; i < num_keys; i++) {
+		status = wlan_crypto_add_key_entry(psoc, &keys[i]);
+		if (QDF_IS_STATUS_ERROR(status))
+			mlme_err("Failed to add key entry for link:%d",
+				 keys[i].link_id);
+	}
+
+	return status;
+}
+#endif
+
 QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev,
 					 uint8_t *event,
 					 uint32_t len)

+ 9 - 3
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c

@@ -1086,9 +1086,10 @@ QDF_STATUS cm_connect_start_ind(struct wlan_objmgr_vdev *vdev,
 					   wlan_vdev_get_id(vdev),
 					   HS_20_AP, &src_cfg);
 	}
-	ml_nlink_conn_change_notify(
-		psoc, wlan_vdev_get_id(vdev),
-		ml_nlink_connect_start_evt, NULL);
+	if (req->source != CM_MLO_LINK_SWITCH_CONNECT)
+		ml_nlink_conn_change_notify(
+			psoc, wlan_vdev_get_id(vdev),
+			ml_nlink_connect_start_evt, NULL);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -1696,6 +1697,11 @@ cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev,
 			rsp->freq);
 
 	if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) {
+		if (rsp->cm_id & CM_ID_LSWITCH_BIT)
+			ml_nlink_conn_change_notify(
+				psoc, vdev_id,
+				ml_nlink_link_switch_pre_completion_evt, NULL);
+
 		if (policy_mgr_ml_link_vdev_need_to_be_disabled(psoc, vdev,
 								false))
 			policy_mgr_move_vdev_from_connection_to_disabled_tbl(

+ 10 - 7
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c

@@ -75,9 +75,10 @@ QDF_STATUS cm_disconnect_start_ind(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_INVAL;
 	}
 	mlo_sta_stop_reconfig_timer(vdev);
-	ml_nlink_conn_change_notify(
-		psoc, wlan_vdev_get_id(vdev),
-		ml_nlink_disconnect_start_evt, NULL);
+	if (req->source != CM_MLO_LINK_SWITCH_DISCONNECT)
+		ml_nlink_conn_change_notify(
+			psoc, wlan_vdev_get_id(vdev),
+			ml_nlink_disconnect_start_evt, NULL);
 	if (cm_csr_is_ss_wait_for_key(req->vdev_id)) {
 		mlme_debug("Stop Wait for key timer");
 		cm_stop_wait_for_key_timer(psoc, req->vdev_id);
@@ -258,10 +259,12 @@ cm_disconnect_complete_ind(struct wlan_objmgr_vdev *vdev,
 	cm_disconnect_diag_event(vdev, rsp);
 	wlan_tdls_notify_sta_disconnect(vdev_id, false, false, vdev);
 	policy_mgr_decr_session_set_pcl(psoc, op_mode, vdev_id);
-	wlan_clear_mlo_sta_link_removed_flag(vdev);
-	ml_nlink_conn_change_notify(
-		psoc, vdev_id, ml_nlink_disconnect_completion_evt,
-		NULL);
+	if (rsp->req.req.source != CM_MLO_LINK_SWITCH_DISCONNECT) {
+		wlan_clear_mlo_sta_link_removed_flag(vdev);
+		ml_nlink_conn_change_notify(
+			psoc, vdev_id, ml_nlink_disconnect_completion_evt,
+			NULL);
+	}
 
 	return QDF_STATUS_SUCCESS;
 }

+ 24 - 1
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h

@@ -317,7 +317,7 @@ wlan_cm_get_rso_user_config_fl(struct wlan_objmgr_vdev *vdev,
 	wlan_cm_get_rso_config_fl(vdev, __func__, __LINE__)
 
 /**
- * wlan_cm_get_rso_config - get per vdev RSO userspace config
+ * wlan_cm_get_rso_user_config - get per vdev RSO userspace config
  * @vdev: vdev pointer
  *
  * Return: rso user space config pointer
@@ -1608,6 +1608,29 @@ wlan_cm_add_frame_to_scan_db(struct wlan_objmgr_psoc *psoc,
 }
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
+/**
+ * cm_roam_sync_key_event_handler() - Handle roam sync key event and
+ * store the keys in crypto module
+ * @psoc:  Pointer to psoc object
+ * @keys:  Pointer to the keys
+ * @num_keys: Number of links for which keys entries are available
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_roam_sync_key_event_handler(struct wlan_objmgr_psoc *psoc,
+					  struct wlan_crypto_key_entry *keys,
+					  uint8_t num_keys);
+#else
+static inline
+QDF_STATUS cm_roam_sync_key_event_handler(struct wlan_objmgr_psoc *psoc,
+					  struct wlan_crypto_key_entry *keys,
+					  uint8_t num_keys)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
 #ifdef WLAN_FEATURE_FIPS
 /**
  * cm_roam_pmkid_req_ind() - Function to handle

+ 8 - 5
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -92,6 +92,7 @@
 #define REASON_ROAM_HANDOFF_DONE                    52
 #define REASON_ROAM_ABORT                           53
 #define REASON_ROAM_SET_PRIMARY                     54
+#define REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE   55
 
 #define FILS_MAX_KEYNAME_NAI_LENGTH WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH
 #define WLAN_FILS_MAX_REALM_LEN WLAN_CM_FILS_MAX_REALM_LEN
@@ -1943,9 +1944,7 @@ enum roam_rt_stats_params {
  * @support_link_num: Configure max number of link mlo connection supports.
  *  Invalid value or 0 will use max supported value by fw.
  * @support_link_band: Configure the band bitmap of mlo connection supports
- *  Bit 0: 2G band support if 1
- *  Bit 1: 5G band support if 1
- *  Bit 2: 6G band support if 1
+ * The bits of the bitmap are defined by the enum reg_wifi_band
  */
 struct wlan_roam_mlo_config {
 	uint8_t vdev_id;
@@ -2854,9 +2853,9 @@ struct roam_offload_synch_ind {
 	uint8_t is_link_beacon;
 #ifdef WLAN_FEATURE_11BE_MLO
 	uint8_t num_setup_links;
-	struct ml_setup_link_param ml_link[WLAN_UMAC_MLO_MAX_VDEVS];
+	struct ml_setup_link_param ml_link[WLAN_MAX_ML_BSS_LINKS];
 	uint8_t num_ml_key_material;
-	struct ml_key_material_param ml_key[WLAN_UMAC_MLO_MAX_VDEVS];
+	struct ml_key_material_param ml_key[WLAN_MAX_ML_BSS_LINKS];
 #endif
 };
 
@@ -2879,6 +2878,7 @@ struct roam_scan_candidate_frame {
  * roaming related commands
  * @roam_sync_event: RX ops function pointer for roam sync event
  * @roam_sync_frame_event: Rx ops function pointer for roam sync frame event
+ * @roam_sync_key_event: Rx ops function pointer for roam sych key event
  * @roam_event_rx: Rx ops function pointer for roam info event
  * @btm_denylist_event: Rx ops function pointer for btm denylist event
  * @vdev_disconnect_event: Rx ops function pointer for vdev disconnect event
@@ -2896,6 +2896,9 @@ struct wlan_cm_roam_rx_ops {
 				      struct roam_offload_synch_ind *sync_ind);
 	QDF_STATUS (*roam_sync_frame_event)(struct wlan_objmgr_psoc *psoc,
 					    struct roam_synch_frame_ind *frm);
+	QDF_STATUS (*roam_sync_key_event)(struct wlan_objmgr_psoc *psoc,
+					  struct wlan_crypto_key_entry *keys,
+					  uint8_t num_keys);
 	QDF_STATUS (*roam_event_rx)(struct roam_offload_roam_event *roam_event);
 	QDF_STATUS (*btm_denylist_event)(struct wlan_objmgr_psoc *psoc,
 					 struct roam_denylist_event *list);

+ 11 - 3
components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h

@@ -26,7 +26,7 @@
 /**
  * enum ml_nlink_change_event_type - Ml link state change trigger event
  * @ml_nlink_link_switch_start_evt: link switch start
- * @ml_nlink_link_switch_completion_evt: link switch done
+ * @ml_nlink_link_switch_pre_completion_evt: link switch pre-completion
  * @ml_nlink_roam_sync_start_evt: roam sync start
  * @ml_nlink_roam_sync_completion_evt: roam sync completion
  * @ml_nlink_connect_start_evt: STA/CLI connect start
@@ -39,7 +39,7 @@
  */
 enum ml_nlink_change_event_type {
 	ml_nlink_link_switch_start_evt,
-	ml_nlink_link_switch_completion_evt,
+	ml_nlink_link_switch_pre_completion_evt,
 	ml_nlink_roam_sync_start_evt,
 	ml_nlink_roam_sync_completion_evt,
 	ml_nlink_connect_start_evt,
@@ -54,8 +54,16 @@ enum ml_nlink_change_event_type {
 /**
  * struct ml_nlink_change_event - connection change event data struct
  * @evt: event parameters
+ * @link_switch: link switch start parameters
  */
 struct ml_nlink_change_event {
+	union {
+		struct {
+			uint8_t curr_ieee_link_id;
+			uint8_t new_ieee_link_id;
+			uint32_t new_primary_freq;
+		} link_switch;
+	} evt;
 };
 
 #ifdef WLAN_FEATURE_11BE_MLO
@@ -88,7 +96,7 @@ static inline const char *link_evt_to_string(uint32_t evt)
 {
 	switch (evt) {
 	CASE_RETURN_STRING(ml_nlink_link_switch_start_evt);
-	CASE_RETURN_STRING(ml_nlink_link_switch_completion_evt);
+	CASE_RETURN_STRING(ml_nlink_link_switch_pre_completion_evt);
 	CASE_RETURN_STRING(ml_nlink_roam_sync_start_evt);
 	CASE_RETURN_STRING(ml_nlink_roam_sync_completion_evt);
 	CASE_RETURN_STRING(ml_nlink_connect_start_evt);

+ 3 - 2
components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h

@@ -176,6 +176,7 @@ QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
  * @partner_info: Destination buffer to fill partner info from roam sync ind
  * @sync_ind: roam sync ind pointer
  * @skip_vdev_id: Skip to copy the link info corresponds to this vdev_id
+ * @fill_all_links: Fill all the links for connect response to userspace
  *
  * This api will be called to copy partner link info to connect response.
  *
@@ -183,7 +184,7 @@ QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
  */
 void mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
 				struct roam_offload_synch_ind *sync_ind,
-				uint8_t skip_vdev_id);
+				uint8_t skip_vdev_id, bool fill_all_links);
 
 /**
  * mlo_roam_init_cu_bpcc() - init cu bpcc per roam sync data
@@ -513,7 +514,7 @@ QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
 static inline void
 mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
 			   struct roam_offload_synch_ind *sync_ind,
-			   uint8_t skip_vdev_id)
+			   uint8_t skip_vdev_id, bool fill_all_links)
 {}
 
 static inline

+ 13 - 4
components/umac/mlme/mlo_mgr/inc/wlan_t2lm_api.h

@@ -71,6 +71,7 @@ enum wlan_t2lm_evt {
  * @peer: pointer to peer
  * @event: T2LM event
  * @event_data: T2LM event data pointer
+ * @frame_len: Received T2LM Frame length
  * @dialog_token: Dialog token
  *
  * This api will be called from lim  layers, to process T2LM event
@@ -81,6 +82,7 @@ QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 			      struct wlan_objmgr_peer *peer,
 			      enum wlan_t2lm_evt event,
 			      void *event_data,
+			      uint32_t frame_len,
 			      uint8_t *dialog_token);
 
 /**
@@ -88,6 +90,7 @@ QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
  * @vdev: vdev pointer
  * @peer: pointer to peer
  * @event_data: T2LM event data pointer
+ * @frame_len: Received Frame length
  * @token: Dialog token
  *
  * This api will be called from lim  layers, after T2LM action frame
@@ -97,7 +100,8 @@ QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
  */
 QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev,
 			      struct wlan_objmgr_peer *peer,
-			      void *event_data, uint8_t *token);
+			      void *event_data, uint32_t frame_len,
+			      uint8_t *token);
 
 /**
  * t2lm_handle_tx_resp - Handler for populating T2LM action frame
@@ -132,6 +136,7 @@ QDF_STATUS t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev,
  * @vdev: vdev pointer
  * @peer: peer pointer
  * @event_data: T2LM event data pointer
+ * @frame_len: Frame length
  * @token: Dialog token
  *
  * This api will be called to parsing T2LM response action frame.
@@ -140,7 +145,8 @@ QDF_STATUS t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev,
  */
 QDF_STATUS t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev,
 			       struct wlan_objmgr_peer *peer,
-			       void *event_data, uint8_t *token);
+			       void *event_data, uint32_t frame_len,
+			       uint8_t *token);
 
 /**
  * t2lm_handle_rx_teardown - Handler for parsing T2LM action frame
@@ -188,6 +194,7 @@ wlan_t2lm_validate_candidate(struct cnx_mgr *cm_ctx,
  * @peer: pointer to peer
  * @event: T2LM event
  * @event_data: T2LM event data
+ * @frame_len: received T2LM frame len
  * @dialog_token: Dialog token
  *
  * Return: QDF_STATUS
@@ -196,6 +203,7 @@ QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 				   struct wlan_objmgr_peer *peer,
 				   enum wlan_t2lm_evt event,
 				   void *event_data,
+				   uint32_t frame_len,
 				   uint8_t *dialog_token);
 
 /**
@@ -249,7 +257,7 @@ wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev,
 static inline QDF_STATUS
 t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev,
 		   struct wlan_objmgr_peer *peer,
-		   void *event_data, uint8_t *token)
+		   void *event_data, uint32_t frame_len, uint8_t *token)
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
@@ -272,7 +280,7 @@ t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev,
 static inline QDF_STATUS
 t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev,
 		    struct wlan_objmgr_peer *peer,
-		    void *event_data, uint8_t *token)
+		    void *event_data, uint32_t frame_len, uint8_t *token)
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
@@ -316,6 +324,7 @@ QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 				   struct wlan_objmgr_peer *peer,
 				   enum wlan_t2lm_evt event,
 				   void *event_data,
+				   uint32_t frame_len,
 				   uint8_t *dialog_token)
 {
 	return QDF_STATUS_E_NOSUPPORT;

+ 217 - 34
components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c

@@ -20,11 +20,13 @@
 #include "wlan_mlo_link_force.h"
 #include "wlan_mlo_mgr_sta.h"
 #include "wlan_policy_mgr_api.h"
+#include "wlan_policy_mgr_i.h"
 #include "wlan_cm_roam_public_struct.h"
 #include "wlan_cm_roam_api.h"
 #include "wlan_mlo_mgr_roam.h"
 #include "wlan_mlme_main.h"
 #include "wlan_mlo_mgr_link_switch.h"
+#include "target_if.h"
 
 void
 ml_nlink_convert_linkid_bitmap_to_vdev_bitmap(
@@ -423,16 +425,28 @@ ml_nlink_get_affect_ml_sta(struct wlan_objmgr_psoc *psoc)
 
 bool ml_is_nlink_service_supported(struct wlan_objmgr_psoc *psoc)
 {
-	/*todo: check WMI_SERVICE_N_LINK_MLO_SUPPORT service bit */
-	return false;
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		mlo_err("Invalid WMI handle");
+		return false;
+	}
+	return wmi_service_enabled(
+			wmi_handle,
+			wmi_service_n_link_mlo_support);
 }
 
 /* Exclude AP removed link */
-#define NLINK_EXCLUDE_REMOVED_LINK	0x01
+#define NLINK_EXCLUDE_REMOVED_LINK      0x01
 /* Include AP removed link only, can't work with other flags */
 #define NLINK_INCLUDE_REMOVED_LINK_ONLY 0x02
 /* Exclude QUITE link */
-#define NLINK_EXCLUDE_QUIET_LINK	0x04
+#define NLINK_EXCLUDE_QUIET_LINK        0x04
+/* Exclude standby link information */
+#define NLINK_EXCLUDE_STANDBY_LINK      0x08
+/* Dump link information */
+#define NLINK_DUMP_LINK                 0x10
 
 static void
 ml_nlink_get_standby_link_info(struct wlan_objmgr_psoc *psoc,
@@ -479,13 +493,17 @@ ml_nlink_get_standby_link_info(struct wlan_objmgr_psoc *psoc,
 			}
 
 			if ((flag & NLINK_EXCLUDE_REMOVED_LINK) &&
-			    link_info->link_status_flags) {
+			    qdf_atomic_test_bit(
+					LS_F_AP_REMOVAL_BIT,
+					&link_info->link_status_flags)) {
 				mlo_debug("standby link %d is removed",
 					  link_info->link_id);
 				continue;
 			}
 			if ((flag & NLINK_INCLUDE_REMOVED_LINK_ONLY) &&
-			    !link_info->link_status_flags) {
+			    !qdf_atomic_test_bit(
+					LS_F_AP_REMOVAL_BIT,
+					&link_info->link_status_flags)) {
 				continue;
 			}
 
@@ -494,12 +512,12 @@ ml_nlink_get_standby_link_info(struct wlan_objmgr_psoc *psoc,
 			ml_vdev_lst[*ml_num_link] = WLAN_INVALID_VDEV_ID;
 			ml_linkid_lst[*ml_num_link] = link_info->link_id;
 			*ml_link_bitmap |= 1 << link_info->link_id;
-
-			mlo_debug("vdev %d link %d freq %d bitmap 0x%x flag 0x%x",
-				  ml_vdev_lst[*ml_num_link],
-				  ml_linkid_lst[*ml_num_link],
-				  ml_freq_lst[*ml_num_link],
-				  *ml_link_bitmap, flag);
+			if (flag & NLINK_DUMP_LINK)
+				mlo_debug("vdev %d link %d freq %d bitmap 0x%x flag 0x%x",
+					  ml_vdev_lst[*ml_num_link],
+					  ml_linkid_lst[*ml_num_link],
+					  ml_freq_lst[*ml_num_link],
+					  *ml_link_bitmap, flag);
 			(*ml_num_link)++;
 		}
 
@@ -507,6 +525,26 @@ ml_nlink_get_standby_link_info(struct wlan_objmgr_psoc *psoc,
 	}
 }
 
+static uint32_t
+ml_nlink_get_standby_link_bitmap(struct wlan_objmgr_psoc *psoc,
+				 struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t ml_num_link = 0;
+	uint32_t standby_link_bitmap = 0;
+	uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS];
+
+	ml_nlink_get_standby_link_info(psoc, vdev, NLINK_DUMP_LINK,
+				       QDF_ARRAY_SIZE(ml_linkid_lst),
+				       ml_link_info, ml_freq_lst, ml_vdev_lst,
+				       ml_linkid_lst, &ml_num_link,
+				       &standby_link_bitmap);
+
+	return standby_link_bitmap;
+}
+
 /**
  * ml_nlink_get_link_info() - Get ML STA link info
  * @psoc: PSOC object information
@@ -609,14 +647,15 @@ static void ml_nlink_get_link_info(struct wlan_objmgr_psoc *psoc,
 		ml_vdev_lst[num_link] = vdev_id;
 		ml_linkid_lst[num_link] = link_id;
 		link_bitmap |= 1 << link_id;
-
-		mlo_debug("vdev %d link %d freq %d bitmap 0x%x flag 0x%x",
-			  ml_vdev_lst[num_link], ml_linkid_lst[num_link],
-			  ml_freq_lst[num_link], link_bitmap, flag);
+		if (flag & NLINK_DUMP_LINK)
+			mlo_debug("vdev %d link %d freq %d bitmap 0x%x flag 0x%x",
+				  ml_vdev_lst[num_link],
+				  ml_linkid_lst[num_link],
+				  ml_freq_lst[num_link], link_bitmap, flag);
 		num_link++;
 	}
 	/* Add standby link only if mlo sta is connected */
-	if (connected)
+	if (connected && !(flag & NLINK_EXCLUDE_STANDBY_LINK))
 		ml_nlink_get_standby_link_info(psoc, vdev, flag,
 					       ml_num_link_sz,
 					       ml_link_info,
@@ -710,7 +749,8 @@ ml_nlink_handle_mcc_links(struct wlan_objmgr_psoc *psoc,
 	uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS];
 	struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS];
 
-	ml_nlink_get_link_info(psoc, vdev, NLINK_INCLUDE_REMOVED_LINK_ONLY,
+	ml_nlink_get_link_info(psoc, vdev, NLINK_INCLUDE_REMOVED_LINK_ONLY |
+						NLINK_DUMP_LINK,
 			       QDF_ARRAY_SIZE(ml_linkid_lst),
 			       ml_link_info, ml_freq_lst, ml_vdev_lst,
 			       ml_linkid_lst, &ml_num_link,
@@ -721,7 +761,8 @@ ml_nlink_handle_mcc_links(struct wlan_objmgr_psoc *psoc,
 		mlo_debug("AP removed link 0x%x", force_inactive_link_bitmap);
 	}
 
-	ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK,
+	ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK |
+						NLINK_DUMP_LINK,
 			       QDF_ARRAY_SIZE(ml_linkid_lst),
 			       ml_link_info, ml_freq_lst, ml_vdev_lst,
 			       ml_linkid_lst, &ml_num_link,
@@ -1081,6 +1122,58 @@ ml_nlink_handle_legacy_p2p_intf(struct wlan_objmgr_psoc *psoc,
 	}
 }
 
+/**
+ * ml_nlink_handle_3_port_specific_scenario() - Check some specific corner
+ * case that can't be handled general logic in
+ * ml_nlink_handle_legacy_intf_3_ports.
+ * @psoc: PSOC object information
+ * @legacy_intf_freq1: legacy interface 1 channel frequency
+ * @legacy_intf_freq2: legacy interface 2 channel frequency
+ * @ml_num_link: number of ML STA links
+ * @ml_freq_lst: ML STA link channel frequency list
+ * @ml_linkid_lst: ML STA link ids
+ *
+ * Return: link force inactive bitmap
+ */
+static uint32_t
+ml_nlink_handle_3_port_specific_scenario(struct wlan_objmgr_psoc *psoc,
+					 qdf_freq_t legacy_intf_freq1,
+					 qdf_freq_t legacy_intf_freq2,
+					 uint8_t ml_num_link,
+					 qdf_freq_t *ml_freq_lst,
+					 uint8_t *ml_linkid_lst)
+{
+	uint32_t force_inactive_link_bitmap = 0;
+
+	if (ml_num_link < 2)
+		return 0;
+
+	/* special case handling:
+	 * LL P2P on 2.4G, ML STA 5G+6G, SAP on 6G, then
+	 * inactive 5G link.
+	 * LL P2P on 2.4G, ML STA 5G+6G, SAP on 5G, then
+	 * inactive 6G link.
+	 */
+	if (WLAN_REG_IS_24GHZ_CH_FREQ(legacy_intf_freq1) &&
+	    !WLAN_REG_IS_24GHZ_CH_FREQ(ml_freq_lst[0]) &&
+	    policy_mgr_are_sbs_chan(psoc, ml_freq_lst[0], ml_freq_lst[1]) &&
+	    policy_mgr_2_freq_always_on_same_mac(psoc, ml_freq_lst[0],
+						 legacy_intf_freq2))
+		force_inactive_link_bitmap |= 1 << ml_linkid_lst[1];
+	else if (WLAN_REG_IS_24GHZ_CH_FREQ(legacy_intf_freq1) &&
+		 !WLAN_REG_IS_24GHZ_CH_FREQ(ml_freq_lst[1]) &&
+		 policy_mgr_are_sbs_chan(psoc, ml_freq_lst[0],
+					 ml_freq_lst[1]) &&
+		 policy_mgr_2_freq_always_on_same_mac(psoc, ml_freq_lst[1],
+						      legacy_intf_freq2))
+		force_inactive_link_bitmap |= 1 << ml_linkid_lst[0];
+
+	if (force_inactive_link_bitmap)
+		mlo_debug("force inactive 0x%x", force_inactive_link_bitmap);
+
+	return force_inactive_link_bitmap;
+}
+
 /**
  * ml_nlink_handle_legacy_intf_3_ports() - Check force inactive needed
  * with 2 legacy interfaces
@@ -1090,10 +1183,15 @@ ml_nlink_handle_legacy_p2p_intf(struct wlan_objmgr_psoc *psoc,
  * @legacy_intf_freq1: legacy interface frequency
  * @legacy_intf_freq2: legacy interface frequency
  *
- * If legacy interface is mcc with any link based on current hw mode, then
- * force inactive the link.
+ * If legacy interface 1 (which channel frequency legacy_intf_freq1) is
+ * mcc with any link based on current hw mode, then force inactive the link.
  * And if standby link is mcc with legacy interface, then disable standby
  * link as well.
+ * In 3 Port case, at present only legacy interface 1(which channel frequency
+ * legacy_intf_freq1) MCC avoidance requirement can be met. The assignment of
+ * legacy_intf_freq1 and legacy_intf_freq2 is based on priority of Port type,
+ * check policy_mgr_get_legacy_conn_info for detail.
+ * Cornor cases will be handled in ml_nlink_handle_3_port_specific_scenario.
  *
  * Return: void
  */
@@ -1136,6 +1234,15 @@ ml_nlink_handle_legacy_intf_3_ports(struct wlan_objmgr_psoc *psoc,
 		} else if (policy_mgr_are_2_freq_on_same_mac(
 				psoc, ml_freq_lst[i], legacy_intf_freq1)) {
 			force_inactive_link_bitmap |= 1 << ml_linkid_lst[i];
+		} else if (i == 1) {
+			force_inactive_link_bitmap |=
+			ml_nlink_handle_3_port_specific_scenario(
+							psoc,
+							legacy_intf_freq1,
+							legacy_intf_freq2,
+							ml_num_link,
+							ml_freq_lst,
+							ml_linkid_lst);
 		}
 	}
 	/* usually it can't happen in 3 Port */
@@ -1442,7 +1549,8 @@ static bool ml_nlink_sta_inactivity_allowed_with_quiet(
 	struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS];
 
 	ml_nlink_get_link_info(psoc, vdev, (NLINK_EXCLUDE_REMOVED_LINK |
-					    NLINK_EXCLUDE_QUIET_LINK),
+					    NLINK_EXCLUDE_QUIET_LINK |
+					    NLINK_EXCLUDE_STANDBY_LINK),
 			       QDF_ARRAY_SIZE(ml_linkid_lst),
 			       ml_link_info, ml_freq_lst, ml_vdev_lst,
 			       ml_linkid_lst, &ml_num_link,
@@ -1518,15 +1626,16 @@ ml_nlink_allow_conc(struct wlan_objmgr_psoc *psoc,
 		if (bss_chan)
 			freq = bss_chan->ch_freq;
 
-		if (!policy_mgr_allow_concurrency(psoc, PM_STA_MODE,
-						  freq,
-						  HW_MODE_20_MHZ,
-						  conc_ext_flags.value,
-						  vdev_ids[i])) {
+		if (!policy_mgr_is_concurrency_allowed(psoc, PM_STA_MODE,
+						       freq,
+						       HW_MODE_20_MHZ,
+						       conc_ext_flags.value,
+						       NULL)) {
 			wlan_objmgr_vdev_release_ref(ml_vdev,
 						     WLAN_MLO_MGR_ID);
 			break;
 		}
+
 		wlan_objmgr_vdev_release_ref(ml_vdev, WLAN_MLO_MGR_ID);
 	}
 
@@ -1610,7 +1719,9 @@ ml_nlink_update_force_inactive(struct wlan_objmgr_psoc *psoc,
 				MLO_LINK_FORCE_MODE_INACTIVE,
 				0,
 				new->force_inactive_bitmap,
-				0, link_ctrl_f_overwrite_inactive_bitmap);
+				0,
+				link_ctrl_f_overwrite_inactive_bitmap |
+				link_ctrl_f_post_re_evaluate);
 	}
 
 end:
@@ -1636,7 +1747,8 @@ ml_nlink_update_force_inactive_num(struct wlan_objmgr_psoc *psoc,
 					new->force_inactive_num,
 					new->force_inactive_num_bitmap,
 					0,
-					link_ctrl_f_dynamic_force_link_num);
+					link_ctrl_f_dynamic_force_link_num |
+					link_ctrl_f_post_re_evaluate);
 	}
 
 	return status;
@@ -1712,6 +1824,12 @@ static QDF_STATUS ml_nlink_state_change(struct wlan_objmgr_psoc *psoc,
 		goto end;
 	if (!mlo_check_if_all_links_up(vdev))
 		goto end;
+	if (mlo_mgr_is_link_switch_in_progress(vdev) &&
+	    evt != ml_nlink_connect_completion_evt) {
+		mlo_debug("mlo vdev %d link switch in progress!",
+			  wlan_vdev_get_id(vdev));
+		goto end;
+	}
 
 	ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state);
 
@@ -1824,6 +1942,65 @@ ml_nlink_state_change_handler(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
+static QDF_STATUS
+ml_nlink_swtich_dynamic_inactive_link(struct wlan_objmgr_psoc *psoc,
+				      struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t link_id;
+	uint32_t standby_link_bitmap, dynamic_inactive_bitmap;
+	struct ml_link_force_state curr_force_state = {0};
+	uint8_t link_ids[MAX_MLO_LINK_ID];
+	uint8_t num_ids;
+
+	link_id = wlan_vdev_get_link_id(vdev);
+	if (link_id >= MAX_MLO_LINK_ID) {
+		mlo_err("invalid link id %d", link_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state);
+	standby_link_bitmap = ml_nlink_get_standby_link_bitmap(psoc, vdev);
+	standby_link_bitmap &= curr_force_state.force_inactive_num_bitmap &
+				~(1 << link_id);
+	/* In DBS RD, ML STA 2+5+6(standby link), force inactive num = 1 and
+	 * force inactive bitmap with 5 + 6 links will be sent to FW, host
+	 * will select 6G as dynamic inactive link, 5G vdev will be kept in
+	 * policy mgr active connection table.
+	 * If FW link switch and repurpose 5G vdev to 6G, host will need to
+	 * select 5G standby link as dynamic inactive.
+	 * Then 6G vdev can be moved to policy mgr active connection table.
+	 */
+	if (((1 << link_id) & curr_force_state.curr_dynamic_inactive_bitmap) &&
+	    ((1 << link_id) & curr_force_state.force_inactive_num_bitmap) &&
+	    !(standby_link_bitmap &
+			curr_force_state.curr_dynamic_inactive_bitmap) &&
+	    (standby_link_bitmap &
+			curr_force_state.force_inactive_num_bitmap)) {
+		num_ids = convert_link_bitmap_to_link_ids(
+						standby_link_bitmap,
+						QDF_ARRAY_SIZE(link_ids),
+						link_ids);
+		if (!num_ids) {
+			mlo_err("unexpected 0 link ids for bitmap 0x%x",
+				standby_link_bitmap);
+			return QDF_STATUS_E_INVAL;
+		}
+		/* Remove the link from dynamic inactive bitmap,
+		 * add the standby link to dynamic inactive bitmap.
+		 */
+		dynamic_inactive_bitmap =
+			curr_force_state.curr_dynamic_inactive_bitmap &
+						~(1 << link_id);
+		dynamic_inactive_bitmap |= 1 << link_ids[0];
+		mlo_debug("move out vdev %d link id %d from dynamic inactive, add standby link id %d",
+			  wlan_vdev_get_id(vdev), link_id, link_ids[0]);
+		ml_nlink_set_dynamic_inactive_links(psoc, vdev,
+						    dynamic_inactive_bitmap);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS
 ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,
 			    uint8_t vdev_id,
@@ -1833,6 +2010,7 @@ ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,
 	struct wlan_objmgr_vdev *vdev;
 	enum QDF_OPMODE mode;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct ml_link_force_state curr_force_state = {0};
 
 	mlo_debug("vdev %d %s(%d)", vdev_id, link_evt_to_string(evt),
 		  evt);
@@ -1846,12 +2024,17 @@ ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,
 
 	switch (evt) {
 	case ml_nlink_link_switch_start_evt:
-		/* todo: allow concurrenct check */
+		ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state);
+		if ((1 << data->evt.link_switch.new_ieee_link_id) &
+		    curr_force_state.force_inactive_bitmap) {
+			mlo_debug("target link %d is force inactive, don't switch to it",
+				  data->evt.link_switch.new_ieee_link_id);
+			status = QDF_STATUS_E_INVAL;
+		}
 		break;
-	case ml_nlink_link_switch_completion_evt:
-		status = ml_nlink_state_change_handler(
-			psoc, vdev, MLO_LINK_FORCE_REASON_CONNECT,
-			evt, data);
+	case ml_nlink_link_switch_pre_completion_evt:
+		status = ml_nlink_swtich_dynamic_inactive_link(
+				psoc, vdev);
 		break;
 	case ml_nlink_roam_sync_start_evt:
 		ml_nlink_clr_force_state(psoc, vdev);

+ 18 - 8
components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c

@@ -55,7 +55,8 @@ mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev)
 			return qdf_test_bit(i, sta_ctx->wlan_connect_req_links);
 	}
 
-	mlo_err("vdev not found in ml dev ctx list");
+	mlo_err("vdev:%d not found in ml dev ctx list", wlan_vdev_get_id(vdev));
+
 	return false;
 }
 
@@ -122,7 +123,7 @@ mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc,
 						    vdev_id,
 						    WLAN_MLME_SB_ID);
 	if (!vdev) {
-		mlo_err("VDEV is null");
+		mlo_err("VDEV:%d is null", vdev_id);
 		return;
 	}
 
@@ -265,7 +266,8 @@ QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 		mlo_debug("MLO_ROAM: Roamed to single link MLO");
 		mlo_set_single_link_ml_roaming(psoc, vdev_id, true);
 	} else {
-		mlo_debug("MLO_ROAM: Roamed to MLO");
+		mlo_debug("MLO_ROAM: Roamed to MLO with %d links",
+			  sync_ind->num_setup_links);
 		mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
 	}
 
@@ -319,12 +321,16 @@ QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev,
 		if (vdev_id == sync_ind->ml_link[i].vdev_id)
 			continue;
 
+		/* Standby Link */
+		if (sync_ind->ml_link[i].vdev_id == WLAN_INVALID_VDEV_ID)
+			continue;
+
 		link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
 								 sync_ind->ml_link[i].vdev_id,
 								 WLAN_MLME_SB_ID);
-
 		if (!link_vdev) {
-			mlo_err("Link vdev is null");
+			mlo_err("Link vdev:%d is null",
+				sync_ind->ml_link[i].vdev_id);
 			return QDF_STATUS_E_FAILURE;
 		}
 
@@ -553,7 +559,7 @@ QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
 void
 mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
 			   struct roam_offload_synch_ind *sync_ind,
-			   uint8_t skip_vdev_id)
+			   uint8_t skip_vdev_id, bool fill_all_links)
 {
 	uint8_t i, j;
 	struct mlo_link_info *link;
@@ -562,8 +568,10 @@ mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
 		return;
 
 	for (i = 0, j = 0; i < sync_ind->num_setup_links; i++) {
-		if (sync_ind->ml_link[i].vdev_id == skip_vdev_id)
+		if (!fill_all_links &&
+		    sync_ind->ml_link[i].vdev_id == skip_vdev_id)
 			continue;
+
 		link = &partner_info->partner_link_info[j];
 		link->link_id = sync_ind->ml_link[i].link_id;
 		link->vdev_id = sync_ind->ml_link[i].vdev_id;
@@ -577,7 +585,9 @@ mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info,
 		j++;
 	}
 	partner_info->num_partner_links = j;
-	mlo_debug("num_setup_links %d", partner_info->num_partner_links);
+	mlo_debug("vdev_to_skip:%d num_setup_links %d fill_all_links:%d",
+		  skip_vdev_id, partner_info->num_partner_links,
+		  fill_all_links);
 }
 
 void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev,

+ 26 - 9
components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c

@@ -48,7 +48,7 @@ const char *t2lm_get_event_str(enum wlan_t2lm_evt event)
 static
 bool t2lm_is_valid_t2lm_link_map(struct wlan_objmgr_vdev *vdev,
 				 struct wlan_t2lm_onging_negotiation_info *t2lm,
-				 uint8_t *valid_dir)
+				 enum wlan_t2lm_direction *valid_dir)
 {
 	uint8_t i, tid = 0;
 	enum wlan_t2lm_direction dir = WLAN_T2LM_INVALID_DIRECTION;
@@ -87,8 +87,10 @@ bool t2lm_is_valid_t2lm_link_map(struct wlan_objmgr_vdev *vdev,
 		    WLAN_T2LM_INVALID_DIRECTION)
 			continue;
 
-		if (t2lm->t2lm_info[dir].default_link_mapping) {
+		if (t2lm->t2lm_info[dir].default_link_mapping &&
+		    t2lm->t2lm_info[dir].direction == WLAN_T2LM_BIDI_DIRECTION) {
 			is_valid_link_mask = true;
+			*valid_dir = dir;
 			continue;
 		}
 
@@ -132,11 +134,12 @@ t2lm_gen_dialog_token(struct wlan_mlo_peer_t2lm_policy *t2lm_policy)
 
 QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev,
 			      struct wlan_objmgr_peer *peer,
-			      void *event_data, uint8_t *token)
+			      void *event_data, uint32_t frame_len,
+			      uint8_t *token)
 {
 	struct wlan_t2lm_onging_negotiation_info t2lm_req = {0};
 	struct wlan_t2lm_info *t2lm_info;
-	uint8_t dir = WLAN_T2LM_MAX_DIRECTION;
+	enum wlan_t2lm_direction dir = WLAN_T2LM_MAX_DIRECTION;
 	bool valid_map = false;
 	QDF_STATUS status;
 	struct wlan_mlo_peer_context *ml_peer;
@@ -146,6 +149,7 @@ QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_FAILURE;
 
 	status = wlan_mlo_parse_t2lm_action_frame(&t2lm_req, event_data,
+						  frame_len,
 						  WLAN_T2LM_CATEGORY_REQUEST);
 	if (status != QDF_STATUS_SUCCESS) {
 		mlme_err("Unable to parse T2LM request action frame");
@@ -165,6 +169,11 @@ QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev,
 		mlme_err("reject t2lm conf");
 	}
 
+	if (dir >= WLAN_T2LM_MAX_DIRECTION) {
+		mlme_err("Received T2LM IE has invalid direction");
+		status = QDF_STATUS_E_INVAL;
+	}
+
 	if (QDF_IS_STATUS_SUCCESS(status) &&
 	    t2lm_req.t2lm_info[dir].direction != WLAN_T2LM_INVALID_DIRECTION) {
 		wlan_t2lm_clear_peer_negotiation(peer);
@@ -224,7 +233,8 @@ QDF_STATUS t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev,
 
 QDF_STATUS t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev,
 			       struct wlan_objmgr_peer *peer,
-			       void *event_data, uint8_t *token)
+			       void *event_data, uint32_t frame_len,
+			       uint8_t *token)
 {
 	struct wlan_t2lm_onging_negotiation_info t2lm_rsp = {0};
 	struct wlan_t2lm_onging_negotiation_info *t2lm_req;
@@ -249,6 +259,7 @@ QDF_STATUS t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_SUCCESS;
 
 	status = wlan_mlo_parse_t2lm_action_frame(&t2lm_rsp, event_data,
+						  frame_len,
 						  WLAN_T2LM_CATEGORY_RESPONSE);
 	if (status != QDF_STATUS_SUCCESS) {
 		mlme_err("Unable to parse T2LM request action frame");
@@ -335,7 +346,8 @@ QDF_STATUS t2lm_handle_tx_teardown(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 			      struct wlan_objmgr_peer *peer,
 			      enum wlan_t2lm_evt event,
-			      void *event_data, uint8_t *token)
+			      void *event_data, uint32_t frame_len,
+			      uint8_t *token)
 {
 	struct wlan_objmgr_psoc *psoc;
 	QDF_STATUS status;
@@ -349,7 +361,8 @@ QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 
 	switch (event) {
 	case WLAN_T2LM_EV_ACTION_FRAME_RX_REQ:
-		status = t2lm_handle_rx_req(vdev, peer, event_data, token);
+		status = t2lm_handle_rx_req(vdev, peer, event_data,
+					    frame_len, token);
 		break;
 	case WLAN_T2LM_EV_ACTION_FRAME_TX_RESP:
 		status = t2lm_handle_tx_resp(vdev, event_data, token);
@@ -358,7 +371,8 @@ QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 		status = t2lm_handle_tx_req(vdev, peer, event_data, token);
 		break;
 	case WLAN_T2LM_EV_ACTION_FRAME_RX_RESP:
-		status = t2lm_handle_rx_resp(vdev, peer, event_data, token);
+		status = t2lm_handle_rx_resp(vdev, peer, event_data,
+					     frame_len, token);
 		break;
 	case WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN:
 		status = t2lm_handle_rx_teardown(vdev, peer, event_data);
@@ -696,6 +710,7 @@ wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev,
 	status = t2lm_deliver_event(vdev, peer,
 				    WLAN_T2LM_EV_ACTION_FRAME_TX_REQ,
 				    &t2lm_neg,
+				    0,
 				    &t2lm_neg.dialog_token);
 
 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
@@ -706,7 +721,9 @@ QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 				   struct wlan_objmgr_peer *peer,
 				   enum wlan_t2lm_evt event,
 				   void *event_data,
+				   uint32_t frame_len,
 				   uint8_t *dialog_token)
 {
-	return t2lm_deliver_event(vdev, peer, event, event_data, dialog_token);
+	return t2lm_deliver_event(vdev, peer, event, event_data,
+				  frame_len, dialog_token);
 }

+ 13 - 0
components/umac/twt/core/src/wlan_twt_cfg.c

@@ -438,3 +438,16 @@ wlan_twt_get_restricted_support(struct wlan_objmgr_psoc *psoc, bool *val)
 
 	return QDF_STATUS_SUCCESS;
 }
+
+bool
+wlan_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc)
+{
+	struct twt_psoc_priv_obj *twt_psoc_obj;
+
+	twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc);
+
+	if (twt_psoc_obj->twt_pmo_disabled)
+		return false;
+	else
+		return true;
+}

+ 14 - 0
components/umac/twt/core/src/wlan_twt_cfg.h

@@ -233,6 +233,14 @@ wlan_twt_cfg_get_support_in_11n_mode(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS
 wlan_twt_get_restricted_support(struct wlan_objmgr_psoc *psoc, bool *val);
 
+/**
+ * wlan_twt_get_pmo_allowed() - Get pmo allowed
+ * @psoc: psoc handler
+ *
+ * Return: True if twt pmo is allowed otherwise false
+ */
+bool
+wlan_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc);
 #else
 
 static inline QDF_STATUS wlan_twt_cfg_init(struct wlan_objmgr_psoc *psoc)
@@ -348,6 +356,12 @@ wlan_twt_get_restricted_support(struct wlan_objmgr_psoc *psoc, bool *val)
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline bool
+wlan_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc)
+{
+	return true;
+}
 #endif
 
 #endif /* End of _WLAN_TWT_CFG_H */

+ 15 - 1
components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h

@@ -1,5 +1,5 @@
 /*
- * 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
@@ -313,6 +313,13 @@ void ucfg_twt_get_work_params(struct wlan_objmgr_vdev *vdev,
  * Return: QDF_STATUS
  */
 QDF_STATUS ucfg_twt_cfg_set_responder(struct wlan_objmgr_psoc *psoc, bool val);
+/**
+ * ucfg_twt_get_pmo_allowed() - Get twt allowed
+ * @psoc: psoc handler
+ *
+ * Return: QDF_STATUS_SUCCESS
+ */
+bool ucfg_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc);
 #else
 static inline
 QDF_STATUS ucfg_twt_psoc_open(struct wlan_objmgr_psoc *psoc)
@@ -431,5 +438,12 @@ bool ucfg_twt_cfg_is_twt_enabled(struct wlan_objmgr_psoc *psoc)
 {
 	return false;
 }
+
+static inline
+bool ucfg_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc)
+{
+	return false;
+}
+
 #endif
 #endif

+ 6 - 0
components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c

@@ -241,3 +241,9 @@ void ucfg_twt_get_work_params(
 {
 	return wlan_twt_get_work_params(vdev, params, next_action);
 }
+
+bool ucfg_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc)
+{
+	return wlan_twt_get_pmo_allowed(psoc);
+}
+

+ 31 - 0
components/wmi/inc/wmi_unified_roam_api.h

@@ -24,6 +24,7 @@
 
 #include <wmi_unified_roam_param.h>
 #include "wlan_cm_roam_public_struct.h"
+#include "wlan_crypto_def_i.h"
 
 #ifdef FEATURE_LFR_SUBNET_DETECTION
 /**
@@ -119,6 +120,36 @@ wmi_extract_roam_vendor_control_param_event(wmi_unified_t wmi_handle,
 
 #endif
 
+#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
+/**
+ * wmi_extract_roam_synch_key_event() - extract roam synch key event
+ * @wmi_handle: wmi handle
+ * @event: roam synch key event buffer pointer
+ * @len: event len
+ * @keys: destination buffer to copy keys
+ * @num_keys: Number of keys
+ * @mld_addr: MLD address pointer
+ *
+ * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure
+ */
+QDF_STATUS
+wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event,
+				 uint32_t len,
+				 struct wlan_crypto_key_entry **keys,
+				 uint8_t *num_keys,
+				 struct qdf_mac_addr *mld_addr);
+#else
+static inline QDF_STATUS
+wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event,
+				 uint32_t len,
+				 struct wlan_crypto_key_entry **keys,
+				 uint8_t *num_keys,
+				 struct qdf_mac_addr *mld_addr)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
 /**
  * wmi_unified_roam_scan_filter_cmd() - send roam scan allowlist,
  *                                      denylist and preferred list

+ 19 - 1
components/wmi/src/wmi_unified_roam_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -157,6 +157,24 @@ wmi_extract_roam_vendor_control_param_event(wmi_unified_t wmi_handle,
 }
 #endif
 
+#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
+QDF_STATUS
+wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event,
+				 uint32_t len,
+				 struct wlan_crypto_key_entry **keys,
+				 uint8_t *num_keys,
+				 struct qdf_mac_addr *mld_addr)
+{
+	if (wmi_handle->ops->extract_roam_synch_key_event)
+		return wmi_handle->ops->extract_roam_synch_key_event(
+							wmi_handle, event,
+							len, keys, num_keys,
+							mld_addr);
+
+	return QDF_STATUS_E_FAILURE;
+}
+#endif
+
 QDF_STATUS wmi_unified_roam_invoke_cmd(wmi_unified_t wmi_handle,
 				       struct roam_invoke_req *roaminvoke)
 {

+ 446 - 25
components/wmi/src/wmi_unified_roam_tlv.c

@@ -27,6 +27,7 @@
 #include "ol_defines.h"
 #include "wlan_cm_roam_api.h"
 #include "wlan_mlme_api.h"
+#include "wlan_crypto_global_api.h"
 
 #define WMI_MAC_TO_PDEV_MAP(x) ((x) + (1))
 #define WMI_PDEV_TO_MAC_MAP(x) ((x) - (1))
@@ -2226,33 +2227,44 @@ wmi_fill_data_synch_event(struct roam_offload_synch_ind *roam_sync_ind,
 }
 
 #ifdef WLAN_FEATURE_11BE_MLO
+#define STANDBY_VDEV_ID (0xFFFFFFFF)
 static QDF_STATUS
 wmi_fill_roam_mlo_info(wmi_unified_t wmi_handle,
 		       WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf,
 		       struct roam_offload_synch_ind *roam_sync_ind)
 {
-	uint8_t i;
+	uint8_t i, mlo_max_allowed_links;
 	wmi_roam_ml_setup_links_param *setup_links;
 	wmi_roam_ml_key_material_param *ml_key_param;
 	struct ml_setup_link_param *link;
 	struct ml_key_material_param *key;
 
+	mlo_max_allowed_links =
+		wlan_mlme_get_sta_mlo_conn_max_num(wmi_handle->soc->wmi_psoc);
 	if (param_buf->num_setup_links_param) {
-		if (param_buf->num_setup_links_param >
-		    WLAN_UMAC_MLO_MAX_VDEVS) {
-			wmi_err("Number of umac mlo vdev entries %d exceeded max vdev supported %d",
+		if (param_buf->num_setup_links_param > mlo_max_allowed_links ||
+		    param_buf->num_setup_links_param > WLAN_MAX_ML_BSS_LINKS) {
+			wmi_err("Number of links %d exceeded max vdev supported %d",
 				param_buf->num_setup_links_param,
-				WLAN_UMAC_MLO_MAX_VDEVS);
+				mlo_max_allowed_links);
 			return QDF_STATUS_E_INVAL;
 		}
+
 		roam_sync_ind->num_setup_links =
-			param_buf->num_setup_links_param;
+				param_buf->num_setup_links_param;
 		setup_links = param_buf->setup_links_param;
 
 		for (i = 0; i < roam_sync_ind->num_setup_links; i++) {
 			link = &roam_sync_ind->ml_link[i];
 			link->link_id = setup_links->link_id;
-			link->vdev_id = setup_links->vdev_id;
+
+			/*
+			 * setup_links->vdev_id == UINT32_MAX for standby link
+			 */
+			link->vdev_id = WLAN_INVALID_VDEV_ID;
+			if (setup_links->vdev_id != STANDBY_VDEV_ID)
+				link->vdev_id = setup_links->vdev_id;
+
 			link->channel = setup_links->channel;
 			link->flags = setup_links->flags;
 
@@ -2269,25 +2281,30 @@ wmi_fill_roam_mlo_info(wmi_unified_t wmi_handle,
 			setup_links++;
 		}
 	}
-	if (param_buf->num_ml_key_material) {
-		roam_sync_ind->num_ml_key_material =
-			param_buf->num_ml_key_material;
-		ml_key_param = param_buf->ml_key_material;
-
-		for (i = 0; i < roam_sync_ind->num_ml_key_material; i++) {
-			key = &roam_sync_ind->ml_key[i];
-			key->link_id = ml_key_param->link_id;
-			key->key_idx = ml_key_param->key_ix;
-			key->key_cipher = ml_key_param->key_cipher;
-			qdf_mem_copy(key->pn, ml_key_param->pn,
-				     WMI_MAX_PN_LEN);
-			qdf_mem_copy(key->key_buff, ml_key_param->key_buff,
-				     WMI_MAX_KEY_LEN);
-			wmi_debug("link_id: %u key_idx: %u key_cipher: %u",
-				  key->link_id, key->key_idx, key->key_cipher);
-			ml_key_param++;
-		}
+
+	if (!param_buf->num_ml_key_material)
+		return QDF_STATUS_SUCCESS;
+
+	if (param_buf->num_ml_key_material > WLAN_MAX_ML_BSS_LINKS)
+		param_buf->num_ml_key_material = WLAN_MAX_ML_BSS_LINKS;
+
+	roam_sync_ind->num_ml_key_material = param_buf->num_ml_key_material;
+	ml_key_param = param_buf->ml_key_material;
+
+	for (i = 0; i < roam_sync_ind->num_ml_key_material; i++) {
+		key = &roam_sync_ind->ml_key[i];
+		key->link_id = ml_key_param->link_id;
+		key->key_idx = ml_key_param->key_ix;
+		key->key_cipher = ml_key_param->key_cipher;
+		qdf_mem_copy(key->pn, ml_key_param->pn,
+			     WMI_MAX_PN_LEN);
+		qdf_mem_copy(key->key_buff, ml_key_param->key_buff,
+			     WMI_MAX_KEY_LEN);
+		wmi_debug("link_id: %u key_idx: %u key_cipher: %u",
+			  key->link_id, key->key_idx, key->key_cipher);
+		ml_key_param++;
 	}
+
 	return QDF_STATUS_SUCCESS;
 }
 #else
@@ -3677,6 +3694,409 @@ wmi_roam_offload_attach_vendor_handoff_tlv(struct wmi_ops *ops)
 }
 #endif
 
+#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO)
+static inline
+enum wlan_crypto_cipher_type wlan_wmi_cipher_to_crypto(uint8_t cipher)
+{
+	switch (cipher) {
+	case WMI_CIPHER_NONE:
+		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_AES_CCM:
+		return WLAN_CRYPTO_CIPHER_AES_CCM;
+	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;
+	default:
+		return 0;
+	}
+}
+#define MLO_PAIRWISE_LINKID 0xF
+/**
+ * wmi_fill_keys_from_tlv  - Fill the destination key buffer from the WMI TLV
+ * @ml_keys: ML Keys TLV pointer
+ * @dst_key: Destination keys
+ * @dst_key_len: Destination keys length
+ * @count: TLV count
+ * @max_num_tlv: Total number of TLVs
+ *
+ * Return: None
+ */
+static void
+wmi_fill_keys_from_tlv(wmi_roam_ml_key_material_param **ml_keys,
+		       uint8_t *dst_key, uint8_t *dst_key_len, uint8_t *count,
+		       uint8_t max_num_tlv)
+{
+	uint8_t rem_key_len, bytes_filled, key_len, total_key_len;
+	uint8_t max_key_len = WLAN_CRYPTO_KEYBUF_SIZE + WLAN_CRYPTO_MICBUF_SIZE;
+
+	*dst_key_len = (*ml_keys)->key_len;
+	if (*dst_key_len > max_key_len)
+		*dst_key_len = max_key_len;
+
+	total_key_len = *dst_key_len;
+	rem_key_len = *dst_key_len;
+
+	while (rem_key_len) {
+		if (!(*ml_keys)) {
+			wmi_err_rl("ml_keys is NULL. rem_key_len:%d",
+				   rem_key_len);
+			return;
+		}
+
+		if (*count >= max_num_tlv) {
+			wmi_debug("Read all TLVs count:%d", *count);
+			return;
+		}
+
+		if (rem_key_len < WMI_MAX_KEY_LEN)
+			key_len = rem_key_len;
+		else
+			key_len = WMI_MAX_KEY_LEN;
+
+		bytes_filled = total_key_len - rem_key_len;
+		qdf_mem_copy(dst_key + bytes_filled, (*ml_keys)->key_buff,
+			     key_len);
+		(*ml_keys)++;
+		(*count)++;
+
+		rem_key_len -= key_len;
+	}
+}
+
+#define WMI_NUM_KEYS_ALLOCATED (WLAN_MAX_ML_BSS_LINKS * 4)
+static QDF_STATUS
+extract_roam_synch_key_event_tlv(wmi_unified_t wmi_handle,
+				 uint8_t *event, uint32_t data_len,
+				 struct wlan_crypto_key_entry **entries,
+				 uint8_t *num_entries,
+				 struct qdf_mac_addr *mld_addr)
+{
+	WMI_ROAM_SYNCH_KEY_EVENTID_param_tlvs *param_buf = NULL;
+	wmi_roam_ml_key_material_param *ml_keys = NULL;
+	struct wlan_crypto_key_entry *key_entry;
+	struct wlan_crypto_keys *all_keys;
+	struct wlan_crypto_key *dst_key, *pairwise;
+	struct wlan_crypto_key *key_alloc_buf[WMI_NUM_KEYS_ALLOCATED];
+	bool flush_keybuf;
+	uint8_t total_num_tlv,  j = 0, k = 0;
+	uint8_t count = 0, total_links = 0, dst_key_count = 0;
+	uint8_t igtk_idx = 0, bigtk_idx = 0;
+	bool slot_found;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	param_buf = (WMI_ROAM_SYNCH_KEY_EVENTID_param_tlvs *)event;
+	if (!param_buf) {
+		wmi_err_rl("received null buf from target");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	total_num_tlv = param_buf->num_ml_key_material;
+	ml_keys = (wmi_roam_ml_key_material_param *)param_buf->ml_key_material;
+	if (!ml_keys) {
+		wmi_err_rl("received ml keys param is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*entries = qdf_mem_malloc(WLAN_MAX_ML_BSS_LINKS * sizeof(*key_entry));
+	if (!*entries)
+		return QDF_STATUS_E_NOMEM;
+
+	/*
+	 * Allocate memory for each PTK, GTK, IGTK, BIGTK keys.
+	 * So total WLAN_MAX_ML_BSS_LINKS * 4 keys are needed
+	 */
+	for (k = 0; k < WMI_NUM_KEYS_ALLOCATED; k++) {
+		key_alloc_buf[k] = qdf_mem_malloc(sizeof(*dst_key));
+		if (!key_alloc_buf[k]) {
+			flush_keybuf = true;
+			status = QDF_STATUS_E_NOMEM;
+			goto free_entries;
+		}
+	}
+
+	/*
+	 * key_entry is the master structure that is given directly to the
+	 * crypto module and stored for each link.
+	 * key_entry -> keys ->key filled from dst_key has the PTK & GTK indexed
+	 * with corresponding key index
+	 *
+	 * key_entry -> keys -> iGTK holds the iGTK key
+	 * key_entry -> keys -> BIGTK holds the BIGTK key
+	 */
+	key_entry = *entries;
+
+	/*
+	 * Initialize all the Key Entry structures with invalid Link
+	 * ID to identify empty links allocated and will be freed
+	 * at the end.
+	 */
+	for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++)
+		key_entry[j].link_id = MLO_INVALID_LINK_IDX;
+
+	/*
+	 * TLV Format to parse:
+	 * 1. wmi_roam_ml_key_material_param -> For PTK with Link ID = 0xF
+	 * Copy this PTK to all the key entry of all the links.
+	 *
+	 * 2. wmi_roam_ml_key_material_param -> GTK for a valid Link.
+	 * Get available entry, and fill the GTK to that entry
+	 *
+	 * 3. wmi_roam_ml_key_material_param -> IGTK for a valid link
+	 *
+	 * 4. wmi_roam_ml_key_material_param -> BIGTK for a valid link
+	 *
+	 * 5. wmi_roam_ml_key_material_param -> For LTF Keyseed with Link ID =
+	 * 0xF and flags has LTF_USAGE set.
+	 *
+	 * If any of the key length is > WMI_MAX_KEY_LEN, then multiple
+	 * wmi_roam_ml_key_material_param TLVs follow to get the entire key
+	 */
+	while (ml_keys && count < total_num_tlv &&
+	       dst_key_count < WMI_NUM_KEYS_ALLOCATED) {
+		/*
+		 * Track individual keys with key_alloc_buf[dst_key_count] array
+		 * pointer to avoid mem leaks if parsing/validating any of the
+		 * keys fail.
+		 * Freeing the allocated keys it done at the end of this
+		 * function
+		 */
+		dst_key = key_alloc_buf[dst_key_count];
+		wmi_debug("link_id:%d key_ix:%d key_cipher:%d key_len:%d key_flags:%d",
+			  ml_keys->link_id, ml_keys->key_ix,
+			  ml_keys->key_cipher,
+			  ml_keys->key_len, ml_keys->key_flags);
+
+		if (!is_valid_keyix(ml_keys->key_ix)) {
+			wmi_err_rl("invalid key index:%d", ml_keys->key_ix);
+			status = QDF_STATUS_E_INVAL;
+			flush_keybuf = true;
+			goto free_entries;
+		}
+
+		/* Copy pairwise keys to all the entries */
+		if (ml_keys->link_id == MLO_PAIRWISE_LINKID) {
+			WMI_MAC_ADDR_TO_CHAR_ARRAY(&ml_keys->mac_addr,
+						   mld_addr->bytes);
+			if (!ml_keys->key_len) {
+				wmi_err_rl("Received key_len as 0 for tlv:%d",
+					   count);
+				status = QDF_STATUS_E_INVAL;
+				flush_keybuf = true;
+				goto free_entries;
+			}
+
+			if (ml_keys->key_flags & LTF_USAGE) {
+				struct wlan_crypto_ltf_keyseed_data key_seed;
+				uint8_t key_seed_len;
+
+				if (ml_keys->key_len >
+				    WLAN_MAX_SECURE_LTF_KEYSEED_LEN)
+					ml_keys->key_len =
+						WLAN_MAX_SECURE_LTF_KEYSEED_LEN;
+
+				/*
+				 * Filling the keys from multiple TLVs is
+				 * handled by below API and ml_keys ptr gets
+				 * incremented accordingly inside
+				 */
+				wmi_fill_keys_from_tlv(&ml_keys,
+						       key_seed.key_seed,
+						       &key_seed_len, &count,
+						       total_num_tlv);
+				key_seed.key_seed_len = key_seed_len;
+				wmi_debug("ML_KEY: Got LTF keyseed key for MLD: "
+					  QDF_MAC_ADDR_FMT   " key_seed_len:%d",
+					  QDF_MAC_ADDR_REF(mld_addr->bytes),
+					  key_seed.key_seed_len);
+
+				for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++)
+					key_entry[j].keys.ltf_key_seed =
+								key_seed;
+
+				continue;
+			}
+
+			dst_key->valid = true;
+			dst_key->keylen = ml_keys->key_len;
+			dst_key->flags = ml_keys->key_flags;
+			dst_key->keyix = ml_keys->key_ix;
+			dst_key->key_type =
+					WLAN_CRYPTO_KEY_TYPE_UNICAST;
+			dst_key->cipher_type =
+				wlan_wmi_cipher_to_crypto(ml_keys->key_cipher);
+			dst_key->keylen = ml_keys->key_len;
+
+			wmi_fill_keys_from_tlv(&ml_keys, dst_key->keyval,
+					       &dst_key->keylen, &count,
+					       total_num_tlv);
+			wmi_err_rl("ML_KEY: Got Pairwise key for MLD: "
+				   QDF_MAC_ADDR_FMT " rem_len:%d",
+				   QDF_MAC_ADDR_REF(mld_addr->bytes),
+				   dst_key->keylen);
+
+			pairwise = dst_key;
+			/*
+			 * Pairwise keys will be sent only once. Copy that for
+			 * all the link entries
+			 */
+			for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) {
+				dst_key = key_alloc_buf[dst_key_count];
+				*dst_key = *pairwise;
+				key_entry[j].keys.key[dst_key->keyix] = dst_key;
+				dst_key_count++;
+			}
+
+			continue;
+		}
+
+		slot_found = false;
+		for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) {
+			if (ml_keys->link_id == MLO_INVALID_LINK_IDX)
+				break;
+
+			if (key_entry[j].link_id == MLO_INVALID_LINK_IDX ||
+			    key_entry[j].link_id == ml_keys->link_id) {
+				slot_found = true;
+				break;
+			}
+		}
+
+		if (!slot_found) {
+			wmi_err_rl("Not able to find a entry for link:%d j=%d",
+				   ml_keys->link_id, j);
+			break;
+		}
+
+		WMI_MAC_ADDR_TO_CHAR_ARRAY(&ml_keys->mac_addr,
+					   dst_key->macaddr);
+		key_entry[j].link_id = ml_keys->link_id;
+		qdf_copy_macaddr((struct qdf_mac_addr *)key_entry[j].mac_addr.raw,
+				 (struct qdf_mac_addr *)dst_key->macaddr);
+		all_keys = &key_entry[j].keys;
+
+		dst_key->valid = true;
+		dst_key->keyix = ml_keys->key_ix;
+		dst_key->cipher_type =
+				wlan_wmi_cipher_to_crypto(ml_keys->key_cipher);
+
+		qdf_mem_copy(dst_key->keyrsc, ml_keys->pn, WMI_MAX_PN_LEN);
+
+		/*
+		 * For LTF keyseed or FILS SHA 384, FILS SHA 512 cases, the key
+		 * size will go beyond WMI_MAX_KEY_LEN(32). So extract first 32
+		 * bytes from 1st TLV and extract the rest of the bytes from
+		 * the following TLVs
+		 */
+		dst_key->keylen = ml_keys->key_len;
+		wmi_fill_keys_from_tlv(&ml_keys, dst_key->keyval,
+				       &dst_key->keylen, &count, total_num_tlv);
+
+		if (is_igtk(dst_key->keyix)) {
+			dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP;
+
+			igtk_idx = dst_key->keyix - WLAN_CRYPTO_MAXKEYIDX;
+			bigtk_idx = igtk_idx - WLAN_CRYPTO_MAXIGTKKEYIDX;
+
+			wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT "Key is IGTK key_ix:%d igtk_idx:%d bigtk:%d",
+				  j, key_entry[j].link_id,
+				  QDF_MAC_ADDR_REF(dst_key->macaddr),
+				  dst_key->keyix, igtk_idx, bigtk_idx);
+			all_keys->igtk_key[igtk_idx] = dst_key;
+			all_keys->def_igtk_tx_keyid = igtk_idx;
+
+			bigtk_idx = 0;
+			igtk_idx = 0;
+		} else if (is_bigtk(dst_key->keyix)) {
+			dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP;
+
+			igtk_idx = dst_key->keyix - WLAN_CRYPTO_MAXKEYIDX;
+			bigtk_idx = igtk_idx - WLAN_CRYPTO_MAXIGTKKEYIDX;
+
+			wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT "Key is BIGTK key_ix:%d igtk_idx:%d bigtk:%d",
+				  j, key_entry[j].link_id,
+				  QDF_MAC_ADDR_REF(dst_key->macaddr),
+				  dst_key->keyix, igtk_idx, bigtk_idx);
+			all_keys->bigtk_key[bigtk_idx] = dst_key;
+			all_keys->def_bigtk_tx_keyid = bigtk_idx;
+
+			bigtk_idx = 0;
+			igtk_idx = 0;
+		} else if (is_gtk(dst_key->keyix)) {
+			wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT " Key is GTK key_ix:%d",
+				  j, key_entry[j].link_id,
+				  QDF_MAC_ADDR_REF(dst_key->macaddr),
+				  dst_key->keyix);
+			dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP;
+			all_keys->key[dst_key->keyix] = dst_key;
+		} else {
+			wmi_debug("Key is Pairwise. Shouldn't reach here");
+			/* Pairwise key */
+			dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_UNICAST;
+			all_keys->key[dst_key->keyix] = dst_key;
+		}
+
+		dst_key_count++;
+	}
+
+	for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) {
+		if (key_entry[j].link_id != MLO_INVALID_LINK_IDX)
+			total_links++;
+	}
+
+	*num_entries = total_links;
+	/* Free the invalid dst_keys allocated */
+	if (!*num_entries)
+		goto free_entries;
+
+	/*
+	 * This is to free the unfilled key_alloc_buf that
+	 * was allocated initially
+	 */
+	flush_keybuf = false;
+
+	wmi_err_rl("ML_KEYS: total_entries filled:%d total_num_tlv:%d dst_key_count:%d",
+		   *num_entries, total_num_tlv, dst_key_count);
+	goto free_keys;
+
+free_entries:
+	qdf_mem_zero(*entries,
+		     WLAN_MAX_ML_BSS_LINKS * sizeof(**entries));
+	qdf_mem_free(*entries);
+
+free_keys:
+	for (k = 0; k < WMI_NUM_KEYS_ALLOCATED; k++) {
+		if (!key_alloc_buf[k])
+			continue;
+
+		if (!flush_keybuf && key_alloc_buf[k]->valid)
+			continue;
+
+		wmi_debug("Free key allocated at idx:%d", k);
+		qdf_mem_zero(key_alloc_buf[k], sizeof(key_alloc_buf[k]));
+		qdf_mem_free(key_alloc_buf[k]);
+	}
+
+	return status;
+}
+
+static void
+wmi_roam_offload_attach_mlo_tlv(struct wmi_ops *ops)
+{
+	ops->extract_roam_synch_key_event = extract_roam_synch_key_event_tlv;
+}
+#else
+static inline void
+wmi_roam_offload_attach_mlo_tlv(struct wmi_ops *ops)
+{}
+#endif
+
 void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
 {
 	struct wmi_ops *ops = wmi_handle->ops;
@@ -3703,6 +4123,7 @@ void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
 	ops->send_set_roam_trigger_cmd = send_set_roam_trigger_cmd_tlv;
 	ops->extract_roam_candidate_frame = extract_roam_candidate_frame_tlv;
 	wmi_roam_offload_attach_vendor_handoff_tlv(ops);
+	wmi_roam_offload_attach_mlo_tlv(ops);
 }
 #else
 static inline QDF_STATUS

+ 12 - 0
configs/config_to_feature.h

@@ -916,6 +916,14 @@
 #define WLAN_SYSFS_EHT_RATE (1)
 #endif
 
+#ifdef CONFIG_WLAN_SYSFS_WDS_MODE
+#define FEATURE_SYSFS_WDS_MODE (1)
+#endif
+
+#ifdef CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP
+#define FEATURE_SYSFS_ROAM_TRIGGER_BITMAP (1)
+#endif
+
 #ifdef CONFIG_RX_PERFORMANCE
 #define RX_PERFORMANCE (1)
 #endif
@@ -2895,4 +2903,8 @@
 #define WLAN_FEATURE_CE_RX_BUFFER_REUSE (1)
 #endif
 
+#ifndef CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE
+#define WLAN_TRACE_HIDE_MAC_ADDRESS (1)
+#endif
+
 #endif /* CONFIG_TO_FEATURE_H */

+ 9 - 4
configs/default_defconfig

@@ -330,6 +330,7 @@ ifeq ($(CONFIG_ARCH_QCS40X), y)
 	CONFIG_WLAN_FEATURE_LL_MODE := y
 ifeq ($(CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH), y)
 	CONFIG_WLAN_CLD_PM_QOS := y
+	CONFIG_WLAN_CLD_DEV_PM_QOS := y
 endif
 endif
 CONFIG_WLAN_FEATURE_MBSSID := y
@@ -409,6 +410,8 @@ endif
 	CONFIG_DP_PKT_ADD_TIMESTAMP := y
 	CONFIG_WLAN_SYSFS_LOG_BUFFER := y
 	CONFIG_WLAN_SYSFS_DFSNOL := y
+	CONFIG_WLAN_SYSFS_WDS_MODE := y
+	CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP := y
 endif
 CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM := y
 CONFIG_WLAN_POWER_DEBUG := y
@@ -419,11 +422,7 @@ endif
 CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y
 
 #Disable the Export Symbol config
-ifeq ($(CONFIG_QCACLD_FEATURE_SON), y)
 CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := n
-else
-CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y
-endif
 
 CONFIG_QCACLD_FEATURE_GREEN_AP := y
 
@@ -1176,10 +1175,16 @@ CONFIG_FEATURE_ROAM_DEBUG := y
 #Flag to enable DFS Master feature
 CONFIG_WLAN_DFS_MASTER_ENABLE := y
 
+ifeq ($(CONFIG_ARCH_PINEAPPLE), y)
 #Flag to enable WEXT support for STA/AP/P2P interfaces
+ifeq ($(CONFIG_CFG80211_WEXT), y)
+CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y
+endif
+else
 ifeq ($(CONFIG_WIRELESS_EXT), y)
 CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y
 endif
+endif
 
 #Flag to enable/disable MTRACE feature
 CONFIG_ENABLE_MTRACE_LOG := y

+ 1 - 0
configs/pineapple_consolidate_kiwi-v2_defconfig

@@ -31,3 +31,4 @@ CONFIG_WLAN_RECORD_RX_PADDR=y
 CONFIG_QDF_TEST=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_FEATURE_WLM_STATS=y
+CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y

+ 0 - 1
configs/pineapple_gki_kiwi-v2_defconfig

@@ -342,7 +342,6 @@ CONFIG_WLAN_TXRX_STATS=y
 CONFIG_WLAN_UMAC_MLO_MAX_DEV=3
 CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y
 CONFIG_WLAN_WBUFF=y
-CONFIG_WLAN_WEXT_SUPPORT_ENABLE=y
 CONFIG_WLAN_WOW_ITO=y
 CONFIG_WLAN_WOWL_ADD_PTRN=y
 CONFIG_WLAN_WOWL_DEL_PTRN=y

+ 2 - 0
configs/qca6174_defconfig

@@ -756,3 +756,5 @@ endif
 
 #Enable thermal throttle
 CONFIG_FW_THERMAL_THROTTLE := y
+
+CONFIG_ALLOC_CONTIGUOUS_MULTI_PAGE := y

+ 0 - 1
configs/wcn6450_defconfig

@@ -36,7 +36,6 @@ CONFIG_SERIALIZE_QUEUE_SETUP := y
 CONFIG_DP_RX_PKT_NO_PEER_DELIVER := y
 CONFIG_DP_RX_DROP_RAW_FRM := y
 CONFIG_FEATURE_ALIGN_STATS_FROM_DP := y
-CONFIG_DP_RX_SPECIAL_FRAME_NEED := y
 CONFIG_FEATURE_STATS_EXT_V2 := y
 CONFIG_WLAN_FEATURE_DP_RX_THREADS := y
 CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT := y

+ 2 - 2
core/dp/htt/htt_t2h.c

@@ -1088,8 +1088,8 @@ void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
 #ifdef WLAN_FEATURE_FASTPATH
 #define HTT_T2H_MSG_BUF_REINIT(_buf, dev)				\
 	do {								\
-		QDF_NBUF_CB_PADDR(_buf) -= (HTC_HEADER_LEN +		\
-					HTC_HDR_ALIGNMENT_PADDING);	\
+		qdf_nbuf_push_head(_buf, (HTC_HEADER_LEN) +		\
+				   HTC_HDR_ALIGNMENT_PADDING);		\
 		qdf_nbuf_init_fast((_buf));				\
 		qdf_mem_dma_sync_single_for_device(dev,			\
 					(QDF_NBUF_CB_PADDR(_buf)),	\

+ 3 - 1
core/hdd/inc/wlan_hdd_assoc.h

@@ -69,6 +69,7 @@ enum peer_status {
  * @hs20_present: hs20 element present or not
  * @ht_op_present: ht operation present or not
  * @vht_op_present: vht operation present or not
+ * @he_present: he operation present or not
  * @reserved: reserved spare bits
  */
 struct hdd_conn_flag {
@@ -78,7 +79,8 @@ struct hdd_conn_flag {
 	uint8_t hs20_present:1;
 	uint8_t ht_op_present:1;
 	uint8_t vht_op_present:1;
-	uint8_t reserved:2;
+	uint8_t he_present:1;
+	uint8_t reserved:1;
 };
 
 /*defines for tx_BF_cap_info */

+ 9 - 4
core/hdd/inc/wlan_hdd_mlo.h

@@ -325,17 +325,21 @@ int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy,
 /**
  * hdd_derive_link_address_from_mld() - Function to derive link address from
  * MLD address which is passed as input argument.
+ * @psoc: PSOC object manager
  * @mld_addr: Input MLD address
  * @link_addr_list: Start index of array to hold derived MAC addresses
  * @max_idx: Number of addresses to derive
  *
  * The API will generate link addresses from the input MLD address and saves
- * each link address as an array in @link_addr_list. Caller can request upto
- * WLAN_MAX_MLD addresses.
+ * each link address as an array in @link_addr_list.
+ *
+ * If CFG_MLO_SAME_LINK_MLD_ADDR is enabled, then API will not derive first
+ * link address and will use MLD address in that place.
  *
  * Return: QDF_STATUS
  */
-QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
+QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc,
+					    struct qdf_mac_addr *mld_addr,
 					    struct qdf_mac_addr *link_addr_list,
 					    uint8_t max_idx);
 
@@ -415,7 +419,8 @@ int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy,
 }
 
 static inline
-QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
+QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc,
+					    struct qdf_mac_addr *mld_addr,
 					    struct qdf_mac_addr *link_addr_list,
 					    uint8_t max_idx)
 {

+ 15 - 2
core/hdd/inc/wlan_hdd_power.h

@@ -499,13 +499,26 @@ int wlan_hdd_ipv6_changed(struct notifier_block *nb,
  * hdd_set_power_config() - set power config to firmware
  * @hddctx: HDD context
  * @adapter: HDD adapter
- * @power: new power config value
+ * @opm_mode: pointer to vendor opm_mode
  *
  * Return: 0 on success; Errno on failure
  */
 int hdd_set_power_config(struct hdd_context *hddctx,
-			 struct hdd_adapter *adapter, uint8_t power);
+			 struct hdd_adapter *adapter,
+			 enum qca_wlan_vendor_opm_mode *opm_mode);
 
+/**
+ * hdd_set_power_config_params() - set power config parameters
+ * @hddctx: HDD context
+ * @adapter: HDD adapter
+ * @ps_ito: power save inactivitiy duration in ms
+ * @spec_wake: power save speculative wake duration in ms
+ *
+ * Return: 0 on success; Errno on failure
+ */
+int hdd_set_power_config_params(struct hdd_context *hddctx,
+				struct hdd_adapter *adapter,
+				uint16_t ps_ito, uint16_t spec_wake);
 #ifdef FEATURE_WLAN_DIAG_SUPPORT
 /**
  * hdd_wlan_suspend_resume_event()- send suspend/resume state

+ 35 - 0
core/hdd/inc/wlan_hdd_twt.h

@@ -372,6 +372,28 @@ QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val);
  * Return: QDF_STATUS
  */
 QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val);
+
+/**
+ * wlan_hdd_resume_pmo_twt() - resume twt worker
+ * @hdd_ctx: hdd context
+ *
+ * Return: None
+ */
+void wlan_hdd_resume_pmo_twt(struct hdd_context *hdd_ctx);
+/**
+ * wlan_hdd_suspend_pmo_twt() - suspend twt worker
+ * @hdd_ctx: hdd context
+ *
+ * Return: None
+ */
+void wlan_hdd_suspend_pmo_twt(struct hdd_context *hdd_ctx);
+/**
+ * wlan_hdd_is_twt_pmo_allowed() - check twt disabled
+ * @hdd_ctx: hdd context
+ *
+ * Return: true if twt pmo is allowed otherwise false
+ */
+bool wlan_hdd_is_twt_pmo_allowed(struct hdd_context *hdd_ctx);
 #else
 static inline void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
 					  struct wma_tgt_cfg *cfg)
@@ -489,6 +511,19 @@ QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val)
 	return QDF_STATUS_E_NOSUPPORT;
 }
 
+static inline void wlan_hdd_resume_pmo_twt(struct hdd_context *hdd_ctx)
+{
+}
+
+static inline void wlan_hdd_suspend_pmo_twt(struct hdd_context *hdd_ctx)
+{
+}
+
+static inline bool wlan_hdd_is_twt_pmo_allowed(struct hdd_context *hdd_ctx)
+{
+	return true;
+}
+
 #define FEATURE_VENDOR_SUBCMD_WIFI_CONFIG_TWT
 
 #endif

+ 35 - 0
core/hdd/src/wlan_hdd_cfg.c

@@ -2171,6 +2171,37 @@ hdd_convert_chwidth_to_phy_chwidth(enum eSirMacHTChannelWidth chwidth)
 	return ch_width;
 }
 
+/**
+ * hdd_update_bss_rate_flags() - update bss rate flag as per new channel width
+ * @adapter: adapter being modified
+ * @psoc: psoc common object
+ * @cw: channel width for which bss rate flag being updated
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS hdd_update_bss_rate_flags(struct hdd_adapter *adapter,
+					    struct wlan_objmgr_psoc *psoc,
+					    enum phy_ch_width cw)
+{
+	struct hdd_station_ctx *hdd_sta_ctx;
+	uint8_t eht_present, he_present, vht_present, ht_present;
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
+	if (!hdd_sta_ctx) {
+		hdd_err("hdd_sta_ctx is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	eht_present = hdd_sta_ctx->conn_info.conn_flag.eht_present;
+	he_present = hdd_sta_ctx->conn_info.conn_flag.he_present;
+	vht_present = hdd_sta_ctx->conn_info.conn_flag.vht_present;
+	ht_present = hdd_sta_ctx->conn_info.conn_flag.ht_present;
+
+	return ucfg_mlme_update_bss_rate_flags(psoc, adapter->deflink->vdev_id,
+					       cw, eht_present, he_present,
+					       vht_present, ht_present);
+}
+
 int hdd_update_channel_width(struct hdd_adapter *adapter,
 			     enum eSirMacHTChannelWidth chwidth,
 			     uint32_t bonding_mode)
@@ -2197,6 +2228,10 @@ int hdd_update_channel_width(struct hdd_adapter *adapter,
 					adapter->deflink->vdev_id, ch_width);
 		if (QDF_IS_STATUS_ERROR(status))
 			return -EIO;
+		status = hdd_update_bss_rate_flags(adapter, hdd_ctx->psoc,
+						   ch_width);
+		if (QDF_IS_STATUS_ERROR(status))
+			return -EIO;
 	}
 
 	sme_config = qdf_mem_malloc(sizeof(*sme_config));

+ 74 - 11
core/hdd/src/wlan_hdd_cfg80211.c

@@ -3574,7 +3574,7 @@ static bool wlan_hdd_check_is_acs_request_same(struct hdd_adapter *adapter,
 	if (sap_config->acs_cfg.master_acs_cfg.ch_width != ch_width)
 		return false;
 
-	if (nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME])) {
+	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME]) {
 		last_scan_ageout_time =
 		nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME]);
 	} else {
@@ -8254,6 +8254,9 @@ const struct nla_policy wlan_hdd_wifi_config_policy[
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_NSS] = {.type = NLA_U8 },
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT] = {
 		.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO] = {.type = NLA_U16 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL] = {
+		.type = NLA_U16 },
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE] = {
 		.type = NLA_U8 },
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS] = {.type = NLA_U8 },
@@ -9540,21 +9543,82 @@ hdd_config_udp_qos_upgrade_threshold(struct wlan_hdd_link_info *link_info,
 	return hdd_set_udp_qos_upgrade_config(adapter, priority);
 }
 
+static enum powersave_mode
+hdd_vendor_opm_to_pmo_opm(enum qca_wlan_vendor_opm_mode opm_mode)
+{
+	switch (opm_mode) {
+	case QCA_WLAN_VENDOR_OPM_MODE_DISABLE:
+		return PMO_PS_ADVANCED_POWER_SAVE_DISABLE;
+	case QCA_WLAN_VENDOR_OPM_MODE_ENABLE:
+		return PMO_PS_ADVANCED_POWER_SAVE_ENABLE;
+	case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED:
+		return PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED;
+	default:
+		hdd_debug("Invalid opm_mode: %d", opm_mode);
+		return PMO_PS_ADVANCED_POWER_SAVE_DISABLE;
+	}
+}
+
 static int hdd_config_power(struct wlan_hdd_link_info *link_info,
-			    const struct nlattr *attr)
+			    struct nlattr *tb[])
 {
 	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
-	uint8_t power;
+	struct wlan_objmgr_vdev *vdev;
+	enum qca_wlan_vendor_opm_mode opm_mode;
+	struct pmo_ps_params ps_params = {0};
+	struct nlattr *power_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER];
+	struct nlattr *opm_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT];
+	struct nlattr *ps_ito_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO];
+	struct nlattr *spec_wake_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL];
+	int ret;
+
+	if (!power_attr && !opm_attr)
+		return 0;
+
+	if (power_attr && opm_attr) {
+		hdd_err_rl("Invalid OPM set attribute");
+		return -EINVAL;
+	}
 
 	if (!ucfg_pmo_get_default_power_save_mode(hdd_ctx->psoc)) {
 		hdd_err_rl("OPM power save is disabled in ini");
 		return -EINVAL;
 	}
 
-	power = nla_get_u8(attr);
+	opm_mode = power_attr ? nla_get_u8(power_attr) : nla_get_u8(opm_attr);
+	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED)
+		if (!ps_ito_attr || !spec_wake_attr) {
+			hdd_err_rl("Invalid User defined OPM attributes");
+			return -EINVAL;
+		}
+
+	ret = hdd_set_power_config(hdd_ctx, adapter, &opm_mode);
+	if (ret)
+		return ret;
+
+	ps_params.opm_mode = hdd_vendor_opm_to_pmo_opm(opm_mode);
+	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED) {
+		ps_params.ps_ito = nla_get_u16(ps_ito_attr);
+		ps_params.spec_wake = nla_get_u16(spec_wake_attr);
+		ret = hdd_set_power_config_params(hdd_ctx, adapter,
+						  ps_params.ps_ito,
+						  ps_params.spec_wake);
+		if (ret)
+			return ret;
+	}
 
-	return hdd_set_power_config(hdd_ctx, adapter, power);
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_POWER_ID);
+	if (vdev) {
+		ucfg_pmo_set_ps_params(vdev, &ps_params);
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
+	}
+
+	return 0;
 }
 
 static int hdd_config_stats_avg_factor(struct wlan_hdd_link_info *link_info,
@@ -11562,8 +11626,6 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_config_lro},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE,
 	 hdd_config_scan_enable},
-	{QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER,
-	 hdd_config_power},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR,
 	 hdd_config_stats_avg_factor},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME,
@@ -11630,8 +11692,6 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_set_dynamic_bw},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_NSS,
 	 hdd_set_nss},
-	{QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT,
-	 hdd_config_power},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE,
 	 hdd_config_udp_qos_upgrade_threshold},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_CONCURRENT_STA_PRIMARY,
@@ -12392,6 +12452,7 @@ static const interdependent_setter_fn interdependent_setters[] = {
 	hdd_config_tx_rx_nss,
 	hdd_process_generic_set_cmd,
 	hdd_config_phy_mode,
+	hdd_config_power,
 };
 
 /**
@@ -21616,7 +21677,8 @@ hdd_adapter_update_mac_on_mode_change(struct hdd_adapter *adapter)
 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
 	struct qdf_mac_addr link_addr[WLAN_MAX_ML_BSS_LINKS] = {0};
 
-	status = hdd_derive_link_address_from_mld(&adapter->mld_addr,
+	status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
+						  &adapter->mld_addr,
 						  &link_addr[0],
 						  WLAN_MAX_ML_BSS_LINKS);
 	if (QDF_IS_STATUS_ERROR(status))
@@ -22727,7 +22789,8 @@ static int wlan_hdd_add_key_vdev(mac_handle_t mac_handle,
 done:
 	wlan_hdd_mlo_link_free_keys(hdd_ctx->psoc, adapter, vdev, pairwise);
 	if (pairwise && adapter->device_mode == QDF_STA_MODE &&
-	    wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+	    wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	    !wlan_vdev_mlme_is_tdls_vdev(vdev)) {
 		wlan_hdd_mlo_link_add_pairwise_key(vdev, hdd_ctx, key_index,
 						   pairwise, params);
 

+ 10 - 0
core/hdd/src/wlan_hdd_cm_connect.c

@@ -1133,6 +1133,16 @@ static void hdd_cm_save_bss_info(struct wlan_hdd_link_info *link_info,
 		hdd_sta_ctx->conn_info.conn_flag.vht_op_present = false;
 	}
 
+	if (assoc_resp->he_cap.present)
+		hdd_sta_ctx->conn_info.conn_flag.he_present = true;
+	else
+		hdd_sta_ctx->conn_info.conn_flag.he_present = false;
+
+	if (assoc_resp->eht_cap.present)
+		hdd_sta_ctx->conn_info.conn_flag.eht_present = true;
+	else
+		hdd_sta_ctx->conn_info.conn_flag.eht_present = false;
+
 	/*
 	 * Cache connection info only in case of station
 	 */

+ 17 - 22
core/hdd/src/wlan_hdd_hostapd.c

@@ -2372,8 +2372,6 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 		if (QDF_IS_STATUS_SUCCESS(qdf_status))
 			hdd_medium_assess_stop_timer(pdev_id, hdd_ctx);
 
-		hdd_medium_assess_deinit();
-
 		/* clear the reason code in case BSS is stopped
 		 * in another place
 		 */
@@ -3126,7 +3124,8 @@ stopbss:
 				ucfg_ipa_uc_disconnect_ap(hdd_ctx->pdev,
 							  adapter->dev);
 				ucfg_ipa_cleanup_dev_iface(hdd_ctx->pdev,
-							   adapter->dev);
+							   adapter->dev,
+							   link_info->vdev_id);
 			}
 		}
 
@@ -5641,10 +5640,11 @@ hdd_check_and_disconnect_sta_on_invalid_channel(struct hdd_context *hdd_ctx,
  * @adapter: SAP adapter
  * @sap_config: sap config
  *
- * In SAP+GO concurrency, if GO is started on 2G and SAP is doing ACS
- * with 2G preferred channel list, then we will move GO to 5G band.
- * The purpose is to have more selection for SAP instead of starting on
- * GO home channel for SCC.
+ * In GO+STA+SAP concurrency, if GO is started on 2G and SAP is doing ACS
+ * with 2G preferred channel list, then we will move GO to 2G SCC
+ * channel of STA if present.
+ * The purpose is to avoid SAP start failure on 2G because we don't
+ * support 3 home channels in same mac.
  *
  * Return: void
  */
@@ -5666,8 +5666,9 @@ hdd_handle_acs_2g_preferred_sap_conc(struct wlan_objmgr_psoc *psoc,
 	uint8_t sta_vdev_num;
 	struct hdd_hostapd_state *hostapd_state;
 	uint8_t go_vdev_id = WLAN_UMAC_VDEV_ID_MAX;
-	qdf_freq_t go_ch_freq = 0, go_new_ch_freq;
+	qdf_freq_t go_ch_freq = 0, go_new_ch_freq = 0;
 	struct wlan_hdd_link_info *go_link_info;
+	enum phy_ch_width go_bw;
 
 	if (adapter->device_mode != QDF_SAP_MODE)
 		return;
@@ -5682,7 +5683,7 @@ hdd_handle_acs_2g_preferred_sap_conc(struct wlan_objmgr_psoc *psoc,
 		if (!WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq_list[i]))
 			return;
 
-	/* Move existing GO interface to 5G band */
+	/* Move existing GO interface to SCC channel of 2G STA */
 	vdev_num = policy_mgr_get_mode_specific_conn_info(
 			psoc, freq_list, vdev_id_list,
 			PM_P2P_GO_MODE);
@@ -5700,19 +5701,15 @@ hdd_handle_acs_2g_preferred_sap_conc(struct wlan_objmgr_psoc *psoc,
 	sta_vdev_num = policy_mgr_get_mode_specific_conn_info(
 			psoc, sta_freq_list, sta_vdev_id_list,
 			PM_STA_MODE);
-	for (i = 0; i < sta_vdev_num; i++)
+	for (i = 0; i < sta_vdev_num; i++) {
 		if (go_ch_freq == sta_freq_list[i])
 			return;
+		if (WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[i]))
+			go_new_ch_freq = sta_freq_list[i];
+	}
 
-	go_new_ch_freq =
-		policy_mgr_get_alternate_channel_for_sap(psoc,
-							 go_vdev_id,
-							 go_ch_freq,
-							 REG_BAND_UNKNOWN);
-	if (!go_new_ch_freq || WLAN_REG_IS_24GHZ_CH_FREQ(go_new_ch_freq)) {
-		hdd_err("no available 5G channel");
+	if (!go_new_ch_freq)
 		return;
-	}
 
 	go_link_info = hdd_get_link_info_by_vdev(adapter->hdd_ctx, go_vdev_id);
 	if (!go_link_info || hdd_validate_adapter(go_link_info->adapter))
@@ -5722,9 +5719,9 @@ hdd_handle_acs_2g_preferred_sap_conc(struct wlan_objmgr_psoc *psoc,
 				    CSA_REASON_SAP_ACS);
 	hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(go_link_info);
 	qdf_event_reset(&hostapd_state->qdf_event);
-
+	go_bw = wlansap_get_chan_width(WLAN_HDD_GET_SAP_CTX_PTR(go_link_info));
 	ret = hdd_softap_set_channel_change(go_link_info->adapter->dev,
-					    go_new_ch_freq, CH_WIDTH_80MHZ,
+					    go_new_ch_freq, go_bw,
 					    false);
 	if (ret) {
 		hdd_err("CSA failed to %d, ret %d", go_new_ch_freq, ret);
@@ -6969,7 +6966,6 @@ int wlan_hdd_cfg80211_start_bss(struct wlan_hdd_link_info *link_info,
 	hdd_set_connection_in_progress(false);
 	policy_mgr_process_force_scc_for_nan(hdd_ctx->psoc);
 	ret = 0;
-	hdd_medium_assess_init();
 	goto free;
 
 error:
@@ -7150,7 +7146,6 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
 				hdd_place_marker(adapter, "STOP with FAILURE",
 						 NULL);
 				hdd_sap_indicate_disconnect_for_sta(adapter);
-				hdd_medium_assess_deinit();
 				QDF_ASSERT(0);
 			}
 		}

+ 25 - 5
core/hdd/src/wlan_hdd_ioctl.c

@@ -2646,11 +2646,11 @@ static int drv_cmd_set_wmmps(struct wlan_hdd_link_info *link_info,
 	return hdd_wmmps_helper(link_info->adapter, command);
 }
 
-static inline int drv_cmd_country(struct wlan_hdd_link_info *link_info,
-				  struct hdd_context *hdd_ctx,
-				  uint8_t *command,
-				  uint8_t command_len,
-				  struct hdd_priv_data *priv_data)
+static inline int __drv_cmd_country(struct wlan_hdd_link_info *link_info,
+				    struct hdd_context *hdd_ctx,
+				    uint8_t *command,
+				    uint8_t command_len,
+				    struct hdd_priv_data *priv_data)
 {
 	char *country_code;
 
@@ -2677,6 +2677,26 @@ static inline int drv_cmd_country(struct wlan_hdd_link_info *link_info,
 	return hdd_reg_set_country(hdd_ctx, country_code);
 }
 
+static inline int drv_cmd_country(struct wlan_hdd_link_info *link_info,
+				  struct hdd_context *hdd_ctx,
+				  uint8_t *command,
+				  uint8_t command_len,
+				  struct hdd_priv_data *priv_data)
+{
+	struct osif_psoc_sync *psoc_sync;
+	int errno;
+
+	errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync);
+	if (errno)
+		return errno;
+	errno = __drv_cmd_country(link_info, hdd_ctx, command, command_len,
+				  priv_data);
+
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno;
+}
+
 /**
  * drv_cmd_get_country() - Helper function to get current county code
  * @link_info: Link info pointer in HDD adapter

+ 19 - 7
core/hdd/src/wlan_hdd_main.c

@@ -8896,11 +8896,15 @@ static inline
 void hdd_ipa_ap_disconnect_evt(struct hdd_context *hdd_ctx,
 			       struct hdd_adapter *adapter)
 {
+	struct wlan_hdd_link_info *link_info;
+
+	link_info = adapter->deflink;
 	if (ucfg_ipa_is_enabled()) {
 		ucfg_ipa_uc_disconnect_ap(hdd_ctx->pdev,
 					  adapter->dev);
 		ucfg_ipa_cleanup_dev_iface(hdd_ctx->pdev,
-					   adapter->dev);
+					   adapter->dev,
+					   link_info->vdev_id);
 	}
 }
 
@@ -9103,7 +9107,8 @@ hdd_sta_disconnect_and_cleanup(struct wlan_hdd_link_info *link_info)
 	status = wlan_hdd_cm_issue_disconnect(link_info, reason, true);
 	if (QDF_IS_STATUS_ERROR(status) && ucfg_ipa_is_enabled()) {
 		hdd_err("STA disconnect failed");
-		ucfg_ipa_uc_cleanup_sta(adapter->hdd_ctx->pdev, adapter->dev);
+		ucfg_ipa_uc_cleanup_sta(adapter->hdd_ctx->pdev, adapter->dev,
+					link_info->vdev_id);
 	}
 }
 
@@ -13618,6 +13623,7 @@ void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx)
 void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx)
 {
 	qdf_delayed_work_stop_sync(&hdd_ctx->psoc_idle_timeout_work);
+	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_IFACE_CHANGE_TIMER);
 	hdd_debug("Stopped psoc idle timer");
 }
 
@@ -13640,6 +13646,8 @@ static int __hdd_psoc_idle_shutdown(struct hdd_context *hdd_ctx)
 
 	hdd_enter();
 
+	hdd_reg_wait_for_country_change(hdd_ctx);
+
 	errno = osif_psoc_sync_trans_start(hdd_ctx->parent_dev, &psoc_sync);
 	if (errno) {
 		hdd_info("psoc busy, abort idle shutdown; errno:%d", errno);
@@ -14327,7 +14335,8 @@ hdd_adapter_get_link_mac_addr(struct wlan_hdd_link_info *link_info)
 
 	adapter = link_info->adapter;
 	if (!hdd_adapter_is_ml_adapter(adapter) ||
-	    qdf_is_macaddr_zero(&link_info->link_addr))
+	    qdf_is_macaddr_zero(&link_info->link_addr) ||
+	    !wlan_vdev_mlme_is_mlo_vdev(link_info->vdev))
 		return &adapter->mac_addr;
 
 	return &link_info->link_addr;
@@ -14370,6 +14379,7 @@ QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter)
 {
 	int i = 0;
 	QDF_STATUS status;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	enum QDF_OPMODE opmode = adapter->device_mode;
 	struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0};
 	struct wlan_hdd_link_info *link_info;
@@ -14386,7 +14396,8 @@ QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter)
 	if (!hdd_adapter_is_ml_adapter(adapter))
 		return QDF_STATUS_SUCCESS;
 
-	status = hdd_derive_link_address_from_mld(&adapter->mac_addr,
+	status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
+						  &adapter->mac_addr,
 						  &link_addrs[0],
 						  WLAN_MAX_ML_BSS_LINKS);
 	if (QDF_IS_STATUS_ERROR(status))
@@ -14619,6 +14630,9 @@ int hdd_start_ap_adapter(struct hdd_adapter *adapter, bool rtnl_held)
 	hdd_register_hl_netdev_fc_timer(adapter,
 					hdd_tx_resume_timer_expired_handler);
 
+	if (cds_is_driver_recovering())
+		hdd_medium_assess_ssr_reinit();
+
 	hdd_exit();
 	return 0;
 
@@ -18010,8 +18024,6 @@ void wlan_hdd_start_sap(struct wlan_hdd_link_info *link_info, bool reinit)
 	}
 	hdd_info("SAP Start Success");
 
-	if (reinit)
-		hdd_medium_assess_init();
 	wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL);
 	set_bit(SOFTAP_BSS_STARTED, &link_info->link_flags);
 	if (hostapd_state->bss_state == BSS_START) {
@@ -20210,6 +20222,7 @@ static void hdd_update_hif_config(struct hdd_context *hdd_ctx)
 		ucfg_dp_get_rx_softirq_yield_duration(hdd_ctx->psoc);
 
 	hif_init_ini_config(scn, &cfg);
+	hif_set_enable_rpm(scn);
 
 	if (prevent_link_down)
 		hif_vote_link_up(scn);
@@ -20767,7 +20780,6 @@ void hdd_restart_sap(struct wlan_hdd_link_info *link_info)
 		}
 		wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL);
 		hdd_err("SAP Start Success");
-		hdd_medium_assess_init();
 		set_bit(SOFTAP_BSS_STARTED, &link_info->link_flags);
 		if (hapd_state->bss_state == BSS_START) {
 			policy_mgr_incr_active_session(hdd_ctx->psoc,

+ 196 - 188
core/hdd/src/wlan_hdd_medium_assess.c

@@ -71,7 +71,8 @@
 
 #define MEDIUM_ASSESS_TIMER_INTERVAL 1000 /* 1000ms */
 static qdf_mc_timer_t hdd_medium_assess_timer;
-static uint8_t timer_enable, ssr_flag;
+static bool ssr_flag;
+static bool timer_enable;
 struct hdd_medium_assess_info medium_assess_info[WLAN_UMAC_MAX_RP_PID];
 unsigned long stime;
 
@@ -377,9 +378,12 @@ void hdd_medium_assess_ssr_enable_flag(void)
 {
 	uint8_t i;
 
-	ssr_flag = 1;
+	ssr_flag = true;
 	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
 		hdd_congestion_reset_data(i);
+
+	if (timer_enable)
+		qdf_mc_timer_destroy(&hdd_medium_assess_timer);
 }
 
 void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx)
@@ -409,6 +413,167 @@ void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx)
 	}
 }
 
+/**
+ * hdd_congestion_notification_calculation() - medium assess congestion
+ * calculation.
+ * @info: structure hdd_medium_assess_info
+ *
+ * Return: None
+ */
+static void
+hdd_congestion_notification_calculation(struct hdd_medium_assess_info *info)
+{
+	struct medium_assess_data *h_data, *t_data;
+	int32_t h_index, t_index;
+	uint32_t rx_clear_count_delta, tx_frame_count_delta;
+	uint32_t cycle_count_delta, my_rx_count_delta;
+	uint32_t congestion = 0;
+	uint64_t diff;
+
+	h_index = info->index - 1;
+	if (h_index < 0)
+		h_index = MEDIUM_ASSESS_NUM - 1;
+
+	if (h_index >= info->config.interval)
+		t_index = h_index - info->config.interval;
+	else
+		t_index = MEDIUM_ASSESS_NUM - info->config.interval - h_index;
+
+	if (h_index < 0 || h_index >= MEDIUM_ASSESS_NUM ||
+	    t_index < 0 || t_index >= MEDIUM_ASSESS_NUM) {
+		hdd_err("medium assess index is not valid.");
+		return;
+	}
+
+	h_data = &info->data[h_index];
+	t_data = &info->data[t_index];
+
+	if (!(h_data->part1_valid || h_data->part2_valid ||
+	      t_data->part1_valid || t_data->part2_valid)) {
+		hdd_err("medium assess data is not valid.");
+		return;
+	}
+
+	if (h_data->rx_clear_count >= t_data->rx_clear_count) {
+		rx_clear_count_delta = h_data->rx_clear_count -
+						t_data->rx_clear_count;
+	} else {
+		rx_clear_count_delta = U32_MAX - t_data->rx_clear_count;
+		rx_clear_count_delta += h_data->rx_clear_count;
+	}
+
+	if (h_data->tx_frame_count >= t_data->tx_frame_count) {
+		tx_frame_count_delta = h_data->tx_frame_count -
+						t_data->tx_frame_count;
+	} else {
+		tx_frame_count_delta = U32_MAX - t_data->tx_frame_count;
+		tx_frame_count_delta += h_data->tx_frame_count;
+	}
+
+	if (h_data->my_rx_count >= t_data->my_rx_count) {
+		my_rx_count_delta = h_data->my_rx_count - t_data->my_rx_count;
+	} else {
+		my_rx_count_delta = U32_MAX - t_data->my_rx_count;
+		my_rx_count_delta += h_data->my_rx_count;
+	}
+
+	if (h_data->cycle_count >= t_data->cycle_count) {
+		cycle_count_delta = h_data->cycle_count - t_data->cycle_count;
+	} else {
+		cycle_count_delta = U32_MAX - t_data->cycle_count;
+		cycle_count_delta += h_data->cycle_count;
+	}
+
+	if (rx_clear_count_delta > tx_frame_count_delta &&
+	    rx_clear_count_delta - tx_frame_count_delta > my_rx_count_delta) {
+		diff = rx_clear_count_delta - tx_frame_count_delta
+		       - my_rx_count_delta;
+		if (cycle_count_delta)
+			congestion = qdf_do_div(diff * 100, cycle_count_delta);
+
+		if (congestion > 100)
+			congestion = 100;
+	}
+
+	hdd_debug("pdev: %d, rx_c %u, tx %u myrx %u cycle %u congestion: %u",
+		  info->pdev_id, rx_clear_count_delta, tx_frame_count_delta,
+		  my_rx_count_delta, cycle_count_delta, congestion);
+	if (congestion >= info->config.threshold)
+		hdd_congestion_notification_report(info->vdev_id, congestion);
+}
+
+/**
+ * hdd_congestion_notification_report_multi() - medium assess report
+ * multi interface.
+ * @pdev_id: pdev id
+ *
+ * Return: None
+ */
+static void hdd_congestion_notification_report_multi(uint8_t pdev_id)
+{
+	struct hdd_medium_assess_info *info;
+
+	info = &medium_assess_info[pdev_id];
+	info->count++;
+	if (info->count % info->config.interval == 0)
+		hdd_congestion_notification_calculation(info);
+}
+
+/**
+ * hdd_medium_assess_expire_handler() - timer callback
+ * @arg: argument
+ *
+ * Return: None
+ */
+static void hdd_medium_assess_expire_handler(void *arg)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct request_info info = {0};
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	struct wlan_hdd_link_info *link_info;
+	uint8_t vdev_id = INVALID_VDEV_ID, pdev_id;
+	uint8_t index, i;
+
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return;
+
+	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
+		if (medium_assess_info[i].config.interval != 0) {
+			vdev_id = medium_assess_info[i].vdev_id;
+			pdev_id = medium_assess_info[i].pdev_id;
+			hdd_congestion_notification_report_multi(pdev_id);
+
+			/* ensure events are reveived at the 'same' time */
+			index = medium_assess_info[i].index;
+			medium_assess_info[i].data[index].part1_valid = false;
+			medium_assess_info[i].data[index].part2_valid = false;
+		}
+
+	if (vdev_id == INVALID_VDEV_ID)
+		return;
+
+	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
+	if (!link_info) {
+		hdd_err("Failed to find adapter of vdev %d", vdev_id);
+		return;
+	}
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_CP_STATS_ID);
+	if (!vdev)
+		return;
+
+	info.vdev_id = vdev_id;
+	info.pdev_id = WMI_HOST_PDEV_ID_SOC;
+	info.u.congestion_notif_cb = hdd_congestion_notification_cb;
+	stime = jiffies + msecs_to_jiffies(40);
+	ucfg_mc_cp_stats_send_stats_request(vdev,
+					    TYPE_CONGESTION_STATS,
+					    &info);
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_CP_STATS_ID);
+	qdf_mc_timer_start(&hdd_medium_assess_timer,
+			   MEDIUM_ASSESS_TIMER_INTERVAL);
+}
+
 /**
  * hdd_medium_assess_congestion_report() - congestion report
  * @hdd_ctx: pointer to HDD context
@@ -453,6 +618,12 @@ static int hdd_medium_assess_congestion_report(struct hdd_context *hdd_ctx,
 		hdd_debug("medium assess disable: pdev_id %d, vdev_id: %d",
 			  pdev_id, vdev_id);
 		hdd_medium_assess_stop_timer(pdev_id, hdd_ctx);
+		if (timer_enable &&
+		    (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) ==
+		     QDF_TIMER_STATE_STOPPED)) {
+			qdf_mc_timer_destroy(&hdd_medium_assess_timer);
+			timer_enable = false;
+		}
 		break;
 	case REPORT_ENABLE:
 		if (!tb[CONGESTION_REPORT_THRESHOLD]) {
@@ -482,8 +653,22 @@ static int hdd_medium_assess_congestion_report(struct hdd_context *hdd_ctx,
 		hdd_debug("medium assess enable: pdev_id %d, vdev_id: %d",
 			  pdev_id, vdev_id);
 
-		if (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) ==
-						     QDF_TIMER_STATE_STOPPED) {
+		if (!timer_enable) {
+			status =
+			    qdf_mc_timer_init(&hdd_medium_assess_timer,
+					      QDF_TIMER_TYPE_SW,
+					      hdd_medium_assess_expire_handler,
+					      NULL);
+			if (QDF_IS_STATUS_ERROR(status)) {
+				hdd_debug("medium assess init timer failed");
+				errno = -EINVAL;
+				goto out;
+			}
+			timer_enable = true;
+		}
+
+		if (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) !=
+		    QDF_TIMER_STATE_RUNNING) {
 			hdd_debug("medium assess atimer start");
 			qdf_mc_timer_start(&hdd_medium_assess_timer,
 					   MEDIUM_ASSESS_TIMER_INTERVAL);
@@ -584,200 +769,23 @@ int hdd_cfg80211_medium_assess(struct wiphy *wiphy,
 	return errno;
 }
 
-/**
- * hdd_congestion_notification_calculation() - medium assess congestion
- * calculation.
- * @info: structure hdd_medium_assess_info
- *
- * Return: None
- */
-static void
-hdd_congestion_notification_calculation(struct hdd_medium_assess_info *info)
-{
-	struct medium_assess_data *h_data, *t_data;
-	int32_t h_index, t_index;
-	uint32_t rx_clear_count_delta, tx_frame_count_delta;
-	uint32_t cycle_count_delta, my_rx_count_delta;
-	uint32_t congestion = 0;
-	uint64_t diff;
-
-	h_index = info->index - 1;
-	if (h_index < 0)
-		h_index = MEDIUM_ASSESS_NUM - 1;
-
-	if (h_index >= info->config.interval)
-		t_index = h_index - info->config.interval;
-	else
-		t_index = MEDIUM_ASSESS_NUM - info->config.interval - h_index;
-
-	if (h_index < 0 || h_index >= MEDIUM_ASSESS_NUM ||
-	    t_index < 0 || t_index >= MEDIUM_ASSESS_NUM) {
-		hdd_err("medium assess index is not valid.");
-		return;
-	}
-
-	h_data = &info->data[h_index];
-	t_data = &info->data[t_index];
-
-	if (!(h_data->part1_valid || h_data->part2_valid ||
-	      t_data->part1_valid || t_data->part2_valid)) {
-		hdd_err("medium assess data is not valid.");
-		return;
-	}
-
-	if (h_data->rx_clear_count >= t_data->rx_clear_count) {
-		rx_clear_count_delta = h_data->rx_clear_count -
-						t_data->rx_clear_count;
-	} else {
-		rx_clear_count_delta = U32_MAX - t_data->rx_clear_count;
-		rx_clear_count_delta += h_data->rx_clear_count;
-	}
-
-	if (h_data->tx_frame_count >= t_data->tx_frame_count) {
-		tx_frame_count_delta = h_data->tx_frame_count -
-						t_data->tx_frame_count;
-	} else {
-		tx_frame_count_delta = U32_MAX - t_data->tx_frame_count;
-		tx_frame_count_delta += h_data->tx_frame_count;
-	}
-
-	if (h_data->my_rx_count >= t_data->my_rx_count) {
-		my_rx_count_delta = h_data->my_rx_count - t_data->my_rx_count;
-	} else {
-		my_rx_count_delta = U32_MAX - t_data->my_rx_count;
-		my_rx_count_delta += h_data->my_rx_count;
-	}
-
-	if (h_data->cycle_count >= t_data->cycle_count) {
-		cycle_count_delta = h_data->cycle_count - t_data->cycle_count;
-	} else {
-		cycle_count_delta = U32_MAX - t_data->cycle_count;
-		cycle_count_delta += h_data->cycle_count;
-	}
-
-	if (rx_clear_count_delta > tx_frame_count_delta &&
-	    rx_clear_count_delta - tx_frame_count_delta > my_rx_count_delta) {
-		diff = rx_clear_count_delta - tx_frame_count_delta
-		       - my_rx_count_delta;
-		if (cycle_count_delta)
-			congestion = qdf_do_div(diff * 100, cycle_count_delta);
-
-		if (congestion > 100)
-			congestion = 100;
-	}
-
-	hdd_debug("pdev: %d, rx_c %u, tx %u myrx %u cycle %u congestion: %u",
-		  info->pdev_id, rx_clear_count_delta, tx_frame_count_delta,
-		  my_rx_count_delta, cycle_count_delta, congestion);
-	if (congestion >= info->config.threshold)
-		hdd_congestion_notification_report(info->vdev_id, congestion);
-}
-
-/**
- * hdd_congestion_notification_report_multi() - medium assess report
- * multi interface.
- * @pdev_id: pdev id
- *
- * Return: None
- */
-static void hdd_congestion_notification_report_multi(uint8_t pdev_id)
-{
-	struct hdd_medium_assess_info *info;
-
-	info = &medium_assess_info[pdev_id];
-	info->count++;
-	if (info->count % info->config.interval == 0)
-		hdd_congestion_notification_calculation(info);
-}
-
-/**
- * hdd_medium_assess_expire_handler() - timer callback
- * @arg: argument
- *
- * Return: None
- */
-static void hdd_medium_assess_expire_handler(void *arg)
-{
-	struct wlan_objmgr_vdev *vdev;
-	struct request_info info = {0};
-	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
-	struct wlan_hdd_link_info *link_info;
-	uint8_t vdev_id = INVALID_VDEV_ID, pdev_id;
-	uint8_t index, i;
-
-	if (wlan_hdd_validate_context(hdd_ctx))
-		return;
-
-	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
-		if (medium_assess_info[i].config.interval != 0) {
-			vdev_id = medium_assess_info[i].vdev_id;
-			pdev_id = medium_assess_info[i].pdev_id;
-			hdd_congestion_notification_report_multi(pdev_id);
-
-			/* ensure events are reveived at the 'same' time */
-			index = medium_assess_info[i].index;
-			medium_assess_info[i].data[index].part1_valid = false;
-			medium_assess_info[i].data[index].part2_valid = false;
-		}
-
-	if (vdev_id == INVALID_VDEV_ID)
-		return;
-
-	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
-	if (!link_info) {
-		hdd_err("Failed to find adapter of vdev %d", vdev_id);
-		return;
-	}
-
-	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_CP_STATS_ID);
-	if (!vdev)
-		return;
-
-	info.vdev_id = vdev_id;
-	info.pdev_id = WMI_HOST_PDEV_ID_SOC;
-	info.u.congestion_notif_cb = hdd_congestion_notification_cb;
-	stime = jiffies + msecs_to_jiffies(40);
-	ucfg_mc_cp_stats_send_stats_request(vdev,
-					    TYPE_CONGESTION_STATS,
-					    &info);
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_CP_STATS_ID);
-	qdf_mc_timer_start(&hdd_medium_assess_timer,
-			   MEDIUM_ASSESS_TIMER_INTERVAL);
-}
-
-void hdd_medium_assess_init(void)
+void hdd_medium_assess_ssr_reinit(void)
 {
 	QDF_STATUS status;
 
-	if (!timer_enable) {
-		hdd_debug("medium assess init timer");
+	if (timer_enable && ssr_flag) {
+		hdd_debug("medium assess init timer in ssr");
 		status = qdf_mc_timer_init(&hdd_medium_assess_timer,
 					   QDF_TIMER_TYPE_SW,
 					   hdd_medium_assess_expire_handler,
 					   NULL);
 		if (QDF_IS_STATUS_ERROR(status)) {
-			hdd_debug("medium assess init timer failed");
+			hdd_debug("medium assess init timer failed in ssr");
 			return;
 		}
 
-		if (ssr_flag) {
-			ssr_flag = 0;
-			qdf_mc_timer_start(&hdd_medium_assess_timer,
-					   MEDIUM_ASSESS_TIMER_INTERVAL);
-		}
-	}
-	timer_enable += 1;
-}
-
-void hdd_medium_assess_deinit(void)
-{
-	timer_enable -= 1;
-	if (!timer_enable) {
-		hdd_debug("medium assess deinit timer");
-		if (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) ==
-						     QDF_TIMER_STATE_RUNNING)
-			qdf_mc_timer_stop(&hdd_medium_assess_timer);
-
-		qdf_mc_timer_destroy(&hdd_medium_assess_timer);
+		ssr_flag = false;
+		qdf_mc_timer_start(&hdd_medium_assess_timer,
+				   MEDIUM_ASSESS_TIMER_INTERVAL);
 	}
 }

+ 3 - 11
core/hdd/src/wlan_hdd_medium_assess.h

@@ -104,18 +104,11 @@ int hdd_cfg80211_medium_assess(struct wiphy *wiphy,
 },
 
 /**
- * hdd_medium_assess_init() - medium assess init timer
+ * hdd_medium_assess_ssr_reinit() - medium assess reinit timer in ssr
  *
  * Return: none
  */
-void hdd_medium_assess_init(void);
-
-/**
- * hdd_medium_assess_deinit() - medium assess deinit timer
- *
- * Return: none
- */
-void hdd_medium_assess_deinit(void);
+void hdd_medium_assess_ssr_reinit(void);
 
 /**
  * hdd_medium_assess_stop_timer() - medium assess reset and stop timer
@@ -135,8 +128,7 @@ void hdd_medium_assess_ssr_enable_flag(void);
 #else
 #define FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS
 #define FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS
-static inline void hdd_medium_assess_init(void) {}
-static inline void hdd_medium_assess_deinit(void) {}
+static inline void hdd_medium_assess_ssr_reinit(void) {}
 static inline void hdd_medium_assess_stop_timer(uint8_t pdev_id,
 						struct hdd_context *hdd_ctx) {}
 static inline void hdd_medium_assess_ssr_enable_flag(void) {}

+ 17 - 7
core/hdd/src/wlan_hdd_mlo.c

@@ -177,7 +177,8 @@ void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx)
 	if (!ml_adapter)
 		return;
 
-	status = hdd_derive_link_address_from_mld(&ml_adapter->mld_addr,
+	status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
+						  &ml_adapter->mld_addr,
 						  &link_addr[0],
 						  WLAN_MAX_ML_BSS_LINKS);
 	if (QDF_IS_STATUS_ERROR(status))
@@ -337,15 +338,16 @@ void hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev *vdev)
 	wlan_unregister_t2lm_link_update_notify_handler(vdev->mlo_dev_ctx, 0);
 }
 
-QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
+QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc,
+					    struct qdf_mac_addr *mld_addr,
 					    struct qdf_mac_addr *link_addr_list,
 					    uint8_t max_idx)
 {
-	uint8_t last_byte, temp_byte, idx;
+	uint8_t last_byte, temp_byte, idx, start_idx = 0;
 	struct qdf_mac_addr new_addr;
 	struct qdf_mac_addr *link_addr;
 
-	if (!mld_addr || !link_addr_list || !max_idx ||
+	if (!psoc || !mld_addr || !link_addr_list || !max_idx ||
 	    max_idx > WLAN_MAX_ML_BSS_LINKS || qdf_is_macaddr_zero(mld_addr)) {
 		hdd_err("Invalid values");
 		return QDF_STATUS_E_INVAL;
@@ -360,7 +362,13 @@ QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
 	hdd_debug("MLD addr: " QDF_MAC_ADDR_FMT,
 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
 
-	for (idx = 0; idx < max_idx; idx++) {
+	if (wlan_mlme_get_sta_same_link_mld_addr(psoc)) {
+		qdf_copy_macaddr(link_addr, mld_addr);
+		link_addr++;
+		start_idx++;
+	}
+
+	for (idx = start_idx; idx < max_idx; idx++) {
 		temp_byte = ((last_byte >> 4 & INTF_MACADDR_MASK) + idx) &
 			     INTF_MACADDR_MASK;
 		new_addr.bytes[5] = last_byte + temp_byte;
@@ -471,7 +479,8 @@ int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 		return ret;
 	}
 
-	status = hdd_derive_link_address_from_mld(&mac_addr, &link_addrs[0],
+	status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
+						  &mac_addr, &link_addrs[0],
 						  WLAN_MAX_ML_BSS_LINKS);
 
 	if (QDF_IS_STATUS_ERROR(status))
@@ -535,7 +544,8 @@ int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 		return ret;
 	}
 
-	status = hdd_derive_link_address_from_mld(&mac_addr, &link_addrs[0],
+	status = hdd_derive_link_address_from_mld(hdd_ctx->psoc,
+						  &mac_addr, &link_addrs[0],
 						  WLAN_MAX_ML_BSS_LINKS);
 
 	if (QDF_IS_STATUS_ERROR(status))

+ 53 - 9
core/hdd/src/wlan_hdd_power.c

@@ -2355,6 +2355,7 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
 	}
 
 	ucfg_pmo_notify_system_resume(hdd_ctx->psoc);
+	wlan_hdd_resume_pmo_twt(hdd_ctx);
 
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
 		   TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
@@ -2626,6 +2627,8 @@ static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
 		return -EAGAIN;
 	}
 
+	wlan_hdd_suspend_pmo_twt(hdd_ctx);
+
 	/*
 	 * Suspend IPA early before proceeding to suspend other entities like
 	 * firmware to avoid any race conditions.
@@ -3397,9 +3400,31 @@ int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
 	return errno;
 }
 
+/**
+ * hdd_convert_opm_mode() - convert opm with equivalent wma opm
+ * @opm_mode: Optimized power management mode
+ *
+ * Return: enum wma_sta_ps_scheme_cfg
+ */
+static enum wma_sta_ps_scheme_cfg
+hdd_convert_opm_mode(enum qca_wlan_vendor_opm_mode opm_mode)
+{
+	switch (opm_mode) {
+	case QCA_WLAN_VENDOR_OPM_MODE_DISABLE:
+		return WMA_STA_PS_OPM_CONSERVATIVE;
+	case QCA_WLAN_VENDOR_OPM_MODE_ENABLE:
+		return WMA_STA_PS_OPM_AGGRESSIVE;
+	case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED:
+		return WMA_STA_PS_USER_DEF;
+	default:
+		hdd_err("Invalid opm_mode: %d", opm_mode);
+		return WMA_STA_PS_OPM_CONSERVATIVE;
+	}
+}
+
 int hdd_set_power_config(struct hdd_context *hddctx,
 			 struct hdd_adapter *adapter,
-			 uint8_t power)
+			 enum qca_wlan_vendor_opm_mode *opm_mode)
 {
 	QDF_STATUS status;
 
@@ -3410,29 +3435,48 @@ int hdd_set_power_config(struct hdd_context *hddctx,
 		return -EINVAL;
 	}
 
-	if (power > PMO_PS_ADVANCED_POWER_SAVE_ENABLE ||
-	    power < PMO_PS_ADVANCED_POWER_SAVE_DISABLE) {
-		hdd_err("invalid power value: %d", power);
+	if (*opm_mode > QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED ||
+	    *opm_mode < QCA_WLAN_VENDOR_OPM_MODE_DISABLE) {
+		hdd_err("invalid power value: %d", *opm_mode);
 		return -EINVAL;
 	}
 
 	if (ucfg_pmo_get_max_ps_poll(hddctx->psoc)) {
 		hdd_info("Disable advanced power save since max ps poll is enabled");
-		power = PMO_PS_ADVANCED_POWER_SAVE_DISABLE;
+		*opm_mode = QCA_WLAN_VENDOR_OPM_MODE_DISABLE;
 	}
 
-	status = wma_set_power_config(adapter->deflink->vdev_id, power);
+	status = wma_set_power_config(adapter->deflink->vdev_id,
+				      hdd_convert_opm_mode(*opm_mode));
 	if (status != QDF_STATUS_SUCCESS) {
 		hdd_err("failed to configure power: %d", status);
 		return -EINVAL;
 	}
 
-	/* cache latest userspace power save config to reapply after SSR */
-	ucfg_pmo_set_power_save_mode(hddctx->psoc, power);
-
 	return 0;
 }
 
+int hdd_set_power_config_params(struct hdd_context *hddctx,
+				struct hdd_adapter *adapter,
+				uint16_t ps_ito, uint16_t spec_wake)
+{
+	QDF_STATUS status;
+
+	status = wma_set_power_config_ito(adapter->deflink->vdev_id, ps_ito);
+	if (status != QDF_STATUS_SUCCESS) {
+		hdd_err("failed to configure power ito: %d", status);
+		return -EINVAL;
+	}
+
+	status = wma_set_power_config_spec_wake(adapter->deflink->vdev_id,
+						spec_wake);
+	if (status != QDF_STATUS_SUCCESS) {
+		hdd_err("failed to configure power spec wake: %d", status);
+		return -EINVAL;
+	}
+
+	return 0;
+}
 
 #ifdef WLAN_SUSPEND_RESUME_TEST
 static struct net_device *g_dev;

+ 1 - 9
core/hdd/src/wlan_hdd_pre_cac.c

@@ -232,20 +232,11 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
 		return -EINVAL;
 	}
 
-	pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
-							SAP_PRE_CAC_IFNAME);
-	if (!pre_cac_adapter) {
-		hdd_err("error opening the pre cac adapter");
-		return -EINVAL;
-	}
-
 	if (policy_mgr_get_connection_count(hdd_ctx->psoc) > 1) {
 		hdd_err("pre cac not allowed in concurrency");
 		return -EINVAL;
 	}
 
-	pre_cac_link_info = pre_cac_adapter->deflink;
-
 	ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
 	if (!ap_adapter) {
 		hdd_err("unable to get SAP adapter");
@@ -322,6 +313,7 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
 		goto release_intf_addr_and_return_failure;
 	}
 
+	pre_cac_link_info = pre_cac_adapter->deflink;
 	pre_cac_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(pre_cac_link_info);
 	sap_clear_global_dfs_param(mac_handle, pre_cac_ap_ctx->sap_context);
 

+ 8 - 1
core/hdd/src/wlan_hdd_regulatory.c

@@ -896,6 +896,8 @@ int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code)
 		qdf_mutex_release(&hdd_ctx->regulatory_status_lock);
 	}
 
+	hdd_reg_wait_for_country_change(hdd_ctx);
+
 	return qdf_status_to_os_return(status);
 }
 
@@ -1061,6 +1063,11 @@ void hdd_reg_notifier(struct wiphy *wiphy,
 		return;
 	}
 
+	if (hdd_ctx->is_wiphy_suspended) {
+		hdd_err_rl("system/cfg80211 is already suspend");
+		return;
+	}
+
 	hdd_debug("country: %c%c, initiator %d, dfs_region: %d",
 		  request->alpha2[0],
 		  request->alpha2[1],
@@ -1861,7 +1868,7 @@ static void __hdd_country_change_work_handle(struct hdd_context *hdd_ctx)
 	sme_generic_change_country_code(hdd_ctx->mac_handle,
 					hdd_ctx->reg.alpha2);
 
-	qdf_event_set(&hdd_ctx->regulatory_update_event);
+	qdf_event_set_all(&hdd_ctx->regulatory_update_event);
 	qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock);
 	hdd_ctx->is_regulatory_update_in_progress = false;
 	qdf_mutex_release(&hdd_ctx->regulatory_status_lock);

+ 163 - 91
core/hdd/src/wlan_hdd_stats.c

@@ -525,12 +525,49 @@ wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
 	hdd_debug("mlo per link stats is not supported by FW");
 	return false;
 }
+
+/**
+ * wlan_hdd_get_bss_peer_mld_mac() - get bss peer mld mac address
+ * @link_info: Link info pointer in HDD adapter
+ * @mld_mac: pointer to mld mac address
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
+			      struct qdf_mac_addr *mld_mac)
+{
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info,
+					   WLAN_OSIF_STATS_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wlan_vdev_get_bss_peer_mld_mac(vdev, mld_mac);
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
+	return status;
+}
+
 #else
 static inline bool
 wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
 {
 	return false;
 }
+
+static inline QDF_STATUS
+wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
+			      struct qdf_mac_addr *mld_mac)
+{
+	return QDF_STATUS_E_FAILURE;
+}
 #endif
 
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
@@ -677,7 +714,7 @@ static bool put_wifi_peer_rates(struct wifi_peer_info *stats,
 	return true;
 }
 
-#if defined(WLAN_FEATURE_11BE_MLO)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 /**
  * wlan_hdd_update_mlo_iface_stats_info() - update mlo per link iface stats info
  * @hdd_ctx: Pointer to hdd_context
@@ -1350,7 +1387,7 @@ static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
 	wlan_cfg80211_vendor_cmd_reply(skb);
 }
 
-#if defined(WLAN_FEATURE_11BE_MLO)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 /**
  * hdd_cache_ll_iface_stats() - Caches ll_stats received from fw
  * @hdd_ctx: Pointer to hdd_context
@@ -1384,41 +1421,6 @@ hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
 	link_info->ll_iface_stats = *if_stat;
 }
 
-/**
- * wlan_hdd_get_mld_peer() - get mld_peer mac address
- * @link_info: Link info pointer in HDD adapter
- * @mld_mac: mld mac address of the STA
- * @bssid: bssid of the link
- *
- * Return: QDF_STATUS
- */
-static QDF_STATUS
-wlan_hdd_get_mld_peer(struct wlan_hdd_link_info *link_info,
-		      struct qdf_mac_addr *mld_mac,
-		      struct qdf_mac_addr *bssid)
-{
-	struct wlan_objmgr_vdev *vdev;
-	QDF_STATUS status;
-	struct qdf_mac_addr *netdev_addr;
-
-	vdev = hdd_objmgr_get_vdev_by_user(link_info,
-					   WLAN_OSIF_STATS_ID);
-	if (!vdev)
-		return QDF_STATUS_E_INVAL;
-
-	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
-		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
-		return QDF_STATUS_E_INVAL;
-	}
-
-	netdev_addr = hdd_adapter_get_netdev_mac_addr(link_info->adapter);
-	qdf_copy_macaddr(mld_mac, netdev_addr);
-
-	status = wlan_vdev_get_bss_peer_mld_mac(vdev, bssid);
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
-	return status;
-}
-
 /**
  * wlan_hdd_get_iface_stats() - Get ll_iface stats info from link_info
  * @link_info: Link info pointer of STA adapter
@@ -1656,9 +1658,7 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 	struct nlattr *ml_iface_stats;
 	struct sk_buff *skb;
 	struct wlan_hdd_link_info *link_info;
-
-	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
-		return;
+	struct qdf_mac_addr *netdev_addr;
 
 	if (wlan_hdd_validate_context(hdd_ctx)) {
 		hdd_err("Invalid hdd context");
@@ -1733,11 +1733,13 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 						 update_stats);
 	}
 
-	status = wlan_hdd_get_mld_peer(ml_adapter->deflink,
-				       &cumulative_if_stat.info.macAddr,
-				       &cumulative_if_stat.info.bssid);
+	netdev_addr = hdd_adapter_get_netdev_mac_addr(ml_adapter);
+	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
+
+	status = wlan_hdd_get_bss_peer_mld_mac(ml_adapter->deflink,
+					       &cumulative_if_stat.info.bssid);
 	if (QDF_IS_STATUS_ERROR(status))
-		hdd_err_rl("Update mld_mac failed for mlo iface stats");
+		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
 
 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_peers, skb)) {
 		hdd_err("put_wifi_iface_stats fail");
@@ -1797,6 +1799,7 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 	struct nlattr *ml_iface_stats;
 	struct sk_buff *skb;
 	struct wlan_hdd_link_info *link_info;
+	struct qdf_mac_addr *netdev_addr;
 
 	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
 		return;
@@ -1853,11 +1856,13 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 		i++;
 	}
 
-	status = wlan_hdd_get_mld_peer(adapter->deflink,
-				       &cumulative_if_stat.info.macAddr,
-				       &cumulative_if_stat.info.bssid);
+	netdev_addr = hdd_adapter_get_netdev_mac_addr(adapter);
+	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
+
+	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink,
+					       &cumulative_if_stat.info.bssid);
 	if (QDF_IS_STATUS_ERROR(status))
-		hdd_err_rl("Update mld_mac failed for mlo iface stats");
+		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
 
 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_peers, skb)) {
 		hdd_err("put_wifi_iface_stats fail");
@@ -3132,6 +3137,22 @@ static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
 }
 #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
 
+static void wlan_hdd_send_mlo_ll_stats(struct wlan_hdd_link_info *link_info,
+				       void *mlo_peer_stats)
+{
+	if (!link_info) {
+		hdd_err("Invalid link_info");
+		return;
+	}
+
+	if (!wlan_hdd_is_mlo_connection(link_info))
+		return;
+
+	wlan_hdd_send_mlo_ll_iface_stats(link_info->adapter);
+	wlan_hdd_send_mlo_ll_peer_stats(link_info->adapter->hdd_ctx,
+					(struct wifi_peer_stat *)mlo_peer_stats);
+}
+
 static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
 				      tSirLLStatsGetReq *req)
 {
@@ -3239,13 +3260,11 @@ static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
 	}
 	qdf_list_destroy(&priv->ll_stats_q);
 
-	if (req->reqId != DEBUGFS_LLSTATS_REQID) {
-		wlan_hdd_send_mlo_ll_iface_stats(adapter);
-		wlan_hdd_send_mlo_ll_peer_stats(hdd_ctx,
-					(struct wifi_peer_stat *)mlo_stats);
-	}
+	if (!ret && req->reqId != DEBUGFS_LLSTATS_REQID)
+		wlan_hdd_send_mlo_ll_stats(link_info, mlo_stats);
 
 	qdf_mem_free(mlo_stats);
+
 exit:
 	qdf_atomic_set(&adapter->is_ll_stats_req_pending, 0);
 	wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc, adapter);
@@ -5726,6 +5745,43 @@ static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
 }
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
+static bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
+				enum tx_rate_info rate_flags,
+				uint8_t mcsidx,
+				uint8_t nss,
+				uint8_t rate_info_flag)
+{
+	if (rate_info_flag == RATE_INFO_FLAGS_EHT_MCS) {
+		rate_info->nss = nss;
+		rate_info->mcs = mcsidx;
+		rate_info->flags |= RATE_INFO_FLAGS_EHT_MCS;
+		if (rate_flags & TX_RATE_EHT320)
+			rate_info->bw = RATE_INFO_BW_320;
+		else if (rate_flags & TX_RATE_EHT160)
+			rate_info->bw = RATE_INFO_BW_160;
+		else if (rate_flags & TX_RATE_EHT80)
+			rate_info->bw = RATE_INFO_BW_80;
+		else if (rate_flags & TX_RATE_EHT40)
+			rate_info->bw = RATE_INFO_BW_40;
+		else if (rate_flags & TX_RATE_EHT20)
+			rate_info->bw = RATE_INFO_BW_20;
+
+		return true;
+	}
+
+	return false;
+}
+#else
+static inline bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
+				       enum tx_rate_info rate_flags,
+				       uint8_t mcsidx,
+				       uint8_t nss,
+				       uint8_t rate_info_flag)
+{
+	return false;
+}
+#endif
 /**
  * hdd_fill_bw_mcs() - fill ch width and mcs flags
  * @rate_info: pointer to struct rate_info
@@ -5744,21 +5800,11 @@ static void hdd_fill_bw_mcs(struct rate_info *rate_info,
 			    uint8_t nss,
 			    uint8_t rate_info_flag)
 {
-	if (rate_info_flag == RATE_INFO_FLAGS_EHT_MCS) {
-		rate_info->nss = nss;
-		rate_info->mcs = mcsidx;
-		rate_info->flags |= RATE_INFO_FLAGS_EHT_MCS;
-		if (rate_flags & TX_RATE_EHT320)
-			rate_info->bw = RATE_INFO_BW_320;
-		else if (rate_flags & TX_RATE_EHT160)
-			rate_info->bw = RATE_INFO_BW_160;
-		else if (rate_flags & TX_RATE_EHT80)
-			rate_info->bw = RATE_INFO_BW_80;
-		else if (rate_flags & TX_RATE_EHT40)
-			rate_info->bw = RATE_INFO_BW_40;
-		else if (rate_flags & TX_RATE_EHT20)
-			rate_info->bw = RATE_INFO_BW_20;
-	} else if (rate_info_flag == RATE_INFO_FLAGS_HE_MCS) {
+	if (hdd_fill_eht_bw_mcs(rate_info, rate_flags, mcsidx, nss,
+				rate_info_flag))
+		return;
+
+	if (rate_info_flag == RATE_INFO_FLAGS_HE_MCS) {
 		rate_info->nss = nss;
 		rate_info->mcs = mcsidx;
 		rate_info->flags |= RATE_INFO_FLAGS_HE_MCS;
@@ -5829,6 +5875,30 @@ static void hdd_fill_bw_mcs(struct rate_info *rate_info,
 }
 #endif
 
+#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
+static void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
+					 uint32_t rate_flags, uint8_t mcsidx,
+					 uint8_t nss)
+{
+	if (rate_flags &
+			(TX_RATE_EHT320 |
+			 TX_RATE_EHT160 |
+			 TX_RATE_EHT80 |
+			 TX_RATE_EHT40 |
+			 TX_RATE_EHT20)) {
+		hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
+				RATE_INFO_FLAGS_EHT_MCS);
+	}
+}
+#else
+static inline void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
+						uint32_t rate_flags,
+						uint8_t mcsidx,
+						uint8_t nss)
+{
+}
+#endif
+
 /**
  * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
  * @sinfo: pointer to struct station_info
@@ -5861,15 +5931,9 @@ static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
 		rate_info->legacy = rate;
 	} else {
 		/* must be MCS */
-		if (rate_flags &
-				(TX_RATE_EHT320 |
-				 TX_RATE_EHT160 |
-				 TX_RATE_EHT80 |
-				 TX_RATE_EHT40 |
-				 TX_RATE_EHT20)) {
-			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
-					RATE_INFO_FLAGS_EHT_MCS);
-		}
+		hdd_fill_sinfo_eht_rate_info(rate_info, rate_flags, mcsidx,
+					     nss);
+
 		if (rate_flags &
 				(TX_RATE_HE160 |
 				 TX_RATE_HE80 |
@@ -7374,7 +7438,7 @@ static int wlan_hdd_update_rate_info(struct wlan_hdd_link_info *link_info,
 			  "[RX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]",
 			  sinfo->txrate.mcs, sinfo->txrate.flags,
 			  sinfo->tx_packets, sinfo->txrate.nss,
-			  sinfo->rxrate.bw, sinfo->rxrate.mcs,
+			  sinfo->txrate.bw, sinfo->rxrate.mcs,
 			  sinfo->rxrate.flags, sinfo->rx_packets,
 			  sinfo->rxrate.nss, sinfo->rxrate.bw);
 	}
@@ -7449,12 +7513,14 @@ static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info,
 
 	hdd_wlan_fill_per_chain_rssi_stats(sinfo, link_info);
 
+	hdd_nofl_debug("Sending station stats for link " QDF_MAC_ADDR_FMT,
+		       QDF_MAC_ADDR_REF(mac));
 	hdd_exit();
 
 	return 0;
 }
 
-#if defined(WLAN_FEATURE_11BE_MLO)
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 #define WLAN_INVALID_RSSI_VALUE -128
 /**
  * wlan_hdd_copy_hdd_stats_to_sinfo() - Copy hdd station stats info to sinfo
@@ -7640,7 +7706,8 @@ wlan_hdd_send_mlo_aggregated_stats(struct wlan_hdd_link_info *link_info,
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
 	bool is_mld_req = false;
 	bool per_link_stats_cap = false;
-	struct qdf_mac_addr *netdev_addr;
+	struct qdf_mac_addr peer_mld_mac;
+	QDF_STATUS status;
 
 	if (!link_info) {
 		hdd_err("Invalid link_info");
@@ -7652,13 +7719,18 @@ wlan_hdd_send_mlo_aggregated_stats(struct wlan_hdd_link_info *link_info,
 		return false;
 	}
 
-	netdev_addr = hdd_adapter_get_netdev_mac_addr(link_info->adapter);
-	is_mld_req = qdf_is_macaddr_equal(netdev_addr,
+	status = wlan_hdd_get_bss_peer_mld_mac(link_info, &peer_mld_mac);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err_rl("mlo_vdev_stats: failed to get bss peer mld mac");
+		return false;
+	}
+
+	is_mld_req = qdf_is_macaddr_equal(&peer_mld_mac,
 					  (struct qdf_mac_addr *)mac);
 	per_link_stats_cap = wlan_hdd_is_per_link_stats_supported(hdd_ctx);
 
 	if (is_mld_req && per_link_stats_cap) {
-		hdd_debug("Fetching Aggregated station stats");
+		hdd_debug_rl("Fetching Aggregated station stats");
 		return true;
 	}
 
@@ -7738,7 +7810,8 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
 		}
 
 		if (!wlan_hdd_send_mlo_aggregated_stats(link_info, mac)) {
-			hdd_debug("Sending Assoc Link stats");
+			hdd_nofl_debug("Station stats requested for vdev_[%u]",
+				       link_info->vdev_id);
 			return wlan_hdd_get_sta_stats(link_info,
 						      mac, sinfo);
 		}
@@ -7896,13 +7969,12 @@ static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
 
 		qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE);
 
-		if (!wlan_hdd_send_mlo_aggregated_stats(adapter->deflink,
-							mac)) {
-			hdd_debug("Sending Assoc Link stats");
-			return wlan_hdd_get_sta_stats(adapter->deflink,
-						      mac, sinfo);
-		}
-		errno = wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
+		if (wlan_hdd_is_mlo_connection(adapter->deflink) &&
+		    wlan_hdd_is_per_link_stats_supported(hdd_ctx))
+			return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
+
+		hdd_debug("Sending Assoc Link stats");
+		errno = wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
 	}
 	return errno;
 }

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

@@ -92,6 +92,8 @@
 #include <wlan_hdd_sysfs_runtime_pm.h>
 #include <wlan_hdd_sysfs_log_buffer.h>
 #include <wlan_hdd_sysfs_dfsnol.h>
+#include <wlan_hdd_sysfs_wds_mode.h>
+#include <wlan_hdd_sysfs_roam_trigger_bitmap.h>
 
 #define MAX_PSOC_ID_SIZE 10
 
@@ -821,11 +823,13 @@ hdd_sysfs_create_sta_adapter_root_obj(struct hdd_adapter *adapter)
 	hdd_sysfs_11be_rate_create(adapter);
 	hdd_sysfs_bmiss_create(adapter);
 	hdd_sysfs_dp_tx_delay_stats_create(adapter);
+	hdd_sysfs_direct_link_ut_cmd_create(adapter);
 }
 
 static void
 hdd_sysfs_destroy_sta_adapter_root_obj(struct hdd_adapter *adapter)
 {
+	hdd_sysfs_direct_link_ut_destroy(adapter);
 	hdd_sysfs_dp_tx_delay_stats_destroy(adapter);
 	hdd_sysfs_bmiss_destroy(adapter);
 	hdd_sysfs_11be_rate_destroy(adapter);
@@ -955,12 +959,16 @@ void hdd_create_sysfs_files(struct hdd_context *hdd_ctx)
 		hdd_sysfs_dp_pkt_add_ts_create(driver_kobject);
 		hdd_sysfs_runtime_pm_create(driver_kobject);
 		hdd_sysfs_log_buffer_create(driver_kobject);
+		hdd_sysfs_wds_mode_create(driver_kobject);
+		hdd_sysfs_roam_trigger_bitmap_create(driver_kobject);
 	}
 }
 
 void hdd_destroy_sysfs_files(void)
 {
 	if  (QDF_GLOBAL_MISSION_MODE == hdd_get_conparam()) {
+		hdd_sysfs_roam_trigger_bitmap_destroy(driver_kobject);
+		hdd_sysfs_wds_mode_destroy(driver_kobject);
 		hdd_sysfs_log_buffer_destroy(driver_kobject);
 		hdd_sysfs_runtime_pm_destroy(driver_kobject);
 		hdd_sysfs_dp_pkt_add_ts_destroy(driver_kobject);

+ 26 - 2
core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.c

@@ -22,7 +22,7 @@
 #include <wlan_hdd_sysfs.h>
 #include "wlan_hdd_sysfs_direct_link_ut_cmd.h"
 
-#define MAX_SYSFS_DIRECT_LNK_UT_USER_COMMAND_LENGTH 64
+#define MAX_SYSFS_DIRECT_LNK_UT_USER_COMMAND_LENGTH 512
 
 static ssize_t __hdd_sysfs_direct_link_ut_cmd_store(struct net_device *net_dev,
 						    char const *buf,
@@ -101,7 +101,31 @@ static ssize_t __hdd_sysfs_direct_link_ut_cmd_store(struct net_device *net_dev,
 		return -EINVAL;
 	qdf_mac_parse(token, &cmd_info.dest_mac);
 
-	qdf_copy_macaddr(&cmd_info.src_mac, &adapter->mac_addr);
+	if (cmd_info.cmd == WFDS_START_WHC) {
+		token = strsep(&sptr, " ");
+		if (!token)
+			return -EINVAL;
+		qdf_mac_parse(token, &cmd_info.src_mac);
+
+		token = strsep(&sptr, " ");
+		if (!token)
+			return -EINVAL;
+		qdf_ipv4_parse(token, &cmd_info.dest_ip);
+
+		token = strsep(&sptr, " ");
+		if (!token)
+			return -EINVAL;
+		qdf_ipv4_parse(token, &cmd_info.src_ip);
+
+		token = strsep(&sptr, " ");
+		if (!token)
+			return -EINVAL;
+		if (kstrtou16(token, 0, &cmd_info.dest_port))
+			return -EINVAL;
+	} else if (cmd_info.cmd == WFDS_START_TRAFFIC) {
+		qdf_copy_macaddr(&cmd_info.src_mac, &adapter->mac_addr);
+	}
+
 send_request:
 	status = os_if_qmi_wfds_send_ut_cmd_req_msg(&cmd_info);
 	if (QDF_IS_STATUS_ERROR(status))

+ 148 - 0
core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.c

@@ -0,0 +1,148 @@
+/*
+ * 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 above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <wlan_hdd_includes.h>
+#include "osif_psoc_sync.h"
+#include <wlan_hdd_sysfs.h>
+#include <wlan_hdd_sysfs_roam_trigger_bitmap.h>
+
+static ssize_t __hdd_sysfs_roam_trigger_bitmap_show(struct hdd_context *hdd_ctx,
+						    struct kobj_attribute *attr,
+						    char *buf)
+{
+	int ret = 0;
+
+	if (!hdd_ctx || !hdd_ctx->psoc) {
+		hdd_err_rl("invalid input");
+		return ret;
+	}
+
+	ret = scnprintf(buf, PAGE_SIZE, "0x%x",
+			ucfg_mlme_get_roaming_triggers(hdd_ctx->psoc));
+
+	return ret;
+}
+
+static ssize_t hdd_sysfs_roam_trigger_bitmap_show(struct kobject *kobj,
+						  struct kobj_attribute *attr,
+						  char *buf)
+{
+	struct osif_psoc_sync *psoc_sync;
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	ssize_t errno_size;
+
+	errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
+					     &psoc_sync);
+	if (errno_size)
+		return errno_size;
+
+	errno_size = __hdd_sysfs_roam_trigger_bitmap_show(hdd_ctx, attr, buf);
+
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno_size;
+}
+
+static ssize_t
+__hdd_sysfs_roam_trigger_bitmap_store(struct hdd_context *hdd_ctx,
+				      struct kobj_attribute *attr,
+				      const char *buf,
+				      size_t count)
+{
+	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
+	char *sptr, *token;
+	uint32_t value;
+	int ret = 0;
+
+	if (!hdd_ctx || !hdd_ctx->psoc) {
+		hdd_err_rl("invalid hdd ctx");
+		return ret;
+	}
+
+	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
+					      buf, count);
+
+	if (ret) {
+		hdd_err_rl("invalid input");
+		return ret;
+	}
+
+	sptr = buf_local;
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &value))
+		return -EINVAL;
+
+	hdd_debug("roam_trigger_bitmap: 0x%x", value);
+
+	ucfg_mlme_set_roaming_triggers(hdd_ctx->psoc, value);
+
+	return count;
+}
+
+static ssize_t
+hdd_sysfs_roam_trigger_bitmap_store(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char const *buf, size_t count)
+{
+	struct osif_psoc_sync *psoc_sync;
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	ssize_t errno_size;
+
+	errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
+					     &psoc_sync);
+	if (errno_size)
+		return errno_size;
+
+	errno_size = __hdd_sysfs_roam_trigger_bitmap_store(hdd_ctx, attr,
+							   buf, count);
+
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno_size;
+}
+
+static struct kobj_attribute roam_trigger_bitmap_attribute =
+	__ATTR(roam_trigger_bitmap, 0664, hdd_sysfs_roam_trigger_bitmap_show,
+	       hdd_sysfs_roam_trigger_bitmap_store);
+
+int hdd_sysfs_roam_trigger_bitmap_create(struct kobject *driver_kobject)
+{
+	int error;
+
+	if (!driver_kobject) {
+		hdd_err("could not get driver kobject!");
+		return -EINVAL;
+	}
+
+	error = sysfs_create_file(driver_kobject,
+				  &roam_trigger_bitmap_attribute.attr);
+	if (error)
+		hdd_err("could not create roam_trigger_bitmap sysfs file");
+
+	return error;
+}
+
+void
+hdd_sysfs_roam_trigger_bitmap_destroy(struct kobject *driver_kobject)
+{
+	if (!driver_kobject) {
+		hdd_err("could not get driver kobject!");
+		return;
+	}
+	sysfs_remove_file(driver_kobject, &roam_trigger_bitmap_attribute.attr);
+}

+ 60 - 0
core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.h

@@ -0,0 +1,60 @@
+/*
+ * 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 above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WLAN_HDD_SYSFS_ROAM_TRIGGER_BITMAP_H
+#define _WLAN_HDD_SYSFS_ROAM_TRIGGER_BITMAP_H
+
+#if defined(WLAN_SYSFS) && defined(FEATURE_SYSFS_ROAM_TRIGGER_BITMAP)
+
+/**
+ * hdd_sysfs_roam_trigger_bitmap_create() - API to create roam_trigger_bitmap
+ *                                          sysfs file
+ * @driver_kobject: sysfs driver kobject
+ *
+ * file path: /sys/kernel/kiwi_v2/roam_trigger_bitmap
+ *
+ * usage:
+ *      echo [arg_0] > roam_trigger_bitmap
+ *
+ * Return: 0 on success and errno on failure
+ */
+int hdd_sysfs_roam_trigger_bitmap_create(struct kobject *driver_kobject);
+
+/**
+ * hdd_sysfs_roam_trigger_bitmap_destroy() - destroy hdd roam_trigger_bitmap
+ *                                          sysfs node
+ * @driver_kobject: pointer to driver kobject
+ *
+ * Return: void
+ *
+ */
+void
+hdd_sysfs_roam_trigger_bitmap_destroy(struct kobject *driver_kobject);
+
+#else
+
+static inline int
+hdd_sysfs_roam_trigger_bitmap_create(struct kobject *driver_kobject)
+{
+	return 0;
+}
+
+static inline void
+hdd_sysfs_roam_trigger_bitmap_destroy(struct kobject *driver_kobject)
+{
+}
+#endif
+#endif

+ 147 - 0
core/hdd/src/wlan_hdd_sysfs_wds_mode.c

@@ -0,0 +1,147 @@
+/*
+ * 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 above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <wlan_hdd_includes.h>
+#include "osif_psoc_sync.h"
+#include <wlan_hdd_sysfs.h>
+#include <wlan_hdd_sysfs_wds_mode.h>
+
+static ssize_t __hdd_sysfs_wds_mode_show(struct hdd_context *hdd_ctx,
+					 struct kobj_attribute *attr,
+					 char *buf)
+{
+	int ret = 0;
+
+	if (!hdd_ctx || !hdd_ctx->psoc) {
+		hdd_err_rl("invalid input");
+		return ret;
+	}
+
+	ret = scnprintf(buf, PAGE_SIZE, "%d",
+			ucfg_mlme_get_wds_mode(hdd_ctx->psoc));
+
+	return ret;
+}
+
+static ssize_t hdd_sysfs_wds_mode_show(struct kobject *kobj,
+				       struct kobj_attribute *attr,
+				       char *buf)
+{
+	struct osif_psoc_sync *psoc_sync;
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	ssize_t errno_size;
+
+	errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
+					     &psoc_sync);
+	if (errno_size)
+		return errno_size;
+
+	errno_size = __hdd_sysfs_wds_mode_show(hdd_ctx, attr, buf);
+
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno_size;
+}
+
+static ssize_t
+__hdd_sysfs_wds_mode_store(struct hdd_context *hdd_ctx,
+			   struct kobj_attribute *attr, const char *buf,
+			   size_t count)
+{
+	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
+	char *sptr, *token;
+	uint32_t value;
+	int ret = 0;
+
+	if (!hdd_ctx || !hdd_ctx->psoc) {
+		hdd_err_rl("invalid hdd ctx");
+		return ret;
+	}
+
+	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
+					      buf, count);
+
+	if (ret) {
+		hdd_err_rl("invalid input");
+		return ret;
+	}
+
+	sptr = buf_local;
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &value))
+		return -EINVAL;
+
+	hdd_debug("wds_mode: %d", value);
+
+	ucfg_mlme_set_wds_mode(hdd_ctx->psoc, value);
+
+	return count;
+}
+
+static ssize_t
+hdd_sysfs_wds_mode_store(struct kobject *kobj,
+			 struct kobj_attribute *attr,
+			 char const *buf, size_t count)
+{
+	struct osif_psoc_sync *psoc_sync;
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	ssize_t errno_size;
+
+	errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
+					     &psoc_sync);
+	if (errno_size)
+		return errno_size;
+
+	errno_size = __hdd_sysfs_wds_mode_store(hdd_ctx, attr,
+						buf, count);
+
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno_size;
+}
+
+static struct kobj_attribute wds_mode_attribute =
+	__ATTR(wds_mode, 0664, hdd_sysfs_wds_mode_show,
+	       hdd_sysfs_wds_mode_store);
+
+int hdd_sysfs_wds_mode_create(struct kobject *driver_kobject)
+{
+	int error;
+
+	if (!driver_kobject) {
+		hdd_err("could not get driver kobject!");
+		return -EINVAL;
+	}
+
+	error = sysfs_create_file(driver_kobject,
+				  &wds_mode_attribute.attr);
+	if (error)
+		hdd_err("could not create wds_mode sysfs file");
+
+	return error;
+}
+
+void
+hdd_sysfs_wds_mode_destroy(struct kobject *driver_kobject)
+{
+	if (!driver_kobject) {
+		hdd_err("could not get driver kobject!");
+		return;
+	}
+	sysfs_remove_file(driver_kobject, &wds_mode_attribute.attr);
+}

+ 58 - 0
core/hdd/src/wlan_hdd_sysfs_wds_mode.h

@@ -0,0 +1,58 @@
+/*
+ * 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 above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WLAN_HDD_SYSFS_WDS_MODE_H
+#define _WLAN_HDD_SYSFS_WDS_MODE_H
+
+#if defined(WLAN_SYSFS) && defined(FEATURE_SYSFS_WDS_MODE)
+
+/**
+ * hdd_sysfs_wds_mode_create() - API to create wds mode sysfs file
+ * @driver_kobject: sysfs driver kobject
+ *
+ * file path: /sys/kernel/kiwi_v2/wds_mode
+ *
+ * usage:
+ *      echo [arg_0] > wds_mode
+ *
+ * Return: 0 on success and errno on failure
+ */
+int hdd_sysfs_wds_mode_create(struct kobject *driver_kobject);
+
+/**
+ * hdd_sysfs_wds_mode_destroy() - destroy hdd wds mode sysfs node
+ * @driver_kobject: pointer to driver kobject
+ *
+ * Return: void
+ *
+ */
+void
+hdd_sysfs_wds_mode_destroy(struct kobject *driver_kobject);
+
+#else
+
+static inline int
+hdd_sysfs_wds_mode_create(struct kobject *driver_kobject)
+{
+	return 0;
+}
+
+static inline void
+hdd_sysfs_wds_mode_destroy(struct kobject *driver_kobject)
+{
+}
+#endif
+#endif

+ 22 - 1
core/hdd/src/wlan_hdd_twt.c

@@ -82,7 +82,8 @@ QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx)
 
 void wlan_twt_concurrency_update(struct hdd_context *hdd_ctx)
 {
-	qdf_sched_work(0, &hdd_ctx->twt_en_dis_work);
+	if (wlan_hdd_is_twt_pmo_allowed(hdd_ctx))
+		qdf_sched_work(0, &hdd_ctx->twt_en_dis_work);
 }
 
 void hdd_twt_update_work_handler(void *data)
@@ -5057,3 +5058,23 @@ int wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
 	return errno;
 }
 
+void wlan_hdd_resume_pmo_twt(struct hdd_context *hdd_ctx)
+{
+	wlan_twt_concurrency_update(hdd_ctx);
+}
+
+void wlan_hdd_suspend_pmo_twt(struct hdd_context *hdd_ctx)
+{
+	qdf_flush_work(&hdd_ctx->twt_en_dis_work);
+}
+
+bool wlan_hdd_is_twt_pmo_allowed(struct hdd_context *hdd_ctx)
+{
+	bool twt_pmo_allowed = false;
+
+	twt_pmo_allowed = ucfg_twt_get_pmo_allowed(hdd_ctx->psoc);
+	hdd_debug("twt_disabled_allowed %d ", twt_pmo_allowed);
+
+	return twt_pmo_allowed;
+}
+

+ 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            "X"
-#define QWLAN_VERSION_BUILD            75
+#define QWLAN_VERSION_EXTRA            ""
+#define QWLAN_VERSION_BUILD            77
 
-#define QWLAN_VERSIONSTR               "5.2.1.75X"
+#define QWLAN_VERSIONSTR               "5.2.1.77"
 
 #endif /* QWLAN_VERSION_H */

+ 0 - 5
core/mac/inc/sir_api.h

@@ -54,11 +54,6 @@ struct mac_context;
 #include "wlan_mlo_mgr_public_structs.h"
 #endif
 
-/* The ini gDataInactivityTimeout is deprecated. So, definng a new macro
- * PS_DATA_INACTIVITY_TIMEOUT with the ini's default value.
- */
-#define PS_DATA_INACTIVITY_TIMEOUT (200)
-
 #define OFFSET_OF(structType, fldName)   (&((structType *)0)->fldName)
 #define WLAN_DOT11_BASIC_RATE_MASK (0x80)
 #define BITS_ON(_Field, _Bitmask)  ((_Field) |=  (_Bitmask))

+ 34 - 6
core/mac/src/pe/lim/lim_api.c

@@ -866,7 +866,7 @@ QDF_STATUS pe_open(struct mac_context *mac, struct cds_config_info *cds_cfg)
 					lim_update_tx_pwr_on_ctry_change_cb);
 
 	wlan_reg_register_is_chan_connected_callback(mac->psoc,
-					lim_is_chan_connected_for_mode);
+					lim_get_connected_chan_for_mode);
 
 	if (mac->mlme_cfg->edca_params.enable_edca_params)
 		lim_register_policy_mgr_callback(mac->psoc);
@@ -916,7 +916,7 @@ QDF_STATUS pe_close(struct mac_context *mac)
 					lim_update_tx_pwr_on_ctry_change_cb);
 
 	wlan_reg_unregister_is_chan_connected_callback(mac->psoc,
-					lim_is_chan_connected_for_mode);
+					lim_get_connected_chan_for_mode);
 
 	if (mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) {
 		qdf_mem_free(mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq);
@@ -2654,7 +2654,7 @@ lim_mlo_roam_copy_partner_info_to_session(struct pe_session *session,
 					  struct roam_offload_synch_ind *sync_ind)
 {
 	mlo_roam_copy_partner_info(&session->ml_partner_info,
-				   sync_ind, sync_ind->roamed_vdev_id);
+				   sync_ind, sync_ind->roamed_vdev_id, false);
 }
 
 static QDF_STATUS
@@ -2749,17 +2749,37 @@ void lim_handle_sr_cap(struct wlan_objmgr_vdev *vdev,
 	uint8_t non_srg_pd_offset = 0;
 	uint8_t srg_max_pd_offset = 0;
 	uint8_t srg_min_pd_offset = 0;
-	uint8_t sr_ctrl;
+	uint8_t sr_ctrl, sr_enable_modes;
 	bool is_pd_threshold_present = false;
 	struct wlan_objmgr_pdev *pdev;
 	enum sr_status_of_roamed_ap sr_status;
 	enum sr_osif_operation sr_op;
+	enum QDF_OPMODE opmode;
+	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
 
+	if (!mac) {
+		pe_err("mac ctx is null");
+		return;
+	}
 	pdev = wlan_vdev_get_pdev(vdev);
 	if (!pdev) {
 		pe_err("invalid pdev");
 		return;
 	}
+
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
+	/* If SR is disabled in INI for the session-operating mode
+	 * Then return.
+	 */
+	wlan_mlme_get_sr_enable_modes(mac->psoc, &sr_enable_modes);
+	if (!(sr_enable_modes & (1 << opmode))) {
+		pe_debug("SR is disabled in INI for mode: %d", opmode);
+		return;
+	}
+	if (!wlan_vdev_mlme_get_he_spr_enabled(vdev)) {
+		pe_debug("SR is not enabled");
+		return;
+	}
 	non_srg_pd_offset = wlan_vdev_mlme_get_non_srg_pd_offset(vdev);
 	wlan_vdev_mlme_get_srg_pd_offset(vdev, &srg_max_pd_offset,
 					 &srg_min_pd_offset);
@@ -3092,9 +3112,17 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 
 	/* Cleanup the old session */
 	session_ptr->limSmeState = eLIM_SME_IDLE_STATE;
+
+	/*
+	 * Delete the ml_peer only if DUT is roamed to a non-11BE candidate.
+	 * ml_peer is already cleaned up in wma_delete_all_peers() at the
+	 * beginning of roam_sync handling for 11BE candidates.
+	 */
 	if (sta_ds) {
-		lim_mlo_notify_peer_disconn(session_ptr, sta_ds);
-		lim_mlo_roam_delete_link_peer(session_ptr, sta_ds);
+		if (!wlan_vdev_mlme_is_mlo_vdev(session_ptr->vdev)) {
+			lim_mlo_notify_peer_disconn(session_ptr, sta_ds);
+			lim_mlo_roam_delete_link_peer(session_ptr, sta_ds);
+		}
 		lim_cleanup_rx_path(mac_ctx, sta_ds, session_ptr, false);
 		lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, aid,
 					  session_ptr);

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

@@ -1391,7 +1391,13 @@ bool lim_is_emlsr_band_supported(struct pe_session *session)
 	uint32_t freq;
 	struct mlo_partner_info *partner_info;
 
-	partner_info = &session->lim_join_req->partner_info;
+	if (!session->lim_join_req) {
+		/* Initial connection */
+		partner_info = &session->ml_partner_info;
+	} else {
+		/* Roaming */
+		partner_info = &session->lim_join_req->partner_info;
+	}
 
 	if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) {
 		pe_debug("Pri link freq: %d, EMLSR mode not allowed",

+ 0 - 1
core/mac/src/pe/lim/lim_mlo.h

@@ -399,7 +399,6 @@ QDF_STATUS lim_get_bpcc_from_mlo_ie(tSchBeaconStruct *bcn,
  * Return: bool
  */
 bool lim_check_cu_happens(struct wlan_objmgr_vdev *vdev, uint8_t new_bpcc);
-
 #else
 static inline void lim_mlo_roam_peer_disconn_del(struct wlan_objmgr_vdev *vdev)
 {

+ 4 - 3
core/mac/src/pe/lim/lim_process_action_frame.c

@@ -2168,7 +2168,8 @@ void lim_process_action_frame(struct mac_context *mac_ctx,
 			if (wlan_t2lm_deliver_event(
 				session->vdev, peer,
 				WLAN_T2LM_EV_ACTION_FRAME_RX_REQ,
-				(void *)body_ptr, &token) == QDF_STATUS_SUCCESS)
+				(void *)body_ptr, frame_len,
+				&token) == QDF_STATUS_SUCCESS)
 				status_code = WLAN_T2LM_RESP_TYPE_SUCCESS;
 			else
 				status_code =
@@ -2187,13 +2188,13 @@ void lim_process_action_frame(struct mac_context *mac_ctx,
 			wlan_t2lm_deliver_event(
 					session->vdev, peer,
 					WLAN_T2LM_EV_ACTION_FRAME_RX_RESP,
-					(void *)body_ptr, &token);
+					(void *)body_ptr, frame_len, &token);
 			break;
 		case EHT_T2LM_TEARDOWN:
 			wlan_t2lm_deliver_event(
 					session->vdev, peer,
 					WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN,
-					(void *)body_ptr, NULL);
+					(void *)body_ptr, frame_len, NULL);
 			break;
 		case EHT_EPCS_REQUEST:
 			wlan_epcs_deliver_event(

+ 63 - 0
core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c

@@ -994,6 +994,62 @@ lim_process_assoc_rsp_t2lm(struct pe_session *session,
 }
 #endif
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * lim_cache_emlsr_params() - cache the EMLSR parameters in ML STA context
+ * @session_entry: session entry
+ * @assoc_rsp: pointer to parsed associate response
+ *
+ * Return: None
+ */
+static void lim_cache_emlsr_params(struct pe_session *session_entry,
+				   tpSirAssocRsp assoc_rsp)
+{
+	struct wlan_mlo_sta *sta_ctx;
+	struct wlan_objmgr_vdev *vdev = session_entry->vdev;
+	struct emlsr_capability *ml_emlcap;
+
+	wlan_objmgr_vdev_get_ref(vdev, WLAN_MLME_SB_ID);
+	if (!vdev) {
+		pe_err("vdev is null");
+		return;
+	}
+
+	if (!vdev->mlo_dev_ctx) {
+		pe_err("mlo dev ctx is null");
+		goto end;
+	}
+
+	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		pe_err("sta ctx is null");
+		goto end;
+	}
+
+	ml_emlcap = &sta_ctx->emlsr_cap;
+
+	if (wlan_vdev_mlme_cap_get(vdev,
+				   WLAN_VDEV_C_EMLSR_CAP)) {
+		ml_emlcap->emlsr_supp = true;
+		ml_emlcap->trans_timeout =
+		assoc_rsp->mlo_ie.mlo_ie.eml_capabilities_info.transition_timeout;
+	} else {
+		ml_emlcap->emlsr_supp = false;
+		ml_emlcap->trans_timeout = 0;
+	}
+
+	pe_debug("EML caps support%d timeout%d", ml_emlcap->emlsr_supp,
+		 ml_emlcap->trans_timeout);
+end:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
+}
+#else
+static inline void lim_cache_emlsr_params(struct pe_session *session_entry,
+					  tpSirAssocRsp assoc_rsp)
+{
+}
+#endif
+
 /**
  * lim_process_assoc_rsp_frame() - Processes assoc response
  * @mac_ctx: Pointer to Global MAC structure
@@ -1445,6 +1501,13 @@ lim_process_assoc_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
 				lim_add_ft_sta_self(mac_ctx,
 					(assoc_rsp->aid & 0x3FFF),
 					session_entry);
+			} else {
+				lim_set_emlsr_caps(mac_ctx, session_entry);
+				lim_objmgr_update_emlsr_caps(mac_ctx->psoc,
+							session_entry->vdev_id,
+							assoc_rsp);
+				lim_cache_emlsr_params(session_entry,
+						       assoc_rsp);
 			}
 			qdf_mem_free(beacon);
 			return;

+ 22 - 0
core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c

@@ -726,6 +726,22 @@ lim_fill_sme_assoc_ind_mlo_mld_addr_copy(struct assoc_ind *sme_assoc_ind,
 	qdf_mem_copy(sme_assoc_ind->peer_mld_addr, assoc_ind->peer_mld_addr,
 		     num_bytes);
 }
+
+/**
+ * lim_update_connected_links() - Update connected mlo links bmap
+ * @session: Pointer to pe session
+ *
+ * Update connected mlo links bmap for all vdev taking
+ * part in association
+ *
+ * Return: None
+ */
+static void lim_update_connected_links(struct pe_session *session)
+{
+	mlo_update_connected_links(session->vdev, 1);
+	mlo_update_connected_links_bmap(session->vdev->mlo_dev_ctx,
+					session->ml_partner_info);
+}
 #else /* WLAN_FEATURE_11BE_MLO */
 static inline void
 lim_fill_sme_assoc_ind_mlo_mld_addr_copy(struct assoc_ind *sme_assoc_ind,
@@ -733,6 +749,10 @@ lim_fill_sme_assoc_ind_mlo_mld_addr_copy(struct assoc_ind *sme_assoc_ind,
 					 uint32_t num_bytes)
 {
 }
+
+static void lim_update_connected_links(struct pe_session *session)
+{
+}
 #endif /* WLAN_FEATURE_11BE_MLO */
 
 void
@@ -1395,6 +1415,8 @@ void lim_handle_sme_join_result(struct mac_context *mac_ctx,
 	}
 
 	if (result_code == eSIR_SME_SUCCESS) {
+		if (wlan_vdev_mlme_is_mlo_vdev(session->vdev))
+			lim_update_connected_links(session);
 		wlan_vdev_mlme_sm_deliver_evt(session->vdev,
 					      WLAN_VDEV_SM_EV_START_SUCCESS,
 					      0, NULL);

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

@@ -337,7 +337,7 @@ lim_process_probe_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_Packet_info
 		}
 		session_entry->bcnLen =
 			WMA_GET_RX_MPDU_LEN(rx_Packet_info);
-			session_entry->beacon =
+		session_entry->beacon =
 			qdf_mem_malloc(session_entry->bcnLen);
 		if (!session_entry->beacon) {
 			pe_err("No Memory to store beacon");

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

@@ -1802,11 +1802,6 @@ lim_update_eht_caps_mcs(struct mac_context *mac, struct pe_session *session)
 		eht_config->bw_320_tx_max_nss_for_mcs_12_and_13 = tx_nss;
 	}
 }
-#else
-void
-lim_update_eht_caps_mcs(struct mac_context *mac, struct pe_session *session)
-{
-}
 #endif
 
 static void lim_check_oui_and_update_session(struct mac_context *mac_ctx,
@@ -3128,6 +3123,11 @@ static void lim_reset_self_ocv_caps(struct pe_session *session)
 
 	pe_debug("self RSN cap: %d", self_rsn_cap);
 	self_rsn_cap &= ~WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED;
+
+	/* Update the new rsn caps */
+	wlan_crypto_set_vdev_param(session->vdev, WLAN_CRYPTO_PARAM_RSN_CAP,
+				   self_rsn_cap);
+
 }
 
 QDF_STATUS
@@ -4388,8 +4388,7 @@ static void lim_fill_ml_info(struct cm_vdev_join_req *req,
 	pe_join_req->assoc_link_id = req->assoc_link_id;
 }
 
-static void lim_set_emlsr_caps(struct mac_context *mac_ctx,
-			       struct pe_session *session)
+void lim_set_emlsr_caps(struct mac_context *mac_ctx, struct pe_session *session)
 {
 	bool emlsr_cap, emlsr_allowed, emlsr_band_check, emlsr_enabled = false;
 
@@ -4423,11 +4422,6 @@ static void lim_fill_ml_info(struct cm_vdev_join_req *req,
 			     struct join_req *pe_join_req)
 {
 }
-
-static void lim_set_emlsr_caps(struct mac_context *mac_ctx,
-			       struct pe_session *session)
-{
-}
 #endif
 
 static QDF_STATUS

+ 5 - 0
core/mac/src/pe/lim/lim_prop_exts_utils.c

@@ -415,6 +415,11 @@ void lim_update_eht_bw_cap_mcs(struct pe_session *session,
 			pe_debug("Session 6G 320M unsupported");
 			session->eht_config.support_320mhz_6ghz = 0;
 		}
+		if (!beacon->eht_cap.support_320mhz_6ghz ||
+		    !beacon->eht_cap.su_beamformer) {
+			pe_debug("Session 320 MHz Sounding Dimensions unsupported");
+			session->eht_config.num_sounding_dim_320mhz = 0;
+		}
 	}
 }
 #else

+ 31 - 6
core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

@@ -1767,12 +1767,14 @@ static QDF_STATUS lim_process_csa_wbw_ie(struct mac_context *mac_ctx,
 static bool lim_is_csa_channel_allowed(struct mac_context *mac_ctx,
 				       struct pe_session *session_entry,
 				       qdf_freq_t ch_freq1,
-				       uint32_t ch_freq2,
-				       enum phy_ch_width new_ch_width)
+				       struct csa_offload_params *csa_params)
 {
 	bool is_allowed = true;
 	u32 cnx_count = 0;
 	enum QDF_OPMODE mode;
+	qdf_freq_t csa_freq = csa_params->csa_chan_freq, sec_ch_2g_freq = 0;
+	enum phy_ch_width new_ch_width = csa_params->new_ch_width;
+	enum channel_state chan_state;
 
 	if (!session_entry->vdev ||
 	    wlan_cm_is_vdev_disconnecting(session_entry->vdev) ||
@@ -1782,15 +1784,39 @@ static bool lim_is_csa_channel_allowed(struct mac_context *mac_ctx,
 		return false;
 	}
 
+	if (WLAN_REG_IS_24GHZ_CH_FREQ(csa_freq) &&
+	    wlan_reg_get_bw_value(new_ch_width) > 20) {
+		if (csa_params->sec_chan_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
+			sec_ch_2g_freq = csa_freq + HT40_SEC_OFFSET;
+		else if (csa_params->sec_chan_offset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
+			sec_ch_2g_freq = csa_freq - HT40_SEC_OFFSET;
+	}
+
+	chan_state = wlan_reg_get_bonded_channel_state_for_pwrmode(
+						mac_ctx->pdev,
+						csa_freq, new_ch_width,
+						sec_ch_2g_freq,
+						REG_CURRENT_PWR_MODE);
+	if (chan_state == CHANNEL_STATE_INVALID ||
+	    chan_state == CHANNEL_STATE_DISABLE) {
+		pe_err("Invalid csa_freq:%d for provided ch_width:%d. Disconnect",
+		       csa_freq, new_ch_width);
+		lim_tear_down_link_with_ap(mac_ctx,
+					   session_entry->peSessionId,
+					   REASON_CHANNEL_SWITCH_FAILED,
+					   eLIM_HOST_DISASSOC);
+		return false;
+	}
+
 	mode = wlan_vdev_mlme_get_opmode(session_entry->vdev);
 	cnx_count = policy_mgr_get_connection_count(mac_ctx->psoc);
 	if ((cnx_count > 1) && !policy_mgr_is_hw_dbs_capable(mac_ctx->psoc) &&
 	    !policy_mgr_is_interband_mcc_supported(mac_ctx->psoc)) {
-		is_allowed = wlan_reg_is_same_band_freqs(ch_freq1, ch_freq2);
+		is_allowed = wlan_reg_is_same_band_freqs(ch_freq1, csa_freq);
 	} else if (cnx_count > 2) {
 		is_allowed =
 		policy_mgr_allow_concurrency_csa(
-			mac_ctx->psoc, ch_freq2,
+			mac_ctx->psoc, csa_freq,
 			policy_mgr_qdf_opmode_to_pm_con_mode(mac_ctx->psoc,
 							     mode,
 							     session_entry->vdev_id),
@@ -1938,8 +1964,7 @@ void lim_handle_sta_csa_param(struct mac_context *mac_ctx,
 
 	if (!lim_is_csa_channel_allowed(mac_ctx, session_entry,
 					session_entry->curr_op_freq,
-					csa_params->csa_chan_freq,
-					csa_params->new_ch_width)) {
+					csa_params)) {
 		pe_debug("Channel switch is not allowed");
 		goto err;
 	}

+ 41 - 33
core/mac/src/pe/lim/lim_utils.c

@@ -9357,49 +9357,54 @@ void lim_intersect_ap_emlsr_caps(struct mac_context *mac_ctx,
 				 struct bss_params *add_bss,
 				 tpSirAssocRsp assoc_rsp)
 {
-	struct wlan_mlo_peer_context *mlo_peer_ctx;
-	struct wlan_objmgr_peer *peer;
+	struct wlan_mlo_sta *sta_ctx;
+	struct wlan_objmgr_vdev *vdev = session->vdev;
+	struct emlsr_capability *ml_emlcap;
 
-	peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, add_bss->bssId,
-					   WLAN_LEGACY_MAC_ID);
-	if (!peer) {
-		pe_err("peer is null");
+	wlan_objmgr_vdev_get_ref(vdev, WLAN_MLME_NB_ID);
+	if (!vdev) {
+		pe_err("vdev is null");
 		return;
 	}
 
-	mlo_peer_ctx = peer->mlo_peer_ctx;
-	if (!mlo_peer_ctx) {
-		pe_err("mlo peer ctx is null");
-		wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
-		return;
+	if (!vdev->mlo_dev_ctx) {
+		pe_err("mlo dev ctx is null");
+		goto end;
 	}
 
-	if (!wlan_vdev_mlme_cap_get(session->vdev, WLAN_VDEV_C_EMLSR_CAP)) {
+	sta_ctx = vdev->mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		pe_err("sta ctx is null");
+		goto end;
+	}
+
+	ml_emlcap = &sta_ctx->emlsr_cap;
+
+	if (!wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_EMLSR_CAP)) {
 		add_bss->staContext.emlsr_support = false;
-		wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
-		return;
+		goto end;
 	}
 
 	if (wlan_vdev_mlme_is_mlo_link_vdev(session->vdev)) {
-		add_bss->staContext.emlsr_support =
-				mlo_peer_ctx->mlpeer_emlcap.emlsr_supp;
+		add_bss->staContext.emlsr_support = ml_emlcap->emlsr_supp;
 		add_bss->staContext.emlsr_trans_timeout =
-				mlo_peer_ctx->mlpeer_emlcap.trans_timeout;
+						ml_emlcap->trans_timeout;
 	} else {
 		add_bss->staContext.emlsr_support = true;
 		add_bss->staContext.emlsr_trans_timeout =
-			assoc_rsp->mlo_ie.mlo_ie.eml_capabilities_info.transition_timeout;
+		assoc_rsp->mlo_ie.mlo_ie.eml_capabilities_info.transition_timeout;
 
-		mlo_peer_ctx->mlpeer_emlcap.emlsr_supp =
-				add_bss->staContext.emlsr_support;
-		mlo_peer_ctx->mlpeer_emlcap.trans_timeout =
-				add_bss->staContext.emlsr_trans_timeout;
+		ml_emlcap->emlsr_supp = add_bss->staContext.emlsr_support;
+		ml_emlcap->trans_timeout =
+					add_bss->staContext.emlsr_trans_timeout;
 	}
 
-	wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
+end:
 	pe_debug("emlsr support: %d, transition timeout:%d",
 		 add_bss->staContext.emlsr_support,
 		 add_bss->staContext.emlsr_trans_timeout);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID);
 }
 
 #define MAX_MSD_OFDM_ED_THRESHOLD 10
@@ -11163,10 +11168,8 @@ bool lim_update_channel_width(struct mac_context *mac_ctx,
 	 * Do not update the channel bonding mode if channel bonding
 	 * mode is disabled in INI.
 	 */
-	if (cb_mode == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) {
-		pe_debug("channel bonding disabled");
+	if (cb_mode == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE)
 		return false;
-	}
 
 	if (sta_ptr->htSupportedChannelWidthSet) {
 		if (sta_ptr->vhtSupportedChannelWidthSet >
@@ -11533,9 +11536,11 @@ lim_update_tx_pwr_on_ctry_change_cb(uint8_t vdev_id)
 	lim_set_tpc_power(mac_ctx, session);
 }
 
-bool lim_is_chan_connected_for_mode(struct wlan_objmgr_psoc *psoc,
-				    enum QDF_OPMODE device_mode,
-				    qdf_freq_t chan_freq)
+struct wlan_channel *
+lim_get_connected_chan_for_mode(struct wlan_objmgr_psoc *psoc,
+				enum QDF_OPMODE device_mode,
+				qdf_freq_t start_freq,
+				qdf_freq_t end_freq)
 {
 	struct wlan_channel *des_chan;
 	struct wlan_objmgr_vdev *vdev;
@@ -11551,23 +11556,26 @@ bool lim_is_chan_connected_for_mode(struct wlan_objmgr_psoc *psoc,
 		if (vdev->vdev_mlme.vdev_opmode != device_mode)
 			goto next;
 
-		if (!wlan_cm_is_vdev_connected(vdev))
+		if ((device_mode == QDF_STA_MODE ||
+		     device_mode == QDF_P2P_CLIENT_MODE) &&
+		     !wlan_cm_is_vdev_connected(vdev))
 			goto next;
 
 		des_chan = vdev->vdev_mlme.des_chan;
 		if (!des_chan)
 			goto next;
 
-		if (des_chan->ch_freq != chan_freq)
+		if (des_chan->ch_freq < start_freq ||
+		    des_chan->ch_freq > end_freq)
 			goto next;
 
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
-		return true;
+		return des_chan;
 next:
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
 	}
 
-	return false;
+	return NULL;
 }
 
 enum phy_ch_width

+ 41 - 19
core/mac/src/pe/lim/lim_utils.h

@@ -284,6 +284,17 @@ QDF_STATUS lim_send_mlo_caps_ie(struct mac_context *mac_ctx,
  */
 void lim_strip_mlo_ie(struct mac_context *mac_ctx,
 		      uint8_t *add_ie, uint16_t *add_ielen);
+
+/**
+ * lim_set_emlsr_caps() - This API will set EMLSR caps in vdev obj if ELMSR is
+ * supported.
+ * @mac: mac context
+ * @pe_session: session entry
+ *
+ * Return: Void
+ */
+void lim_set_emlsr_caps(struct mac_context *mac_ctx,
+			struct pe_session *session);
 #else
 static inline uint16_t lim_assign_mlo_conn_idx(struct mac_context *mac,
 					       struct pe_session *pe_session,
@@ -324,6 +335,11 @@ QDF_STATUS lim_send_mlo_caps_ie(struct mac_context *mac_ctx,
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
+
+static inline void lim_set_emlsr_caps(struct mac_context *mac_ctx,
+				      struct pe_session *session)
+{
+}
 #endif
 
 void lim_enable_overlap11g_protection(struct mac_context *mac,
@@ -2112,6 +2128,17 @@ void lim_update_stads_eht_bw_320mhz(struct pe_session *session,
  * Return: bool
  */
 bool lim_is_session_chwidth_320mhz(struct pe_session *session);
+
+/**
+ * lim_update_eht_caps_mcs() - update eht caps
+ *
+ * @mac: Pointer to Global mac structure
+ * @session: Session pointer of the interface
+ *
+ * Return: None
+ */
+void
+lim_update_eht_caps_mcs(struct mac_context *mac, struct pe_session *session);
 #else
 static inline
 void lim_update_tdls_sta_eht_capable(struct mac_context *mac,
@@ -2297,6 +2324,11 @@ lim_is_session_chwidth_320mhz(struct pe_session *session)
 {
 	return false;
 }
+
+static inline void
+lim_update_eht_caps_mcs(struct mac_context *mac, struct pe_session *session)
+{
+}
 #endif /* WLAN_FEATURE_11BE */
 
 #ifdef WLAN_FEATURE_11BE_MLO
@@ -3273,18 +3305,20 @@ void
 lim_update_tx_pwr_on_ctry_change_cb(uint8_t vdev_id);
 
 /*
- * lim_is_chan_connected_for_mode() - Check if frequency is connected
- *                                    for given opmode.
+ * lim_get_connected_chan_for_mode() - Get connected channel for given opmode
+ *                                     in given frequency range.
+ *
  * @psoc: Pointer to psoc object
  * @opmode: Vdev opmode
  * @freq: Frequency
  *
- * Return: Return true if frequency is connected for given opmode.
+ * Return: Return connected channel in given frequcy range for given opmode.
  */
-bool
-lim_is_chan_connected_for_mode(struct wlan_objmgr_psoc *psoc,
-			       enum QDF_OPMODE opmode,
-			       qdf_freq_t freq);
+struct wlan_channel *
+lim_get_connected_chan_for_mode(struct wlan_objmgr_psoc *psoc,
+				enum QDF_OPMODE opmode,
+				qdf_freq_t start_freq,
+				qdf_freq_t end_freq);
 
 /**
  * lim_convert_vht_chwidth_to_phy_chwidth() - Convert VHT operation
@@ -3297,16 +3331,4 @@ lim_is_chan_connected_for_mode(struct wlan_objmgr_psoc *psoc,
  */
 enum phy_ch_width
 lim_convert_vht_chwidth_to_phy_chwidth(uint8_t ch_width, bool is_40);
-
-/**
- * lim_update_eht_caps_mcs() - update eht caps
- *
- * @mac: Pointer to Global mac structure
- * @session: Session pointer of the interface
- *
- * Return: None
- */
-void lim_update_eht_caps_mcs(struct mac_context *mac,
-			     struct pe_session *session);
-
 #endif /* __LIM_UTILS_H */

Vissa filer visades inte eftersom för många filer har ändrats