Преглед изворни кода

Merge f0b0a1ae9c17244937df01a2d13b80ba5100087f on remote branch

Change-Id: I2dbc8a0ca18d714fbc18ee65a2c9a83fe0ecca43
Linux Build Service Account пре 1 година
родитељ
комит
19c6321e8d
100 измењених фајлова са 5676 додато и 1334 уклоњено
  1. 3 1
      Kbuild
  2. 5 4
      Kconfig
  3. 3 0
      components/action_oui/core/src/wlan_action_oui_main.c
  4. 30 0
      components/action_oui/dispatcher/inc/wlan_action_oui_cfg.h
  5. 3 0
      components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h
  6. 16 4
      components/cmn_services/interface_mgr/src/wlan_if_mgr_sta.c
  7. 285 22
      components/cmn_services/logging/inc/wlan_connectivity_logging.h
  8. 90 0
      components/cmn_services/logging/src/wlan_connectivity_logging.c
  9. 15 13
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
  10. 9 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h
  11. 24 12
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c
  12. 70 56
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c
  13. 38 82
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  14. 0 2
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h
  15. 56 8
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c
  16. 5 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c
  17. 20 0
      components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h
  18. 21 18
      components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
  19. 75 0
      components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
  20. 8 3
      components/dp/core/src/wlan_dp_fisa_rx.c
  21. 1 1
      components/dp/core/src/wlan_dp_rx_thread.c
  22. 19 2
      components/dp/core/src/wlan_dp_softap_txrx.c
  23. 46 10
      components/mlme/core/inc/wlan_mlme_main.h
  24. 118 37
      components/mlme/core/src/wlan_mlme_main.c
  25. 4 0
      components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c
  26. 9 0
      components/mlme/dispatcher/inc/wlan_mlme_api.h
  27. 32 0
      components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
  28. 37 1
      components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
  29. 52 10
      components/mlme/dispatcher/src/wlan_mlme_api.c
  30. 28 9
      components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
  31. 1 2
      components/nan/core/src/nan_main.c
  32. 13 1
      components/pmo/core/src/wlan_pmo_suspend_resume.c
  33. 16 8
      components/tdls/core/src/wlan_tdls_ct.c
  34. 1 1
      components/tdls/core/src/wlan_tdls_main.c
  35. 42 33
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c
  36. 3 1
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h
  37. 28 4
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c
  38. 26 24
      components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c
  39. 4 0
      configs/config_to_feature.h
  40. 2 1
      configs/default_defconfig
  41. 1 2
      configs/pineapple_gki_kiwi-v2_defconfig
  42. 2 0
      configs/qca6174_defconfig
  43. 1 0
      configs/qca6390_defconfig
  44. 1 0
      configs/wcn6450_defconfig
  45. 5 1
      core/hdd/inc/hdd_config.h
  46. 32 3
      core/hdd/inc/hdd_dp_cfg.h
  47. 23 6
      core/hdd/inc/hdd_sar_safety_config.h
  48. 43 2
      core/hdd/inc/wlan_hdd_cfg.h
  49. 14 0
      core/hdd/inc/wlan_hdd_main.h
  50. 3 1
      core/hdd/inc/wlan_hdd_wmm.h
  51. 214 2
      core/hdd/src/wlan_hdd_cfg.c
  52. 440 28
      core/hdd/src/wlan_hdd_cfg80211.c
  53. 3 1
      core/hdd/src/wlan_hdd_cfg80211.h
  54. 1 1
      core/hdd/src/wlan_hdd_cm_connect.c
  55. 2 1
      core/hdd/src/wlan_hdd_cm_disconnect.c
  56. 8 0
      core/hdd/src/wlan_hdd_driver_ops.c
  57. 19 10
      core/hdd/src/wlan_hdd_hostapd.c
  58. 100 20
      core/hdd/src/wlan_hdd_main.c
  59. 3 1
      core/hdd/src/wlan_hdd_medium_assess.c
  60. 0 8
      core/hdd/src/wlan_hdd_mlo.c
  61. 7 7
      core/hdd/src/wlan_hdd_sar_limits.c
  62. 2 1
      core/hdd/src/wlan_hdd_son.c
  63. 419 150
      core/hdd/src/wlan_hdd_stats.c
  64. 5 0
      core/hdd/src/wlan_hdd_sysfs.c
  65. 446 0
      core/hdd/src/wlan_hdd_sysfs_bitrates.c
  66. 90 0
      core/hdd/src/wlan_hdd_sysfs_bitrates.h
  67. 2 1
      core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.c
  68. 4 2
      core/hdd/src/wlan_hdd_tsf.c
  69. 1 3
      core/hdd/src/wlan_hdd_twt.c
  70. 55 17
      core/hdd/src/wlan_hdd_wmm.c
  71. 2 0
      core/mac/inc/ani_global.h
  72. 3 3
      core/mac/inc/qwlan_version.h
  73. 114 0
      core/mac/inc/sir_mac_prot_def.h
  74. 3 2
      core/mac/inc/wni_api.h
  75. 102 6
      core/mac/src/cfg/cfgUtil/dot11f.frms
  76. 157 43
      core/mac/src/include/dot11f.h
  77. 27 1
      core/mac/src/include/parser_api.h
  78. 1 1
      core/mac/src/include/sir_params.h
  79. 52 0
      core/mac/src/pe/include/rrm_api.h
  80. 72 1
      core/mac/src/pe/include/rrm_global.h
  81. 12 28
      core/mac/src/pe/lim/lim_api.c
  82. 8 0
      core/mac/src/pe/lim/lim_process_message_queue.c
  83. 75 0
      core/mac/src/pe/lim/lim_process_mlm_req_messages.c
  84. 96 48
      core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
  85. 4 0
      core/mac/src/pe/lim/lim_process_probe_rsp_frame.c
  86. 44 5
      core/mac/src/pe/lim/lim_process_sme_req_messages.c
  87. 40 8
      core/mac/src/pe/lim/lim_send_management_frames.c
  88. 32 0
      core/mac/src/pe/lim/lim_timer_utils.c
  89. 3 2
      core/mac/src/pe/lim/lim_timer_utils.h
  90. 2 1
      core/mac/src/pe/lim/lim_trace.c
  91. 9 0
      core/mac/src/pe/lim/lim_types.h
  92. 31 7
      core/mac/src/pe/lim/lim_utils.c
  93. 868 34
      core/mac/src/pe/rrm/rrm_api.c
  94. 250 217
      core/mac/src/sys/legacy/src/utils/src/dot11f.c
  95. 3 0
      core/mac/src/sys/legacy/src/utils/src/mac_trace.c
  96. 186 3
      core/mac/src/sys/legacy/src/utils/src/parser_api.c
  97. 12 3
      core/pld/src/pld_pcie.c
  98. 263 262
      core/sap/src/sap_ch_select.c
  99. 0 20
      core/sap/src/sap_ch_select.h
  100. 1 1
      core/sap/src/sap_fsm.c

+ 3 - 1
Kbuild

@@ -3659,6 +3659,7 @@ 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
+cppflags-$(CONFIG_BCN_RATECODE_ENABLE) += -DWLAN_BCN_RATECODE_ENABLE
 
 ifeq ($(CONFIG_LEAK_DETECTION), y)
 ccflags-y += \
@@ -3790,6 +3791,7 @@ ccflags-$(CONFIG_FEATURE_STATS_EXT) += -DWLAN_FEATURE_STATS_EXT
 ccflags-$(CONFIG_QCACLD_FEATURE_NAN) += -DWLAN_FEATURE_NAN
 ccflags-$(CONFIG_QCACLD_FEATURE_SON) += -DWLAN_FEATURE_SON
 ccflags-$(CONFIG_NDP_SAP_CONCURRENCY_ENABLE) += -DNDP_SAP_CONCURRENCY_ENABLE
+ccflags-$(CONFIG_ENFORCE_PLD_REMOVE) += -DENFORCE_PLD_REMOVE
 
 ifeq ($(CONFIG_DFS_FCC_TYPE4_DURATION_CHECK), y)
 ccflags-$(CONFIG_DFS_FCC_TYPE4_DURATION_CHECK) += -DDFS_FCC_TYPE4_DURATION_CHECK
@@ -4246,7 +4248,6 @@ ccflags-$(CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC) += -DMON_ENABLE_DROP_FOR_NON_
 ccflags-$(CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG) += -DDP_WAR_INVALID_FIRST_MSDU_FLAG
 ccflags-$(CONFIG_LITHIUM) += -DDISABLE_MON_RING_MSI_CFG
 ccflags-$(CONFIG_LITHIUM) += -DFEATURE_IRQ_AFFINITY
-ccflags-$(CONFIG_RHINE) += -DDISABLE_MON_RING_MSI_CFG
 ccflags-$(CONFIG_RHINE) += -DFEATURE_IRQ_AFFINITY
 ccflags-$(CONFIG_RHINE) += -DWLAN_SOFTUMAC_SUPPORT
 ccflags-$(CONFIG_BERYLLIUM) += -DFEATURE_IRQ_AFFINITY
@@ -4772,6 +4773,7 @@ ccflags-$(CONFIG_WINDOW_REG_PLD_LOCK_ENABLE) += -DWINDOW_REG_PLD_LOCK_ENABLE
 ccflags-$(CONFIG_DUMP_REO_QUEUE_INFO_IN_DDR) += -DDUMP_REO_QUEUE_INFO_IN_DDR
 ccflags-$(CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK) += -DDP_RX_REFILL_CPU_PERF_AFFINE_MASK
 ccflags-$(CONFIG_WLAN_FEATURE_AFFINITY_MGR) += -DWLAN_FEATURE_AFFINITY_MGR
+ccflags-$(CONFIG_FEATURE_ENABLE_CE_DP_IRQ_AFFINE) += -DFEATURE_ENABLE_CE_DP_IRQ_AFFINE
 found = $(shell if grep -qF "walt_get_cpus_taken" $(srctree)/kernel/sched/walt/walt.c; then echo "yes" ;else echo "no" ;fi;)
 ifeq ($(findstring yes, $(found)), yes)
 ccflags-y += -DWALT_GET_CPU_TAKEN_SUPPORT

+ 5 - 4
Kconfig

@@ -1602,6 +1602,11 @@ config WLAN_SYSFS_WLAN_DBG
 	depends on WLAN_SYSFS
 	default n
 
+config WLAN_SYSFS_BITRATES
+	bool "enable WLAN_SYSFS_BITRATES"
+	depends on WLAN_SYSFS
+	default n
+
 config WLAN_THERMAL_CFG
 	bool "Enable WLAN_THERMAL_CFG"
 	default n
@@ -1742,10 +1747,6 @@ config WLAN_CTRL_NAME
 	string "Enable CONFIG_WLAN_CTRL_NAME"
 	default \"wlan\"
 
-config QCA_WIFI_FTM_IOCTL
-	bool "Enable CONFIG_QCA_WIFI_FTM_IOCTL"
-	default n
-
 config LL_DP_SUPPORT_NON_LITH
 	bool "ENABLE CONFIG_LL_DP_SUPPORT_NON_LITH"
 	default n

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

@@ -197,6 +197,9 @@ static void action_oui_load_config(struct action_oui_psoc_priv *psoc_priv)
 			[ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ],
 		      cfg_get(psoc, CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ),
 		      ACTION_OUI_MAX_STR_LEN);
+	qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_DISABLE_BFORMEE],
+		      cfg_get(psoc, CFG_ACTION_OUI_DISABLE_BFORMEE),
+			      ACTION_OUI_MAX_STR_LEN);
 }
 
 static void action_oui_parse_config(struct wlan_objmgr_psoc *psoc)

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

@@ -743,6 +743,35 @@
 	"", \
 	"send auth/assoc req with 6 Mbps rate on 2.4 GHz for specified APs")
 
+/*
+ * <ini>
+ * CFG_ACTION_OUI_DISABLE_BFORMEE - Used to disable SU/MU beamformee
+ * capability for specified AP with some conditions
+ *
+ * Example OUIs: (All values in Hex)
+ * OUI 1: 000c43
+ *       OUI data Len: 04
+ *       OUI Data : 03000000
+ *       OUI data Mask: F0 - 11110000
+ *       Info Mask : 01 - only OUI present in Info mask
+ *
+ * Refer to gEnableActionOUI for more detail about the format.
+ *
+ * Related: gEnableActionOUI
+ *
+ * Supported Feature: Action OUIs
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_ACTION_OUI_DISABLE_BFORMEE CFG_INI_STRING( \
+	"gActionOUIDisableBFORMEE", \
+	0, \
+	ACTION_OUI_MAX_STR_LEN, \
+	"", \
+	"disable SU/MU beamformee capability for specified AP")
+
 /*
  * <ini>
  * gActionOUIEnableCTS2SelfWithQoSNull - Used to enable CTS2SELF with QoS null
@@ -824,5 +853,6 @@
 	CFG(CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL) \
 	CFG(CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN) \
 	CFG(CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ) \
+	CFG(CFG_ACTION_OUI_DISABLE_BFORMEE) \
 	CFG(CFG_ENABLE_ACTION_OUI)
 #endif

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

@@ -112,6 +112,8 @@
  * @ACTION_OUI_TAKE_ALL_BAND_INFO: let AP country ie take all band info
  * @ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ: send auth/assoc req with 6 Mbps rate
  * on 2.4 GHz
+ * @ACTION_OUI_DISABLE_BFORMEE: disable SU/MU beam formee capability for
+ * specified AP
  * @ACTION_OUI_MAXIMUM_ID: maximum number of action oui types
  */
 enum action_oui_id {
@@ -136,6 +138,7 @@ enum action_oui_id {
 	ACTION_OUI_HOST_RECONN = ACTION_OUI_HOST_ONLY,
 	ACTION_OUI_TAKE_ALL_BAND_INFO,
 	ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ,
+	ACTION_OUI_DISABLE_BFORMEE,
 	ACTION_OUI_MAXIMUM_ID
 };
 

+ 16 - 4
components/cmn_services/interface_mgr/src/wlan_if_mgr_sta.c

@@ -67,9 +67,9 @@ QDF_STATUS if_mgr_connect_start(struct wlan_objmgr_vdev *vdev,
 	sta_cnt = policy_mgr_get_mode_specific_conn_info(psoc, NULL,
 							 vdev_id_list,
 							 PM_STA_MODE);
-	sap_cnt = policy_mgr_get_mode_specific_conn_info(psoc, NULL,
-							 &vdev_id_list[sta_cnt],
-							 PM_SAP_MODE);
+	sap_cnt = policy_mgr_get_sap_mode_info(psoc, NULL,
+					       &vdev_id_list[sta_cnt]);
+
 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
 
 	if (op_mode == QDF_STA_MODE || op_mode == QDF_P2P_CLIENT_MODE)
@@ -198,6 +198,7 @@ QDF_STATUS if_mgr_disconnect_start(struct wlan_objmgr_vdev *vdev,
 {
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_objmgr_pdev *pdev;
+	struct mlme_legacy_priv *mlme_priv;
 
 	pdev = wlan_vdev_get_pdev(vdev);
 	if (!pdev)
@@ -207,7 +208,11 @@ QDF_STATUS if_mgr_disconnect_start(struct wlan_objmgr_vdev *vdev,
 	if (!psoc)
 		return QDF_STATUS_E_FAILURE;
 
-	/* Leaving as stub to fill in later */
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv)
+		return QDF_STATUS_E_FAILURE;
+
+	qdf_runtime_pm_prevent_suspend(&mlme_priv->disconnect_runtime_lock);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -217,6 +222,7 @@ QDF_STATUS if_mgr_disconnect_complete(struct wlan_objmgr_vdev *vdev,
 {
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_objmgr_pdev *pdev;
+	struct mlme_legacy_priv *mlme_priv;
 	QDF_STATUS status;
 
 	pdev = wlan_vdev_get_pdev(vdev);
@@ -227,6 +233,12 @@ QDF_STATUS if_mgr_disconnect_complete(struct wlan_objmgr_vdev *vdev,
 	if (!psoc)
 		return QDF_STATUS_E_FAILURE;
 
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv)
+		return QDF_STATUS_E_FAILURE;
+
+	qdf_runtime_pm_allow_suspend(&mlme_priv->disconnect_runtime_lock);
+
 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE ||
 	    wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE)
 		wlan_handle_emlsr_sta_concurrency(psoc, false, true);

+ 285 - 22
components/cmn_services/logging/inc/wlan_connectivity_logging.h

@@ -165,6 +165,8 @@ enum wlan_main_tag {
  * @WLAN_CONN_DIAG_NBR_RPT_RESP_EVENT: Neighbor report response
  * @WLAN_CONN_DIAG_BCN_RPT_REQ_EVENT: Beacon report request
  * @WLAN_CONN_DIAG_BCN_RPT_RESP_EVENT: Beacon report response
+ * @WLAN_CONN_DIAG_MLO_T2LM_REQ_EVENT: MLO T2LM request
+ * @WLAN_CONN_DIAG_MLO_T2LM_RESP_EVENT: MLO T2LM response
  * @WLAN_CONN_DIAG_MAX: MAX tag
  */
 enum qca_conn_diag_log_event_type {
@@ -213,9 +215,73 @@ enum qca_conn_diag_log_event_type {
 	WLAN_CONN_DIAG_NBR_RPT_RESP_EVENT,
 	WLAN_CONN_DIAG_BCN_RPT_REQ_EVENT,
 	WLAN_CONN_DIAG_BCN_RPT_RESP_EVENT,
+	WLAN_CONN_DIAG_MLO_T2LM_REQ_EVENT,
+	WLAN_CONN_DIAG_MLO_T2LM_RESP_EVENT,
 	WLAN_CONN_DIAG_MAX
 };
 
+/*
+ * enum wlan_diag_wifi_band - Enum describing wifi band
+ * @WLAN_INVALID_BAND: invalid band
+ * @WLAN_24GHZ_BAND: 2.4 GHz band
+ * @WLAN_5GHZ_BAND: 5 GHz band
+ * @WLAN_6GHZ_BAND: 6 GHz band
+ */
+enum wlan_diag_wifi_band {
+	WLAN_INVALID_BAND = 0,
+	WLAN_24GHZ_BAND,
+	WLAN_5GHZ_BAND,
+	WLAN_6GHZ_BAND,
+};
+
+/**
+ * enum wlan_diag_mlo_link_switch_reason - MLO link switch reason enumeration
+ * @LINK_STATE_SWITCH_REASON_VDEV_READY: Link switch when vdev is ready
+ * @LINK_STATE_SWITCH_REASON_ULL_MODE: Link switch due to ULL mode configuration
+ * @LINK_STATE_SWITCH_REASON_T2LM_ENABLE: Link switch due to T2LM enable
+ * @LINK_STATE_SWITCH_REASON_T2LM_DISABLE: Link switch due T2LM disable
+ * @LINK_STATE_SWITCH_REASON_FORCE_ENABLED: Link switch when link is
+ * forcibly enable
+ * @LINK_STATE_SWITCH_REASON_FORCE_DISABLED: Link switch when link is
+ * forcibly disable
+ * @LINK_STATE_SWITCH_REASON_LINK_QUALITY: Link switch due to
+ * poor link quality
+ * @LINK_STATE_SWITCH_REASON_LINK_CAPACITY: Link switch due to link capacity
+ * @LINK_STATE_SWITCH_REASON_RSSI: Link switch due to changes in rssi
+ * @LINK_STATE_SWITCH_REASON_BMISS: Link switch due to BMISS
+ * @LINK_STATE_SWITCH_REASON_BT_STATUS: Link switch due to BT status
+ * @LINK_STATE_SWITCH_REASON_MAX: Max value
+ */
+enum wlan_diag_mlo_link_switch_reason {
+	LINK_STATE_SWITCH_REASON_VDEV_READY = 0,
+	LINK_STATE_SWITCH_REASON_ULL_MODE = 1,
+	LINK_STATE_SWITCH_REASON_T2LM_ENABLE = 2,
+	LINK_STATE_SWITCH_REASON_T2LM_DISABLE = 3,
+	LINK_STATE_SWITCH_REASON_FORCE_ENABLED = 4,
+	LINK_STATE_SWITCH_REASON_FORCE_DISABLED = 5,
+	LINK_STATE_SWITCH_REASON_LINK_QUALITY = 6,
+	LINK_STATE_SWITCH_REASON_LINK_CAPACITY = 7,
+	LINK_STATE_SWITCH_REASON_RSSI = 8,
+	LINK_STATE_SWITCH_REASON_BMISS = 9,
+	LINK_STATE_SWITCH_REASON_BT_STATUS = 10,
+	LINK_STATE_SWITCH_REASON_MAX,
+};
+
+/**
+ * enum wlan_bcn_rpt_measurement_mode - Measurement mode enum.
+ * Defined in IEEE Std 802.11‐2020 Table 9-103.
+ * @MEASURE_MODE_PASSIVE: Passive measurement mode
+ * @MEASURE_MODE_ACTIVE: Active measurement mode
+ * @MEASURE_MODE_BCN_TABLE: Beacon table measurement mode
+ * @MEASURE_MODE_RESERVED: Reserved
+ */
+enum wlan_bcn_rpt_measurement_mode {
+	MEASURE_MODE_PASSIVE = 0,
+	MEASURE_MODE_ACTIVE,
+	MEASURE_MODE_BCN_TABLE,
+	MEASURE_MODE_RESERVED = 0xFF
+};
+
 /**
  * struct wlan_connectivity_log_diag_cmn - Structure for diag event
  * @bssid: bssid
@@ -225,14 +291,171 @@ enum qca_conn_diag_log_event_type {
  * @ktime_us: Kernel Timestamp in microseconds
  */
 struct wlan_connectivity_log_diag_cmn {
-	uint8_t bssid[6];
+	uint8_t bssid[QDF_MAC_ADDR_SIZE];
 	uint16_t vdev_id;
 	uint64_t timestamp_us;
 	uint64_t fw_timestamp;
 	uint64_t ktime_us;
 } qdf_packed;
 
+#define DIAG_STA_INFO_VERSION 1
+
+/**
+ * struct wlan_diag_sta_info - STA info structure
+ * @diag_cmn: Common diag info
+ * @version: structure version
+ * @is_mlo: MLO connection bit
+ * @mac_2g: 2.4 GHz link station mac address
+ * @mac_5g: 5 GHz link station mac address
+ * @mac_6g: 6 GHz link station mac address
+ */
+struct wlan_diag_sta_info {
+	struct wlan_connectivity_log_diag_cmn diag_cmn;
+	uint8_t version;
+	uint8_t is_mlo;
+	uint8_t mac_2g[QDF_MAC_ADDR_SIZE];
+	uint8_t mac_5g[QDF_MAC_ADDR_SIZE];
+	uint8_t mac_6g[QDF_MAC_ADDR_SIZE];
+} qdf_packed;
+
+/*
+ * struct wlan_diag_mlo_cmn_info - MLO common info
+ * @band: Indicates link on which mlo setup is initiated.
+ * Refer enum enum wlan_diag_wifi_band.
+ * @link_id: Link id of the link when link is accepted
+ * @vdev_id: vdev id associated with the link
+ * @tid_ul: TID-to-link mapping information on the uplink
+ * @tid_dl: TID-to-link mapping information on the downlink
+ * @link_addr: Link address of the link.
+ */
+struct wlan_diag_mlo_cmn_info {
+	uint8_t band;
+	uint8_t link_id;
+	uint8_t vdev_id;
+	uint8_t tid_ul;
+	uint8_t tid_dl;
+	uint8_t status;
+	uint8_t link_addr[QDF_MAC_ADDR_SIZE];
+};
+
+#define DIAG_MLO_SETUP_VERSION 1
+
+#define MAX_BANDS 3
+/**
+ * struct wlan_diag_mlo_setup - MLO setup structure
+ * @diag_cmn: Common diag info
+ * @version: structure version
+ * @reserved: Reserved field
+ * @status: status code of the link. Non-zero value when link is rejected
+ * @mlo_cmn_info: MLO common info
+ */
+struct wlan_diag_mlo_setup {
+	struct wlan_connectivity_log_diag_cmn diag_cmn;
+	uint32_t version:8;
+	uint32_t reserved:24;
+	struct wlan_diag_mlo_cmn_info mlo_cmn_info[MAX_BANDS];
+} qdf_packed;
+
+#define DIAG_MLO_RECONFIG_VERSION 1
+
+/**
+ * struct wlan_diag_mlo_reconfig - MLO reconfig diag event structure
+ * @diag_cmn: Common diag info
+ * @version: structure version
+ * @reserved: Reserved field
+ * @mlo_cmn_info: MLO common info
+ */
+struct wlan_diag_mlo_reconfig {
+	struct wlan_connectivity_log_diag_cmn diag_cmn;
+	uint32_t version:8;
+	uint32_t reserved:24;
+	struct wlan_diag_mlo_cmn_info mlo_cmn_info;
+} qdf_packed;
+
+#define DIAG_MLO_T2LM_STATUS_VERSION 1
+
+/**
+ * struct wlan_diag_mlo_t2lm_status - MLO T2LM status diag event structure
+ * @diag_cmn: Common diag info
+ * @version: structure version
+ * @reserved: Reserved field
+ * @mlo_cmn_info: MLO common info
+ */
+struct wlan_diag_mlo_t2lm_status {
+	struct wlan_connectivity_log_diag_cmn diag_cmn;
+	uint32_t version:8;
+	uint32_t reserved:24;
+	struct wlan_diag_mlo_cmn_info mlo_cmn_info[MAX_BANDS];
+} qdf_packed;
+
+#define DIAG_MLO_T2LM_REQ_RESP_VERSION 1
+
+/**
+ * struct wlan_diag_mlo_t2lm_req_resp - MLO T2LM Req/Resp diag event structure
+ * @diag_cmn: Common diag info
+ * @version: Structure version
+ * @band: Indicates the band of the link
+ * @status: status code of TID-to-Link mapping response frame
+ * @token: Dialog Token field of TID-To-Link Mapping Request/Response frame
+ * @is_rx: Indicates the direction of packet. 0 - TX and 1 - RX
+ * @tx_status: tx status of transmitted packet. Refer enum qdf_dp_tx_rx_status
+ * @subtype: Subtype of the event
+ * @reserved: Reserved field
+ */
+struct wlan_diag_mlo_t2lm_req_resp {
+	struct wlan_connectivity_log_diag_cmn diag_cmn;
+	uint8_t version;
+	uint8_t band;
+	uint8_t status;
+	uint8_t token;
+	uint8_t is_rx:1;
+	uint8_t tx_status:7;
+	uint8_t subtype;
+	uint16_t reserved;
+} qdf_packed;
+
+#define DIAG_MLO_T2LM_TEARDOWN_VERSION 1
+
+/**
+ * struct wlan_diag_mlo_t2lm_teardown - MLO T2LM Teardown diag event structure
+ * @diag_cmn: Common diag info
+ * @version: structure version
+ * @band: Indicates the band of the link. Refer enum wlan_diag_wifi_band
+ * @tx_status: tx status of transmitted packet. Refer enum qdf_dp_tx_rx_status
+ * @reserved: Reserved field
+ */
+struct wlan_diag_mlo_t2lm_teardown {
+	struct wlan_connectivity_log_diag_cmn diag_cmn;
+	uint8_t version;
+	uint8_t band;
+	uint8_t tx_status;
+	uint8_t reserved;
+} qdf_packed;
+
+#define DIAG_MLO_LINK_STATUS_VERSION 1
+/**
+ * struct wlan_diag_mlo_link_status - MLO Link status diag event structure
+ * @diag_cmn: Common diag info
+ * @version: structure version
+ * @active_link: List of current active links. BIT 0: 2.4GHz BIT 1: 5GHz
+ * BIT 2: 6GHz
+ * @prev_active_link: List of inactive links. BIT 0: 2.4GHz BIT 1: 5GHz
+ * BIT 2: 6GHz
+ * @reason: Reason for changed link status. Refer
+ * enum wlan_diag_mlo_link_switch_reason
+ * @reserved: Reserved field
+ */
+struct wlan_diag_mlo_link_status {
+	struct wlan_connectivity_log_diag_cmn diag_cmn;
+	uint8_t version;
+	uint8_t active_link:5;
+	uint8_t prev_active_link:5;
+	uint8_t reserved:6;
+	uint8_t reason;
+} qdf_packed;
+
 #define DIAG_NBR_RPT_VERSION 1
+#define DIAG_NBR_RPT_VERSION_2 2
 
 /**
  * struct wlan_diag_nbr_rpt - Neighbor report structure
@@ -246,6 +469,9 @@ struct wlan_connectivity_log_diag_cmn {
  * @seq_num: Sequence number
  * @ssid: SSID
  * @freq: Frequency list in response frame
+ * @band: Band on which packet was received or transmitted.
+ * Refer enum enum wlan_diag_wifi_band
+ * @reserved: Reserved field
  */
 struct wlan_diag_nbr_rpt {
 	struct wlan_connectivity_log_diag_cmn diag_cmn;
@@ -258,24 +484,12 @@ struct wlan_diag_nbr_rpt {
 	uint32_t seq_num;
 	char ssid[WLAN_SSID_MAX_LEN];
 	uint32_t freq[WLAN_MAX_LOGGING_FREQ];
+	uint32_t band:8;
+	uint32_t reserved:24;
 } qdf_packed;
 
-/**
- * enum wlan_bcn_rpt_measurement_mode - Measurement mode enum.
- * Defined in IEEE Std 802.11‐2020 Table 9-103.
- * @MEASURE_MODE_PASSIVE: Passive measurement mode
- * @MEASURE_MODE_ACTIVE: Active measurement mode
- * @MEASURE_MODE_BCN_TABLE: Beacon table measurement mode
- * @MEASURE_MODE_RESERVED: Reserved
- */
-enum wlan_bcn_rpt_measurement_mode {
-	MEASURE_MODE_PASSIVE = 0,
-	MEASURE_MODE_ACTIVE,
-	MEASURE_MODE_BCN_TABLE,
-	MEASURE_MODE_RESERVED = 0xFF
-};
-
 #define DIAG_BCN_RPT_VERSION 1
+#define DIAG_BCN_RPT_VERSION_2 2
 
 /**
  * struct wlan_diag_bcn_rpt - Beacon report structure
@@ -294,6 +508,9 @@ enum wlan_bcn_rpt_measurement_mode {
  * Std 802.11‐2020 Table 9-103.
  * @duration: The duration over which the Beacon report was measured.(in ms)
  * @seq_num: Sequence number.
+ * @band: Band on which packet was received or transmitted.
+ * Refer enum enum wlan_diag_wifi_band
+ * @reserved: Reserved field
  */
 struct wlan_diag_bcn_rpt {
 	struct wlan_connectivity_log_diag_cmn diag_cmn;
@@ -308,6 +525,8 @@ struct wlan_diag_bcn_rpt {
 	uint16_t mode;
 	uint16_t duration;
 	uint32_t seq_num;
+	uint32_t band:8;
+	uint32_t reserved:24;
 } qdf_packed;
 
 #define DIAG_ROAM_CAND_VERSION 1
@@ -318,6 +537,7 @@ struct wlan_diag_bcn_rpt {
  * @diag_cmn: Common diag info
  * @version: Structure Version
  * @is_current_ap: Is the entry candidate AP or connected AP
+ * @is_mlo: MLO connection indicator
  * @reserved: Reserved
  * @idx: Entry index
  * @cu_load: Channel utilization load of the AP in percentage
@@ -331,7 +551,8 @@ struct wlan_diag_roam_candidate_info {
 	struct wlan_connectivity_log_diag_cmn diag_cmn;
 	uint8_t version;
 	uint8_t is_current_ap:1;
-	uint8_t reserved:7;
+	uint8_t is_mlo:1;
+	uint8_t reserved:6;
 	uint16_t idx;
 	uint16_t cu_load;
 	uint16_t subtype;
@@ -383,6 +604,7 @@ struct wlan_diag_roam_result {
 } qdf_packed;
 
 #define DIAG_ROAM_SCAN_START_VERSION 1
+#define DIAG_ROAM_SCAN_START_VERSION_V2 2
 
 /**
  * struct wlan_diag_roam_scan_start - Structure to store roam scan trigger
@@ -391,7 +613,8 @@ struct wlan_diag_roam_result {
  * @version: Structure Version
  * @is_full_scan: True if the scan is Full scan. False if the roam scan is
  * partial channel map scan
- * @reserved: Reserved
+ * @band: Band involved in the roaming during a MLO connection.
+ * Refer enum enum wlan_diag_wifi_band
  * @cu:  Current connected channel load in percentage
  * @trigger_reason: Roam trigger reason defined by enum roam_trigger_reason
  * @trigger_sub_reason: Roam scan trigger sub reason indicating if
@@ -404,7 +627,7 @@ struct wlan_diag_roam_scan_start {
 	struct wlan_connectivity_log_diag_cmn diag_cmn;
 	uint8_t version;
 	uint8_t is_full_scan:1;
-	uint8_t reserved:7;
+	uint8_t band:7;
 	uint16_t cu;
 	uint32_t trigger_reason;
 	uint32_t trigger_sub_reason;
@@ -431,6 +654,7 @@ struct wlan_diag_btm_cand_info {
 } qdf_packed;
 
 #define DIAG_BTM_VERSION 1
+#define DIAG_BTM_VERSION_2 2
 
 /**
  * struct wlan_diag_btm_info - BTM frame related logging data
@@ -445,7 +669,8 @@ struct wlan_diag_btm_cand_info {
  * 802.11‐2020 Table 9-428—BTM status code definitions
  * @delay: BSS Termination Delay field
  * @is_disassoc_imminent: Disassociation imminent bit
- * @reserved: Reserved field
+ * @band: indicates the link involved in MLO conenection.
+ * Refer enum enum wlan_diag_wifi_band
  * @token: dialog token. Dialog Token is a nonzero value chosen by the STA
  * @wtc_duration: WTC duration field in minutes
  * while sending the BTM frame to identify the query/request/response
@@ -465,7 +690,7 @@ struct wlan_diag_btm_info {
 	uint8_t status;
 	uint8_t delay;
 	uint8_t is_disassoc_imminent:1;
-	uint8_t reserved:7;
+	uint8_t band:7;
 	uint8_t token;
 	uint8_t subtype;
 	uint16_t wtc_duration;
@@ -474,6 +699,8 @@ struct wlan_diag_btm_info {
 } qdf_packed;
 
 #define DIAG_MGMT_VERSION 1
+#define DIAG_MGMT_VERSION_V2 2
+#define MAX_VSIE_LEN 255
 
 /**
  * struct wlan_diag_packet_info - Data packets related info
@@ -490,6 +717,9 @@ struct wlan_diag_btm_info {
  * @reason: reason code defined in Table 9-49 Reason codes field’ from the
  * IEEE 802.11 standard document.
  * @is_retry_frame: Retry frame indicator
+ * @is_tx: Packet direction indicator. 0 - RX, 1 - TX
+ * @supported_links: link id bitmap indicates the links involved
+ * in MLO connection.
  * @reserved: Reserved field
  * @subtype: Diag event defined in  enum qca_conn_diag_log_event_type
  * @assoc_id: Association ID
@@ -498,6 +728,11 @@ struct wlan_diag_btm_info {
  * https://www.iana.org/assignments/eap-numbers
  * @sn: Frame sequence number
  * @rssi: Peer RSSI in dBm
+ * @tx_fail_reason: tx failure reason printed on TX_FAIL status.
+ * Refer enum qdf_dp_tx_rx_status
+ * @mld_addr: MLD mac address
+ * @vsie_len: VSIE length
+ * @vsie: VSIE
  */
 struct wlan_diag_packet_info {
 	struct wlan_connectivity_log_diag_cmn diag_cmn;
@@ -509,13 +744,18 @@ struct wlan_diag_packet_info {
 	uint8_t tx_status;
 	uint8_t reason;
 	uint8_t is_retry_frame:1;
-	uint8_t reserved:7;
+	uint8_t is_tx:1;
+	uint8_t supported_links:6;
 	uint16_t subtype;
 	uint16_t assoc_id;
 	uint16_t eap_len;
 	uint16_t eap_type;
 	uint32_t sn;
 	int32_t rssi;
+	uint8_t tx_fail_reason;
+	uint8_t mld_addr[QDF_MAC_ADDR_SIZE];
+	uint8_t vsie_len;
+	uint8_t vsie[MAX_VSIE_LEN];
 } qdf_packed;
 
 #define DIAG_CONN_VERSION 1
@@ -947,6 +1187,15 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 static inline void wlan_connectivity_logging_stop(void)
 {}
 
+/**
+ * wlan_connectivity_sta_info_event() - APi to send STA info event
+ * @psoc: Pointer to global psoc object
+ * @vdev_id: Vdev id
+ */
+void
+wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc,
+				 uint8_t vdev_id);
+
 #elif defined(WLAN_FEATURE_CONNECTIVITY_LOGGING)
 /**
  * wlan_connectivity_logging_start()  - Initialize the connectivity/roaming
@@ -1015,6 +1264,15 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     uint8_t auth_algo, uint8_t auth_type,
 			     uint8_t auth_seq, uint16_t aid,
 			     enum wlan_main_tag tag);
+
+/**
+ * wlan_connectivity_sta_info_event() - APi to send STA info event
+ * @psoc: Pointer to global psoc object
+ * @vdev_id: Vdev id
+ */
+void
+wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc,
+				 uint8_t vdev_id);
 #else
 static inline
 void wlan_connectivity_logging_start(struct wlan_objmgr_psoc *psoc,
@@ -1046,5 +1304,10 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     uint8_t auth_seq, uint16_t aid,
 			     enum wlan_main_tag tag)
 {}
+static inline void
+wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc,
+				 uint8_t vdev_id)
+{
+}
 #endif
 #endif /* _WLAN_CONNECTIVITY_LOGGING_H_ */

+ 90 - 0
components/cmn_services/logging/src/wlan_connectivity_logging.c

@@ -23,6 +23,7 @@
 #include "wlan_connectivity_logging.h"
 #include "wlan_cm_api.h"
 #include "wlan_mlme_main.h"
+#include "wlan_mlo_mgr_sta.h"
 
 #ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
 static struct wlan_connectivity_log_buf_data global_cl;
@@ -299,6 +300,95 @@ wlan_cache_connectivity_log(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 
 #define WLAN_SAE_AUTH_ALGO_NUMBER 3
 #ifdef CONNECTIVITY_DIAG_EVENT
+
+#ifdef WLAN_FEATURE_11BE_MLO
+static QDF_STATUS
+wlan_populate_link_addr(struct wlan_objmgr_vdev *vdev,
+			struct wlan_diag_sta_info *wlan_diag_event)
+{
+	uint i = 0;
+	struct mlo_link_switch_context *link_ctx = vdev->mlo_dev_ctx->link_ctx;
+	struct wlan_channel *link_chan_info;
+
+	if (!link_ctx)
+		return QDF_STATUS_E_FAILURE;
+
+	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
+		link_chan_info = link_ctx->links_info[i].link_chan_info;
+
+		if (wlan_reg_is_24ghz_ch_freq(
+		    (qdf_freq_t)link_chan_info->ch_freq)) {
+			qdf_mem_copy(wlan_diag_event->mac_2g,
+				     link_ctx->links_info[i].link_addr.bytes,
+				     QDF_MAC_ADDR_SIZE);
+		} else if (wlan_reg_is_5ghz_ch_freq(
+			   (qdf_freq_t)link_chan_info->ch_freq)) {
+			qdf_mem_copy(wlan_diag_event->mac_5g,
+				     link_ctx->links_info[i].link_addr.bytes,
+				     QDF_MAC_ADDR_SIZE);
+		} else if (wlan_reg_is_6ghz_chan_freq(
+			   link_chan_info->ch_freq)) {
+			qdf_mem_copy(wlan_diag_event->mac_6g,
+				     link_ctx->links_info[i].link_addr.bytes,
+				     QDF_MAC_ADDR_SIZE);
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS
+wlan_populate_link_addr(struct wlan_objmgr_vdev *vdev,
+			struct wlan_diag_sta_info *wlan_diag_event)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+void
+wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev = NULL;
+
+	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_sta_info);
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_OBJMGR_ID);
+	if (!vdev) {
+		logging_err_rl("Invalid vdev:%d", vdev_id);
+		return;
+	}
+
+	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
+		goto out;
+
+	wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get());
+	wlan_diag_event.diag_cmn.vdev_id = vdev_id;
+	wlan_diag_event.is_mlo = mlo_is_mld_sta(vdev);
+
+	if (wlan_diag_event.is_mlo) {
+		qdf_mem_copy(wlan_diag_event.diag_cmn.bssid,
+			     wlan_vdev_mlme_get_mldaddr(vdev),
+			     QDF_MAC_ADDR_SIZE);
+		status = wlan_populate_link_addr(vdev, &wlan_diag_event);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			logging_err_rl("wlan_populate_link_addr failed");
+			goto out;
+		}
+	} else {
+		qdf_mem_copy(wlan_diag_event.diag_cmn.bssid,
+			     wlan_vdev_mlme_get_macaddr(vdev),
+			     QDF_MAC_ADDR_SIZE);
+	}
+
+	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_STA_INFO);
+
+out:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+}
+
 void
 wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     struct wlan_frame_hdr *mac_hdr,

+ 15 - 13
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -131,6 +131,8 @@ static inline const char *pcl_type_to_string(uint32_t idx)
 	CASE_RETURN_STRING(PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G);
 	CASE_RETURN_STRING(PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G);
 	CASE_RETURN_STRING(PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G);
+	CASE_RETURN_STRING(PM_SBS_CH_MCC_CH);
+	CASE_RETURN_STRING(PM_SBS_5G_MCC_24G);
 	default:
 		return "Unknown";
 	}
@@ -145,6 +147,7 @@ static inline const char *device_mode_to_string(uint32_t idx)
 	CASE_RETURN_STRING(PM_P2P_GO_MODE);
 	CASE_RETURN_STRING(PM_NDI_MODE);
 	CASE_RETURN_STRING(PM_NAN_DISC_MODE);
+	CASE_RETURN_STRING(PM_LL_LT_SAP_MODE);
 	default:
 		return "Unknown";
 	}
@@ -2409,19 +2412,6 @@ bool policy_mgr_is_mcc_on_any_sta_vdev(struct wlan_objmgr_psoc *psoc);
 void policy_mgr_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status,
 		uint32_t scan_config, uint32_t fw_mode_config);
 
-/**
- * policy_mgr_map_concurrency_mode() - to map concurrency mode
- * between sme and hdd
- * @old_mode: sme provided adapter mode
- * @new_mode: hdd provided concurrency mode
- *
- * This routine will map concurrency mode between sme and hdd
- *
- * Return: true or false
- */
-bool policy_mgr_map_concurrency_mode(enum QDF_OPMODE *old_mode,
-				     enum policy_mgr_con_mode *new_mode);
-
 /**
  * policy_mgr_mode_specific_num_open_sessions() - to get number of open sessions
  *                                                for a specific mode
@@ -5528,4 +5518,16 @@ uint32_t policy_mgr_get_sap_mode_info(struct wlan_objmgr_psoc *psoc,
 uint32_t policy_mgr_get_beaconing_mode_info(struct wlan_objmgr_psoc *psoc,
 					    uint32_t *ch_freq_list,
 					    uint8_t *vdev_id);
+
+/**
+ * policy_mgr_is_freq_on_mac_id() - Check if given freq belongs to given mac id
+ * @freq_range: Frequency range pointer
+ * @freq: Frequency which needs to be checked
+ * @mac_id: MAC id on which this frequency needs to be checked
+ *
+ * Return: True if given frequency belongs to the given MAC id
+ */
+bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range,
+				  qdf_freq_t freq, uint8_t mac_id);
+
 #endif /* __WLAN_POLICY_MGR_API_H */

+ 9 - 0
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h

@@ -387,4 +387,13 @@ ucfg_policy_mgr_get_indoor_chnl_marking(struct wlan_objmgr_psoc *psoc,
 
 bool
 ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_policy_mgr_is_fw_supports_dbs() - to check whether FW supports DBS or
+ * not
+ * @psoc: pointer to psoc
+ *
+ * Return: true if DBS is supported else false
+ */
+bool ucfg_policy_mgr_is_fw_supports_dbs(struct wlan_objmgr_psoc *psoc);
 #endif //__WLAN_POLICY_MGR_UCFG

+ 24 - 12
components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c

@@ -385,8 +385,13 @@ QDF_STATUS policy_mgr_update_connection_info(struct wlan_objmgr_psoc *psoc,
 
 	cur_freq = pm_conc_connection_list[conn_index].freq;
 
-	mode = policy_mgr_get_mode(conn_table_entry.type,
-					conn_table_entry.sub_type);
+	mode = policy_mgr_qdf_opmode_to_pm_con_mode(
+					psoc,
+					wlan_get_opmode_from_vdev_id(
+								pm_ctx->pdev,
+								vdev_id),
+					vdev_id);
+
 	ch_freq = conn_table_entry.mhz;
 	status = policy_mgr_get_nss_for_vdev(psoc, mode, &nss_2g, &nss_5g);
 	if (QDF_IS_STATUS_SUCCESS(status)) {
@@ -1499,7 +1504,7 @@ policy_mgr_con_mode_by_vdev_id(struct wlan_objmgr_psoc *psoc,
 		return mode;
 	}
 
-	op_mode = wlan_get_opmode_vdev_id(pm_ctx->pdev, vdev_id);
+	op_mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id);
 	return policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, vdev_id);
 }
 
@@ -1535,8 +1540,7 @@ static bool policy_mgr_is_sap_go_existed(struct wlan_objmgr_psoc *psoc)
 {
 	uint32_t ap_present, go_present;
 
-	ap_present = policy_mgr_mode_specific_connection_count(
-				psoc, PM_SAP_MODE, NULL);
+	ap_present = policy_mgr_get_sap_mode_count(psoc, NULL);
 	if (ap_present)
 		return true;
 
@@ -1963,7 +1967,7 @@ policy_mgr_nan_sap_pre_enable_conc_check(struct wlan_objmgr_psoc *psoc,
 		return false;
 	}
 
-	if (!(mode == PM_SAP_MODE || mode == PM_NAN_DISC_MODE)) {
+	if (!policy_mgr_is_sap_mode(mode) || mode == PM_NAN_DISC_MODE) {
 		policy_mgr_debug("Not NAN or SAP mode");
 		return true;
 	}
@@ -1987,6 +1991,13 @@ policy_mgr_nan_sap_pre_enable_conc_check(struct wlan_objmgr_psoc *psoc,
 		sap_freq = policy_mgr_mode_specific_get_channel(pm_ctx->psoc,
 								PM_SAP_MODE);
 		policy_mgr_debug("FREQ SAP: %d NAN: %d", sap_freq, ch_freq);
+		if (!sap_freq) {
+			sap_freq = policy_mgr_mode_specific_get_channel(
+							pm_ctx->psoc,
+							PM_LL_LT_SAP_MODE);
+			policy_mgr_debug("FREQ LL_LT_SAP: %d NAN: %d",
+					 sap_freq, ch_freq);
+		}
 		if (ucfg_is_nan_dbs_supported(pm_ctx->psoc) &&
 		    !WLAN_REG_IS_SAME_BAND_FREQS(sap_freq, ch_freq))
 			return true;
@@ -2005,7 +2016,7 @@ policy_mgr_nan_sap_pre_enable_conc_check(struct wlan_objmgr_psoc *psoc,
 			policy_mgr_debug("NAN+SAP unsafe ch SCC disabled");
 			return false;
 		}
-	} else if (mode == PM_SAP_MODE) {
+	} else if (policy_mgr_is_sap_mode(mode)) {
 		nan_2g_freq =
 			policy_mgr_mode_specific_get_channel(pm_ctx->psoc,
 							     PM_NAN_DISC_MODE);
@@ -2063,7 +2074,7 @@ policy_mgr_nan_sap_post_enable_conc_check(struct wlan_objmgr_psoc *psoc)
 
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
-		if (pm_conc_connection_list[i].mode == PM_SAP_MODE &&
+		if (policy_mgr_is_sap_mode(pm_conc_connection_list[i].mode) &&
 		    pm_conc_connection_list[i].in_use) {
 			sap_info = &pm_conc_connection_list[i];
 			break;
@@ -2309,7 +2320,7 @@ policy_mgr_handle_sap_plus_go_force_scc(struct wlan_objmgr_psoc *psoc)
 
 	vdev_id = work_info->sap_plus_go_force_scc.initiator_vdev_id;
 	chan_freq = wlan_get_operation_chan_freq_vdev_id(pm_ctx->pdev, vdev_id);
-	opmode = wlan_get_opmode_vdev_id(pm_ctx->pdev, vdev_id);
+	opmode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id);
 	vdev_con_mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, opmode,
 							     vdev_id);
 
@@ -2571,9 +2582,10 @@ static void __policy_mgr_check_sta_ap_concurrent_ch_intf(
 	if (!policy_mgr_is_sap_go_existed(pm_ctx->psoc))
 		goto end;
 
-	cc_count = policy_mgr_get_mode_specific_conn_info(
-				pm_ctx->psoc, &op_ch_freq_list[cc_count],
-				&vdev_id[cc_count], PM_SAP_MODE);
+	cc_count = policy_mgr_get_sap_mode_info(pm_ctx->psoc,
+						&op_ch_freq_list[cc_count],
+						&vdev_id[cc_count]);
+
 	policy_mgr_debug("Number of concurrent SAP: %d", cc_count);
 	if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS)
 		cc_count = cc_count +

+ 70 - 56
components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c

@@ -529,7 +529,7 @@ void policy_mgr_update_conc_list(struct wlan_objmgr_psoc *psoc,
 		pm_ctx->cdp_cbacks.cdp_update_mac_id(psoc, vdev_id, mac);
 
 	/* IPA only cares about STA or SAP mode */
-	if (mode == PM_STA_MODE || mode == PM_SAP_MODE) {
+	if (mode == PM_STA_MODE || policy_mgr_is_sap_mode(mode)) {
 		mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
 
 		if (pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb)
@@ -1166,6 +1166,9 @@ static uint32_t policy_mgr_dump_current_concurrency_one_connection(
 	case PM_NDI_MODE:
 		count = strlcat(cc_mode, "NDI", length);
 		break;
+	case PM_LL_LT_SAP_MODE:
+		count = strlcat(cc_mode, "LT_SAP", length);
+		break;
 	default:
 		policy_mgr_err("unexpected mode %d", mode);
 		break;
@@ -1237,6 +1240,12 @@ static uint32_t policy_mgr_dump_current_concurrency_two_connection(
 				psoc, cc_mode, length);
 		count += strlcat(cc_mode, "+NAN Disc", length);
 		break;
+	case PM_LL_LT_SAP_MODE:
+		count = policy_mgr_dump_current_concurrency_one_connection(
+				psoc, cc_mode, length);
+		count += strlcat(cc_mode, "+LT_SAP",
+					length);
+		break;
 	default:
 		policy_mgr_err("unexpected mode %d", mode);
 		break;
@@ -1309,6 +1318,13 @@ static uint32_t policy_mgr_dump_current_concurrency_three_connection(
 		count += strlcat(cc_mode, "+NDI",
 					length);
 		break;
+	case PM_LL_LT_SAP_MODE:
+		count = policy_mgr_dump_current_concurrency_two_connection(
+				psoc, cc_mode, length);
+		count += strlcat(cc_mode, "+LT_SAP",
+					length);
+
+		break;
 	default:
 		policy_mgr_err("unexpected mode %d", mode);
 		break;
@@ -1519,6 +1535,13 @@ static uint32_t policy_mgr_dump_current_concurrency_4_connection(
 		count += strlcat(cc_mode, "+NDI",
 					length);
 		break;
+	case PM_LL_LT_SAP_MODE:
+		count = policy_mgr_dump_current_concurrency_three_connection(
+				psoc, cc_mode, length);
+		count += strlcat(cc_mode, "+LT_SAP",
+					length);
+		break;
+
 	default:
 		policy_mgr_err("unexpected mode %d", mode);
 		break;
@@ -2082,58 +2105,6 @@ uint32_t policy_mgr_get_connection_for_vdev_id(struct wlan_objmgr_psoc *psoc,
 	return conn_index;
 }
 
-/**
- * policy_mgr_get_mode() - Get mode from type and subtype
- * @type: type
- * @subtype: subtype
- *
- * Get the concurrency mode from the type and subtype
- * of the interface
- *
- * Return: policy_mgr_con_mode
- */
-enum policy_mgr_con_mode policy_mgr_get_mode(uint8_t type,
-		uint8_t subtype)
-{
-	enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE;
-
-	if (type == WMI_VDEV_TYPE_AP) {
-		switch (subtype) {
-		case 0:
-			mode = PM_SAP_MODE;
-			break;
-		case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO:
-			mode = PM_P2P_GO_MODE;
-			break;
-		default:
-			policy_mgr_err("Unknown subtype %d for type %d",
-				subtype, type);
-			break;
-		}
-	} else if (type == WMI_VDEV_TYPE_STA) {
-		switch (subtype) {
-		case 0:
-			mode = PM_STA_MODE;
-			break;
-		case WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT:
-			mode = PM_P2P_CLIENT_MODE;
-			break;
-		default:
-			policy_mgr_err("Unknown subtype %d for type %d",
-				subtype, type);
-			break;
-		}
-	} else if (type == WMI_VDEV_TYPE_NAN) {
-		mode = PM_NAN_DISC_MODE;
-	} else if (type == WMI_VDEV_TYPE_NDI) {
-		mode = PM_NDI_MODE;
-	} else {
-		policy_mgr_err("Unknown type %d", type);
-	}
-
-	return mode;
-}
-
 /**
  * policy_mgr_get_bw() - Get channel bandwidth type used by WMI
  * @chan_width: channel bandwidth type defined by host
@@ -3706,6 +3677,49 @@ QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc,
 					  false);
 		status = QDF_STATUS_SUCCESS;
 		break;
+	case PM_SBS_CH_MCC_CH:
+		get_sub_channels(psoc,
+				 sbs_freqs, &sbs_num,
+				 scc_freqs, &scc_num,
+				 rest_freqs, &rest_num,
+				 channel_list_5, chan_index_5,
+				 channel_list_6, chan_index_6);
+		add_chlist_to_pcl(pm_ctx->pdev,
+				  pcl_channels, pcl_weights, pcl_sz,
+				  len, WEIGHT_OF_GROUP1_PCL_CHANNELS,
+				  sbs_freqs, sbs_num,
+				  skip_6ghz_channel);
+		add_chlist_to_pcl(pm_ctx->pdev,
+				  pcl_channels, pcl_weights, pcl_sz,
+				  len, WEIGHT_OF_GROUP2_PCL_CHANNELS,
+				  rest_freqs, rest_num,
+				  false);
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SBS_5G_MCC_24G:
+		get_sub_channels(psoc,
+				 sbs_freqs, &sbs_num,
+				 scc_freqs, &scc_num,
+				 rest_freqs, &rest_num,
+				 channel_list_5, chan_index_5,
+				 channel_list_6, chan_index_6);
+		add_chlist_to_pcl(pm_ctx->pdev,
+				  pcl_channels, pcl_weights, pcl_sz,
+				  len, WEIGHT_OF_GROUP1_PCL_CHANNELS,
+				  sbs_freqs, sbs_num,
+				  skip_6ghz_channel);
+		add_chlist_to_pcl(pm_ctx->pdev,
+				  pcl_channels, pcl_weights, pcl_sz,
+				  len, WEIGHT_OF_GROUP2_PCL_CHANNELS,
+				  rest_freqs, rest_num,
+				  skip_6ghz_channel);
+		add_chlist_to_pcl(pm_ctx->pdev,
+				  pcl_channels, pcl_weights, pcl_sz,
+				  len, WEIGHT_OF_GROUP3_PCL_CHANNELS,
+				  channel_list_24, chan_index_24,
+				  false);
+		status = QDF_STATUS_SUCCESS;
+		break;
 	default:
 		policy_mgr_err("unknown pcl value %d", pcl);
 		break;
@@ -4009,7 +4023,7 @@ policy_mgr_get_pref_force_scc_freq(struct wlan_objmgr_psoc *psoc,
 	else if (policy_mgr_is_mlo_in_mode_sbs(psoc, PM_STA_MODE, NULL, NULL))
 		sbs_ml_sta_present = true;
 
-	op_mode = wlan_get_opmode_vdev_id(pm_ctx->pdev, vdev_id);
+	op_mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id);
 	mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, vdev_id);
 
 	qdf_mem_zero(&pcl, sizeof(pcl));
@@ -4409,8 +4423,8 @@ QDF_STATUS policy_mgr_nss_update(struct wlan_objmgr_psoc *psoc,
 		}
 	}
 
-	count = policy_mgr_mode_specific_connection_count(psoc,
-			PM_SAP_MODE, list);
+	count = policy_mgr_get_sap_mode_count(psoc, list);
+
 	for (index = 0; index < count; index++) {
 		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 		vdev_id = pm_conc_connection_list[list[index]].vdev_id;

+ 38 - 82
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -4912,10 +4912,9 @@ void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc,
 	 * there are more than one STA connections
 	 */
 	if ((policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, NULL) > 1) ||
-	    (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, NULL) > 0) ||
+	    (policy_mgr_get_beaconing_mode_count(psoc, NULL) > 0) ||
 	    (policy_mgr_mode_specific_connection_count(psoc, PM_P2P_CLIENT_MODE, NULL) >
 									0) ||
-	    (policy_mgr_mode_specific_connection_count(psoc, PM_P2P_GO_MODE, NULL) > 0) ||
 	    (policy_mgr_mode_specific_connection_count(psoc,
 						       PM_NDI_MODE,
 						       NULL) > 0)) {
@@ -4924,8 +4923,7 @@ void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc,
 	};
 
 	/* Enable RPS if SAP interface has come up */
-	if (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, NULL)
-		== 1) {
+	if (policy_mgr_get_sap_mode_count(psoc, NULL) == 1) {
 		if (pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb)
 			pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb(true);
 	}
@@ -5080,15 +5078,10 @@ QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
 	    ((policy_mgr_mode_specific_connection_count(psoc,
 							PM_STA_MODE,
 							NULL) == 1) &&
-	     (policy_mgr_mode_specific_connection_count(psoc,
-							PM_SAP_MODE,
-							NULL) == 0) &&
+	     (policy_mgr_get_beaconing_mode_count(psoc, NULL) == 0) &&
 	     (policy_mgr_mode_specific_connection_count(psoc,
 							PM_P2P_CLIENT_MODE,
 							NULL) == 0) &&
-	     (policy_mgr_mode_specific_connection_count(psoc,
-							PM_P2P_GO_MODE,
-							NULL) == 0) &&
 	     (policy_mgr_mode_specific_connection_count(psoc,
 							PM_NDI_MODE,
 							NULL) == 0))) {
@@ -5097,8 +5090,7 @@ QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
 	};
 
 	/* Disable RPS if SAP interface has come up */
-	if (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, NULL)
-		== 0) {
+	if (policy_mgr_get_sap_mode_count(psoc, NULL) == 0) {
 		if (pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb)
 			pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb(false);
 	}
@@ -5181,8 +5173,8 @@ QDF_STATUS policy_mgr_incr_connection_count(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	mode = policy_mgr_get_mode(conn_table_entry.type,
-					conn_table_entry.sub_type);
+	mode =  policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, vdev_id);
+
 	ch_freq = conn_table_entry.mhz;
 	status = policy_mgr_get_nss_for_vdev(psoc, mode, &nss_2g, &nss_5g);
 	if (QDF_IS_STATUS_SUCCESS(status)) {
@@ -5293,40 +5285,6 @@ QDF_STATUS policy_mgr_decr_connection_count(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
-bool policy_mgr_map_concurrency_mode(enum QDF_OPMODE *old_mode,
-				     enum policy_mgr_con_mode *new_mode)
-{
-	bool status = true;
-
-	switch (*old_mode) {
-
-	case QDF_STA_MODE:
-		*new_mode = PM_STA_MODE;
-		break;
-	case QDF_SAP_MODE:
-		*new_mode = PM_SAP_MODE;
-		break;
-	case QDF_P2P_CLIENT_MODE:
-		*new_mode = PM_P2P_CLIENT_MODE;
-		break;
-	case QDF_P2P_GO_MODE:
-		*new_mode = PM_P2P_GO_MODE;
-		break;
-	case QDF_NAN_DISC_MODE:
-		*new_mode = PM_NAN_DISC_MODE;
-		break;
-	case QDF_NDI_MODE:
-		*new_mode = PM_NDI_MODE;
-		break;
-	default:
-		*new_mode = PM_MAX_NUM_OF_MODE;
-		status = false;
-		break;
-	}
-
-	return status;
-}
-
 uint32_t policy_mgr_get_mode_specific_conn_info(
 		struct wlan_objmgr_psoc *psoc,
 		uint32_t *ch_freq_list, uint8_t *vdev_id,
@@ -5719,8 +5677,7 @@ static bool policy_mgr_is_6g_channel_allowed(
 		is_dfs = (conn->ch_flagext &
 			(IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2)) &&
 			WLAN_REG_IS_5GHZ_CH_FREQ(conn->freq);
-		if ((conn->mode == PM_SAP_MODE ||
-		     conn->mode == PM_P2P_GO_MODE) &&
+		if (policy_mgr_is_beaconing_mode(conn->mode) &&
 		    is_dfs && (ch_freq != conn->freq &&
 			       !policy_mgr_are_sbs_chan(psoc, ch_freq,
 							conn->freq))) {
@@ -6273,7 +6230,8 @@ 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)) {
+	if (ml_is_nlink_service_supported(psoc) &&
+	    reason != MLO_LINK_FORCE_REASON_TDLS) {
 		status =
 		policy_mgr_mlo_sta_set_link_by_linkid(psoc, vdev, reason,
 						      mode,
@@ -7224,12 +7182,10 @@ policy_mgr_handle_ml_sta_link_concurrency(struct wlan_objmgr_psoc *psoc,
 	 * the link, disabled by SAP/P2P logic, as this API only consider
 	 * STA specific counts and ignore other counts.
 	 */
-	if (policy_mgr_mode_specific_connection_count(psoc,
-						      PM_SAP_MODE, NULL) ||
+	if (policy_mgr_get_beaconing_mode_count(psoc, NULL) ||
 	    policy_mgr_mode_specific_connection_count(psoc,
-					      PM_P2P_CLIENT_MODE, NULL) ||
-	    policy_mgr_mode_specific_connection_count(psoc,
-						      PM_P2P_GO_MODE, NULL)) {
+						      PM_P2P_CLIENT_MODE,
+						      NULL)) {
 		policy_mgr_debug("SAP/GO/CLI exist ignore this check");
 		return QDF_STATUS_E_INVAL;
 	}
@@ -7271,8 +7227,8 @@ policy_mgr_handle_ml_sta_link_concurrency(struct wlan_objmgr_psoc *psoc,
 static bool
 policy_mgr_is_mode_p2p_sap(enum policy_mgr_con_mode mode)
 {
-	return (mode == PM_SAP_MODE) || (mode == PM_P2P_CLIENT_MODE) ||
-	       (mode == PM_P2P_GO_MODE);
+	return (policy_mgr_is_beaconing_mode(mode) ||
+		(mode == PM_P2P_CLIENT_MODE));
 }
 
 bool
@@ -9569,6 +9525,7 @@ enum QDF_OPMODE policy_mgr_get_qdf_mode_from_pm(
 		mode = QDF_STA_MODE;
 		break;
 	case PM_SAP_MODE:
+	case PM_LL_LT_SAP_MODE:
 		mode = QDF_SAP_MODE;
 		break;
 	case PM_P2P_CLIENT_MODE:
@@ -10248,9 +10205,8 @@ uint32_t policy_mgr_get_sap_go_count_on_mac(struct wlan_objmgr_psoc *psoc,
 	     conn_index++) {
 		if (pm_conc_connection_list[conn_index].mac == mac_id &&
 		    pm_conc_connection_list[conn_index].in_use &&
-		    (pm_conc_connection_list[conn_index].mode == PM_SAP_MODE ||
-		     pm_conc_connection_list[conn_index].mode ==
-		     PM_P2P_GO_MODE)) {
+		    policy_mgr_is_beaconing_mode(
+				pm_conc_connection_list[conn_index].mode)) {
 			if (list)
 				list[count] =
 				    pm_conc_connection_list[conn_index].vdev_id;
@@ -10314,9 +10270,9 @@ QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_INVAL;
 	}
 
-	cc_count = policy_mgr_get_mode_specific_conn_info(
-			psoc, &op_ch_freq_list[cc_count],
-			&vdev_id[cc_count], PM_SAP_MODE);
+	cc_count = policy_mgr_get_sap_mode_info(psoc,
+						&op_ch_freq_list[cc_count],
+						&vdev_id[cc_count]);
 
 	if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS)
 		cc_count = cc_count +
@@ -10748,7 +10704,7 @@ bool policy_mgr_is_multi_sap_allowed_on_same_band(
 		return false;
 	}
 
-	if (!ch_freq || mode != PM_SAP_MODE)
+	if (!ch_freq || !policy_mgr_is_sap_mode(mode))
 		return true;
 
 	status = policy_mgr_get_multi_sap_allowed_on_same_band(psoc,
@@ -10763,8 +10719,7 @@ bool policy_mgr_is_multi_sap_allowed_on_same_band(
 		uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
 		struct policy_mgr_conc_connection_info *ap_info;
 
-		ap_cnt = policy_mgr_mode_specific_connection_count(psoc,
-							PM_SAP_MODE, list);
+		ap_cnt = policy_mgr_get_sap_mode_count(psoc, list);
 		if (!ap_cnt)
 			return true;
 
@@ -11031,7 +10986,8 @@ void policy_mgr_init_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc,
 	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
 			conn_index++) {
 		conn_info = &pm_conc_connection_list[conn_index];
-		if (conn_info->in_use && PM_SAP_MODE == conn_info->mode &&
+		if (conn_info->in_use &&
+		    policy_mgr_is_sap_mode(conn_info->mode) &&
 		    vdev_id == conn_info->vdev_id) {
 			conn_info->conn_6ghz_flag = ap_6ghz_capable;
 			conn_info->conn_6ghz_flag |= CONN_6GHZ_FLAG_VALID;
@@ -11063,8 +11019,8 @@ void policy_mgr_set_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc,
 	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
 			conn_index++) {
 		conn_info = &pm_conc_connection_list[conn_index];
-		if (conn_info->in_use && (PM_SAP_MODE == conn_info->mode ||
-					  PM_P2P_GO_MODE == conn_info->mode) &&
+		if (conn_info->in_use &&
+		    policy_mgr_is_beaconing_mode(conn_info->mode) &&
 		    policy_mgr_is_6ghz_conc_mode_supported(
 						psoc, conn_info->mode) &&
 		    vdev_id == conn_info->vdev_id) {
@@ -11104,8 +11060,8 @@ bool policy_mgr_get_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc,
 	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
 			conn_index++) {
 		conn_info = &pm_conc_connection_list[conn_index];
-		if (conn_info->in_use && (PM_SAP_MODE == conn_info->mode ||
-					  PM_P2P_GO_MODE == conn_info->mode) &&
+		if (conn_info->in_use &&
+		    policy_mgr_is_beaconing_mode(conn_info->mode) &&
 		    policy_mgr_is_6ghz_conc_mode_supported(
 						psoc, conn_info->mode) &&
 		    vdev_id == conn_info->vdev_id) {
@@ -11249,10 +11205,8 @@ policy_mgr_fetch_existing_con_info(struct wlan_objmgr_psoc *psoc,
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
 	     conn_index++) {
-		if ((pm_conc_connection_list[conn_index].mode ==
-		    PM_P2P_GO_MODE ||
-		    pm_conc_connection_list[conn_index].mode ==
-		    PM_SAP_MODE ||
+		if ((policy_mgr_is_beaconing_mode(
+				pm_conc_connection_list[conn_index].mode) ||
 		    pm_conc_connection_list[conn_index].mode ==
 		    PM_P2P_CLIENT_MODE ||
 		    pm_conc_connection_list[conn_index].mode ==
@@ -11591,10 +11545,7 @@ QDF_STATUS policy_mgr_check_mon_concurrency(struct wlan_objmgr_psoc *psoc)
 		return QDF_STATUS_E_BUSY;
 	}
 
-	num_open_session = policy_mgr_mode_specific_connection_count(
-					psoc,
-					PM_SAP_MODE,
-					NULL);
+	num_open_session = policy_mgr_get_sap_mode_count(psoc, NULL);
 
 	if (num_open_session) {
 		policy_mgr_err("cannot add monitor mode, due to SAP concurrency");
@@ -11858,8 +11809,8 @@ static qdf_freq_t _policy_mgr_get_ll_sap_freq(struct wlan_objmgr_psoc *psoc,
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	for (conn_idx = 0; conn_idx < MAX_NUMBER_OF_CONC_CONNECTIONS;
 	     conn_idx++) {
-		if (!(pm_conc_connection_list[conn_idx].mode ==
-		      PM_SAP_MODE &&
+		if (!(policy_mgr_is_sap_mode(
+				pm_conc_connection_list[conn_idx].mode) &&
 		      pm_conc_connection_list[conn_idx].in_use))
 			continue;
 
@@ -12144,3 +12095,8 @@ policy_mgr_reset_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc)
 	return QDF_STATUS_SUCCESS;
 }
 
+bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range,
+				  qdf_freq_t freq, uint8_t mac_id)
+{
+	return IS_FREQ_ON_MAC_ID(freq_range, freq, mac_id);
+}

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

@@ -818,8 +818,6 @@ policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx) {}
 void policy_mgr_dump_current_concurrency(struct wlan_objmgr_psoc *psoc);
 
 void pm_dbs_opportunistic_timer_handler(void *data);
-enum policy_mgr_con_mode policy_mgr_get_mode(uint8_t type,
-		uint8_t subtype);
 
 /**
  * policy_mgr_get_channel_list() - Get channel list based on PCL and mode

+ 56 - 8
components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -1394,6 +1394,45 @@ static inline bool policy_mgr_is_6G_chan_valid_for_ll_sap(qdf_freq_t freq)
 	return false;
 }
 #endif
+
+static bool policy_mgr_is_dynamic_sbs_enabled(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx)
+		return false;
+
+	return (policy_mgr_is_hw_sbs_capable(psoc) &&
+		policy_mgr_can_2ghz_share_low_high_5ghz_sbs(pm_ctx));
+}
+
+/**
+ * policy_mgr_is_sbs_mac0_freq() - Check if the given frequency is
+ * sbs frequency on mac0.
+ * @psoc: psoc pointer
+ * @freq: Frequency which needs to be checked.
+ *
+ * Return: true/false.
+ */
+static bool policy_mgr_is_sbs_mac0_freq(struct wlan_objmgr_psoc *psoc,
+					qdf_freq_t freq)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	struct policy_mgr_freq_range *freq_range;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx)
+		return false;
+
+	freq_range = pm_ctx->hw_mode.freq_range_caps[MODE_SBS];
+
+	if (policy_mgr_is_freq_on_mac_id(freq_range, freq, 0))
+		return true;
+
+	return false;
+}
+
 static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap(
 			struct wlan_objmgr_psoc *psoc,
 			uint32_t *pcl_channels, uint8_t *pcl_weight,
@@ -1403,6 +1442,8 @@ static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap(
 	uint32_t pcl_list[NUM_CHANNELS], orig_len = *len;
 	uint8_t weight_list[NUM_CHANNELS];
 	uint32_t i, pcl_len = 0;
+	bool is_dynamic_sbs_enabled;
+	bool sbs_mac0_modified_pcl;
 
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {
@@ -1410,6 +1451,7 @@ static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap(
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	is_dynamic_sbs_enabled = policy_mgr_is_dynamic_sbs_enabled(psoc);
 	policy_mgr_pcl_modification_for_sap(
 		psoc, pcl_channels, pcl_weight, len, weight_len);
 
@@ -1424,6 +1466,13 @@ static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap(
 		    !policy_mgr_is_6G_chan_valid_for_ll_sap(pcl_channels[i]))
 			continue;
 
+		/* Remove mac0 frequencies for static SBS case */
+		if (!is_dynamic_sbs_enabled &&
+		    policy_mgr_is_sbs_mac0_freq(psoc, pcl_channels[i])) {
+			sbs_mac0_modified_pcl = true;
+			continue;
+		}
+
 		pcl_list[pcl_len] = pcl_channels[i];
 		weight_list[pcl_len++] = pcl_weight[i];
 	}
@@ -1437,7 +1486,8 @@ static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap(
 	qdf_mem_copy(pcl_weight, weight_list, pcl_len);
 	*len = pcl_len;
 
-	policy_mgr_debug("PCL after ll sap modification");
+	policy_mgr_debug("sbs_mac0_modified_pcl %d, PCL after ll sap modification",
+			 sbs_mac0_modified_pcl);
 	policy_mgr_dump_channel_list(*len, pcl_channels, pcl_weight);
 
 	return QDF_STATUS_SUCCESS;
@@ -1763,6 +1813,8 @@ enum policy_mgr_one_connection_mode
 			index = PM_NAN_DISC_24_1x1;
 		else
 			index = PM_NAN_DISC_24_2x2;
+	} else if (PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) {
+		index = PM_LL_LT_SAP_5_2x2;
 	}
 
 	policy_mgr_debug("mode:%d freq:%d chain:%d index:%d",
@@ -3479,7 +3531,7 @@ QDF_STATUS policy_mgr_get_valid_chans_from_range(
 	ch_weight_len = *ch_cnt;
 
 	/* check the channel avoidance list for beaconing entities */
-	if (mode == PM_SAP_MODE || mode == PM_P2P_GO_MODE)
+	if (policy_mgr_is_beaconing_mode(mode))
 		policy_mgr_update_with_safe_channel_list(
 			psoc, ch_freq_list, ch_cnt, ch_weight_list,
 			ch_weight_len);
@@ -3930,10 +3982,7 @@ QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc,
 		 * vdev is SAP/P2PGO/P2PGC.
 		 */
 		if ((mode == PM_P2P_GO_MODE || mode == PM_P2P_CLIENT_MODE) &&
-		    (policy_mgr_mode_specific_connection_count(
-						psoc, PM_SAP_MODE, NULL) ||
-		     policy_mgr_mode_specific_connection_count(
-						psoc, PM_P2P_GO_MODE, NULL) ||
+		    ((policy_mgr_get_beaconing_mode_count(psoc, NULL)) ||
 		     policy_mgr_mode_specific_connection_count(
 					psoc, PM_P2P_CLIENT_MODE, NULL)))
 			strict_follow_pcl = true;
@@ -4308,8 +4357,7 @@ bool policy_mgr_is_sta_chan_valid_for_connect_and_roam(
 	skip_6g_and_indoor_freq =
 		wlan_scan_cfg_skip_6g_and_indoor_freq(psoc);
 	sap_count =
-		policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE,
-							  NULL);
+		policy_mgr_get_sap_mode_count(psoc, NULL);
 	/*
 	 * Do not allow STA to connect/roam on 6Ghz or indoor channel for
 	 * non-dbs hardware if SAP is present and skip_6g_and_indoor_freq_scan

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

@@ -332,3 +332,8 @@ ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl(struct wlan_objmgr_psoc *psoc)
 	return policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc) ?
 								true : false;
 }
+
+bool ucfg_policy_mgr_is_fw_supports_dbs(struct wlan_objmgr_psoc *psoc)
+{
+	return policy_mgr_find_if_fw_supports_dbs(psoc);
+}

+ 20 - 0
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h

@@ -394,6 +394,19 @@ void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc,
 				    struct channel_status *chan_stat,
 				    uint8_t vdev_id);
 
+/**
+ * wlan_cp_stats_get_rx_clear_count() - API to get rx clear count for a channel
+ * @psoc: pointer to psoc
+ * @vdev_id: vdev id
+ * @channel: channel for which rx clear count require
+ * @chan_load: buffer to store rx clear count for a channel
+ *
+ * Return: None
+ */
+void wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, uint8_t channel,
+				      uint8_t *chan_load);
+
 /**
  * ucfg_mc_cp_stats_clear_channel_status() - API to clear chan stats
  * @pdev: pointer to pdev object
@@ -506,6 +519,13 @@ void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc,
 {
 }
 
+static inline
+void wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, uint8_t channel,
+				      uint8_t *chan_load)
+{
+}
+
 static inline
 void ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev *pdev)
 {

+ 21 - 18
components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c

@@ -672,8 +672,8 @@ tgt_mc_infra_cp_stats_extract_twt_stats(struct wlan_objmgr_psoc *psoc,
 					struct infra_cp_stats_event *ev)
 {
 	QDF_STATUS status;
-	get_infra_cp_stats_cb resp_cb;
-	void *context;
+	get_infra_cp_stats_cb resp_cb = NULL;
+	void *context = NULL;
 
 	status = wlan_cp_stats_infra_cp_get_context(psoc, &resp_cb, &context);
 	if (QDF_IS_STATUS_ERROR(status)) {
@@ -761,31 +761,34 @@ tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc,
 #ifdef WLAN_FEATURE_11BE_MLO
 static void
 update_ml_vdev_id_from_stats_event(struct wlan_objmgr_psoc *psoc,
-				   struct stats_event *ev,
 				   struct request_info *req,
 				   uint8_t *vdev_id)
 {
-	uint8_t i, j, t_vdev_id;
+	uint8_t j, t_vdev_id;
 
-	if (!wlan_vdev_mlme_get_is_mlo_vdev(psoc, req->vdev_id)) {
+	if ((!wlan_vdev_mlme_get_is_mlo_vdev(psoc, req->vdev_id) &&
+	    !wlan_vdev_mlme_get_is_mlo_link(psoc, req->vdev_id)) ||
+	    !req->ml_vdev_info.ml_vdev_count) {
 		*vdev_id = req->vdev_id;
 		return;
 	}
 
-	for (i = 0; i < ev->num_summary_stats; i++) {
-		t_vdev_id = ev->vdev_summary_stats[i].vdev_id;
-		for (j = 0; j < req->ml_vdev_info.ml_vdev_count; j++) {
-			if (t_vdev_id == req->ml_vdev_info.ml_vdev_id[j]) {
-				*vdev_id = req->ml_vdev_info.ml_vdev_id[j];
-				break;
-			}
+	t_vdev_id = *vdev_id;
+	for (j = 0; j < req->ml_vdev_info.ml_vdev_count; j++) {
+		if (t_vdev_id == req->ml_vdev_info.ml_vdev_id[j]) {
+			*vdev_id = req->ml_vdev_info.ml_vdev_id[j];
+			return;
 		}
 	}
+
+	if (j == req->ml_vdev_info.ml_vdev_count) {
+		cp_stats_err("vdev[%u] not found", t_vdev_id);
+		*vdev_id = WLAN_UMAC_VDEV_ID_MAX;
+	}
 }
 #else
 static void
 update_ml_vdev_id_from_stats_event(struct wlan_objmgr_psoc *psoc,
-				   struct stats_event *ev,
 				   struct request_info *req,
 				   uint8_t *vdev_id)
 {
@@ -893,8 +896,9 @@ static void tgt_mc_cp_stats_extract_vdev_summary_stats(
 	}
 
 	vdev_id = last_req.vdev_id;
-	update_ml_vdev_id_from_stats_event(psoc, ev, &last_req, &vdev_id);
 	for (i = 0; i < ev->num_summary_stats; i++) {
+		vdev_id = ev->vdev_summary_stats[i].vdev_id;
+		update_ml_vdev_id_from_stats_event(psoc, &last_req, &vdev_id);
 		if (ev->vdev_summary_stats[i].vdev_id == vdev_id)
 			break;
 	}
@@ -973,12 +977,11 @@ static void tgt_mc_cp_stats_extract_vdev_chain_rssi_stats(
 	}
 
 	for (i = 0; i < ev->num_chain_rssi_stats; i++) {
-		vdev_id = last_req.vdev_id;
-		if (vdev_id != ev->vdev_chain_rssi[i].vdev_id)
+		vdev_id = ev->vdev_chain_rssi[i].vdev_id;
+		update_ml_vdev_id_from_stats_event(psoc, &last_req, &vdev_id);
+		if (ev->vdev_chain_rssi[i].vdev_id != vdev_id)
 			continue;
 
-		update_ml_vdev_id_from_stats_event(psoc, ev,
-						   &last_req, &vdev_id);
 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
 							    WLAN_CP_STATS_ID);
 		if (!vdev) {

+ 75 - 0
components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c

@@ -1048,6 +1048,81 @@ void ucfg_mc_cp_stats_register_lost_link_info_cb(
 	psoc_cp_stats_priv->legacy_stats_cb = lost_link_cp_stats_info_cb;
 }
 
+#ifdef QCA_SUPPORT_CP_STATS
+void wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
+				      uint8_t vdev_id, uint8_t channel,
+				      uint8_t *chan_load)
+{
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_vdev *vdev;
+	struct pdev_cp_stats *pdev_cp_stats_priv;
+	struct per_channel_stats *channel_stats;
+	struct channel_status *channel_status_list;
+	uint8_t total_channel;
+	uint8_t i;
+	uint32_t rx_clear_count = 0, cycle_count = 0, mac_clk_mhz = 0;
+	uint64_t clock_freq, time, time_busy;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_CP_STATS_ID);
+	if (!vdev)
+		return;
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		cp_stats_err("pdev object is null");
+		goto release_ref;
+	}
+
+	pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
+	if (!pdev_cp_stats_priv) {
+		cp_stats_err("pdev cp stats object is null");
+		goto release_ref;
+	}
+
+	channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats;
+	channel_status_list = channel_stats->channel_status_list;
+	total_channel = channel_stats->total_channel;
+
+	for (i = 0; i < total_channel && i < NUM_CHANNELS; i++) {
+		if (channel_status_list[i].channel_id == channel) {
+			rx_clear_count = channel_status_list[i].rx_clear_count;
+			cycle_count = channel_status_list[i].cycle_count;
+			mac_clk_mhz = channel_status_list[i].mac_clk_mhz;
+			break;
+		}
+	}
+
+	if (i == total_channel) {
+		cp_stats_debug("no channel found for chan:%d", channel);
+		goto release_ref;
+	}
+
+	clock_freq = mac_clk_mhz * 1000;
+	if (clock_freq == 0) {
+		cp_stats_debug("clock_freq is zero");
+		goto release_ref;
+	}
+
+	time = qdf_do_div(cycle_count, clock_freq);
+	if (time == 0) {
+		cp_stats_debug("time is zero");
+		goto release_ref;
+	}
+
+	time_busy = qdf_do_div(rx_clear_count, clock_freq);
+
+	*chan_load = ((time_busy * 255) / time);
+
+	cp_stats_debug("t_chan:%d, chan:%d, rcc:%u, cc:%u, cf:%u, time:%u, time_busy:%u, chan_load:%d",
+		       total_channel, channel, rx_clear_count, cycle_count,
+		       clock_freq, time, time_busy, *chan_load);
+
+release_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
+}
+#endif
+
 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
 static QDF_STATUS
 ucfg_mc_cp_stats_suspend_req_handler(struct wlan_objmgr_psoc *psoc)

+ 8 - 3
components/dp/core/src/wlan_dp_fisa_rx.c

@@ -1470,6 +1470,10 @@ get_new_vdev_ref:
 				fisa_flow_head_skb_vdev->mld_mac_addr.raw,
 				QDF_MAC_ADDR_SIZE) != 0)) {
 			qdf_nbuf_free(fisa_flow->head_skb);
+			dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
+					     fisa_flow_head_skb_vdev,
+					     DP_MOD_ID_RX);
+			fisa_flow_head_skb_vdev = NULL;
 			goto out;
 		} else {
 			fisa_flow->same_mld_vdev_mismatch++;
@@ -1511,9 +1515,10 @@ dp_fisa_rx_get_flow_flush_vdev_ref(ol_txrx_soc_handle cdp_soc,
 	return fisa_flow_head_skb_vdev;
 
 out:
-	dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
-			     fisa_flow_head_skb_vdev,
-			     DP_MOD_ID_RX);
+	if (fisa_flow_head_skb_vdev)
+		dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc),
+				     fisa_flow_head_skb_vdev,
+				     DP_MOD_ID_RX);
 	return NULL;
 }
 #endif

+ 1 - 1
components/dp/core/src/wlan_dp_rx_thread.c

@@ -763,9 +763,9 @@ static int dp_rx_refill_thread_loop(void *arg)
 			QDF_DEBUG_PANIC("wait_event_interruptible returned -ERESTARTSYS");
 			break;
 		}
-		dp_rx_refill_thread_sub_loop(rx_thread, &shutdown);
 		qdf_atomic_clear_bit(RX_REFILL_POST_EVENT,
 				     &rx_thread->event_flag);
+		dp_rx_refill_thread_sub_loop(rx_thread, &shutdown);
 	}
 
 	/* If we get here the scheduler thread must exit */

+ 19 - 2
components/dp/core/src/wlan_dp_softap_txrx.c

@@ -229,6 +229,19 @@ int dp_post_dhcp_ind(struct wlan_dp_link *dp_link, uint8_t *mac_addr,
 	}
 
 	dp_intf = dp_link->dp_intf;
+	/*
+	 * If DP RX thread is enabled, RX DHCP packets are enqueue into
+	 * DP RX thread queue, defer DHCP inspection until host has
+	 * resumed entirely, no issue to send DHCP indication MSG.
+	 * If DP RX thread is disabled, DHCP inspection happens earlier,
+	 * skip sending DHCP indication MSG if host has not resumed.
+	 */
+	if (qdf_unlikely(!dp_intf->dp_ctx->enable_dp_rx_threads &&
+			 dp_intf->dp_ctx->is_suspend)) {
+		dp_err_rl("Device is system suspended, skip DHCP Ind");
+		return QDF_STATUS_E_INVAL;
+	}
+
 	sb_ops = &dp_intf->dp_ctx->sb_ops;
 	msg.dhcp_start = dhcp_start;
 	msg.device_mode = dp_intf->device_mode;
@@ -322,7 +335,9 @@ int dp_softap_inspect_dhcp_packet(struct wlan_dp_link *dp_link,
 						sta_info->sta_mac.bytes,
 						true);
 			sta_info->dhcp_phase = DHCP_PHASE_DISCOVER;
-			sta_info->dhcp_nego_status = DHCP_NEGO_IN_PROGRESS;
+			if (QDF_IS_STATUS_SUCCESS(errno))
+				sta_info->dhcp_nego_status =
+						DHCP_NEGO_IN_PROGRESS;
 			break;
 		case QDF_PROTO_DHCP_OFFER:
 			sta_info->dhcp_phase = DHCP_PHASE_OFFER;
@@ -335,7 +350,9 @@ int dp_softap_inspect_dhcp_packet(struct wlan_dp_link *dp_link,
 						dp_link,
 						sta_info->sta_mac.bytes,
 						true);
-			sta_info->dhcp_nego_status = DHCP_NEGO_IN_PROGRESS;
+			if (QDF_IS_STATUS_SUCCESS(errno))
+				sta_info->dhcp_nego_status =
+						DHCP_NEGO_IN_PROGRESS;
 			fallthrough;
 		case QDF_PROTO_DHCP_DECLINE:
 			if (dir == QDF_RX)

+ 46 - 10
components/mlme/core/inc/wlan_mlme_main.h

@@ -774,6 +774,7 @@ struct enhance_roam_info {
  * @bss_color_change_wakelock: wakelock to complete bss color change
  *				operation on bss color collision detection
  * @bss_color_change_runtime_lock: runtime lock to complete bss color change
+ * @disconnect_runtime_lock: runtime lock to complete disconnection
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -844,6 +845,7 @@ struct mlme_legacy_priv {
 #endif
 	qdf_wake_lock_t bss_color_change_wakelock;
 	qdf_runtime_lock_t bss_color_change_runtime_lock;
+	qdf_runtime_lock_t disconnect_runtime_lock;
 };
 
 /**
@@ -1159,6 +1161,22 @@ QDF_STATUS wlan_mlme_get_bssid_vdev_id(struct wlan_objmgr_pdev *pdev,
 				       uint8_t vdev_id,
 				       struct qdf_mac_addr *bss_peer_mac);
 
+/**
+ * mlme_update_freq_in_scan_start_req() - Fill frequencies in wide
+ * band scan req for mlo connection
+ * @vdev: vdev common object
+ * @req: pointer to scan request
+ * @scan_ch_width: Channel width for which to trigger a wide band scan
+ * @scan_freq: frequency for which to trigger a wide band RRM scan
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev,
+				   struct scan_start_request *req,
+				   enum phy_ch_width scan_ch_width,
+				   qdf_freq_t scan_freq);
+
 /**
  * wlan_get_operation_chan_freq() - get operating chan freq of
  * given vdev
@@ -1179,16 +1197,6 @@ qdf_freq_t wlan_get_operation_chan_freq(struct wlan_objmgr_vdev *vdev);
 qdf_freq_t wlan_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev,
 						uint8_t vdev_id);
 
-/**
- * wlan_get_opmode_vdev_id() - get operating mode of given vdev id
- * @pdev: Pointer to pdev
- * @vdev_id: vdev id
- *
- * Return: opmode
- */
-enum QDF_OPMODE wlan_get_opmode_vdev_id(struct wlan_objmgr_pdev *pdev,
-					uint8_t vdev_id);
-
 /**
  * wlan_vdev_set_dot11mode - Set the dot11mode of the vdev
  * @mac_mlme_cfg: MAC's MLME config pointer
@@ -1674,6 +1682,20 @@ wlan_set_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev, bool value)
 }
 #endif
 
+/**
+ * wlan_mlme_get_sta_num_tx_chains() - API to get station num tx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @tx_chains : tx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+QDF_STATUS
+wlan_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *tx_chains);
+
 /**
  * wlan_mlme_get_sta_tx_nss() - API to get station tx NSS
  *
@@ -1688,6 +1710,20 @@ wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc,
 			 struct wlan_objmgr_vdev *vdev,
 			 uint8_t *tx_nss);
 
+/**
+ * wlan_mlme_get_sta_num_rx_chains() - API to get station num rx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @rx_chains : rx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+QDF_STATUS
+wlan_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *rx_chains);
+
 /**
  * wlan_mlme_get_sta_rx_nss() - API to get station rx NSS
  *

+ 118 - 37
components/mlme/core/src/wlan_mlme_main.c

@@ -36,6 +36,7 @@
 #include "twt/core/src/wlan_twt_cfg.h"
 #include "wlan_scan_api.h"
 #include "wlan_mlme_vdev_mgr_interface.h"
+#include "wlan_vdev_mgr_utils_api.h"
 
 #define NUM_OF_SOUNDING_DIMENSIONS     1 /*Nss - 1, (Nss = 2 for 2x2)*/
 
@@ -362,19 +363,11 @@ wlan_scan_get_scan_phy_mode(struct wlan_objmgr_vdev *vdev, qdf_freq_t op_freq,
 	return scan_phymode;
 }
 
-/**
- * mlme_update_freq_in_scan_start_req() - Fill frequencies in wide
- * band scan req for mlo connection
- * @vdev: vdev common object
- * @req: pointer to scan request
- * @associated_ch_width: channel width at the time of initial connection
- *
- * Return: QDF_STATUS
- */
-static QDF_STATUS
+QDF_STATUS
 mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev,
 				   struct scan_start_request *req,
-				   enum phy_ch_width associated_ch_width)
+				   enum phy_ch_width scan_ch_width,
+				   qdf_freq_t scan_freq)
 {
 	const struct bonded_channel_freq *range;
 	uint8_t num_chan;
@@ -383,14 +376,18 @@ mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev,
 	uint8_t vdev_id;
 
 	vdev_id = vdev->vdev_objmgr.vdev_id;
-	op_freq = wlan_get_operation_chan_freq(vdev);
 
-	mlme_debug("vdev %d : fill ch list for op_freq:%d, assoc_ch_width: %d",
-		   vdev_id, op_freq, associated_ch_width);
+	if (scan_freq != INVALID_CHANNEL)
+		op_freq = scan_freq;
+	else
+		op_freq = wlan_get_operation_chan_freq(vdev);
+
+	mlme_debug("vdev %d : fill ch list for op_freq:%d, scan_ch_width: %d",
+		   vdev_id, op_freq, scan_ch_width);
 
-	if (associated_ch_width == CH_WIDTH_320MHZ) {
+	if (scan_ch_width == CH_WIDTH_320MHZ) {
 		range = wlan_reg_get_bonded_chan_entry(op_freq,
-						       associated_ch_width, 0);
+						       scan_ch_width, 0);
 		if (!range) {
 			mlme_debug("vdev %d : range is null for freq %d",
 				   vdev_id, op_freq);
@@ -494,7 +491,8 @@ mlme_fill_freq_in_mlo_wide_band_scan_start_req(struct wlan_objmgr_vdev *vdev,
 			}
 
 			status = mlme_update_freq_in_scan_start_req(mlo_vdev,
-						req, associated_ch_width);
+						req, associated_ch_width,
+						INVALID_CHANNEL);
 			if (QDF_IS_STATUS_ERROR(status))
 				return QDF_STATUS_E_FAILURE;
 		}
@@ -552,7 +550,8 @@ mlme_fill_freq_in_wide_scan_start_request(struct wlan_objmgr_vdev *vdev,
 	}
 
 	status = mlme_update_freq_in_scan_start_req(vdev, req,
-						    associated_ch_width);
+						    associated_ch_width,
+						    INVALID_CHANNEL);
 	if (QDF_IS_STATUS_ERROR(status))
 		return QDF_STATUS_E_FAILURE;
 
@@ -4268,25 +4267,6 @@ qdf_freq_t wlan_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev,
 	return chan_freq;
 }
 
-enum QDF_OPMODE wlan_get_opmode_vdev_id(struct wlan_objmgr_pdev *pdev,
-					uint8_t vdev_id)
-{
-	enum QDF_OPMODE opmode = QDF_MAX_NO_OF_MODE;
-	struct wlan_objmgr_vdev *vdev;
-
-	if (!pdev)
-		return opmode;
-
-	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
-						    WLAN_LEGACY_MAC_ID);
-	if (!vdev)
-		return opmode;
-	opmode = wlan_vdev_mlme_get_opmode(vdev);
-	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
-
-	return opmode;
-}
-
 void wlan_vdev_set_dot11mode(struct wlan_mlme_cfg *mac_mlme_cfg,
 			     enum QDF_OPMODE device_mode,
 			     struct vdev_mlme_obj *vdev_mlme)
@@ -5157,6 +5137,57 @@ wlan_set_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev, bool value)
 }
 #endif
 
+QDF_STATUS wlan_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc,
+					   struct wlan_objmgr_vdev *vdev,
+					   uint8_t *tx_chains)
+{
+	bool dynamic_nss_chains_support;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	QDF_STATUS status;
+	struct vdev_mlme_obj *vdev_mlme;
+
+	status = wlan_mlme_cfg_get_dynamic_nss_chains_support
+					(psoc, &dynamic_nss_chains_support);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("Failed to get dynamic_nss_chains_support");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_mlme =
+		wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						      WLAN_UMAC_COMP_MLME);
+	if (!vdev_mlme) {
+		QDF_ASSERT(0);
+		return false;
+	}
+
+	if (dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			mlme_err("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		operating_band = ucfg_cm_get_connected_band(vdev);
+		switch (operating_band) {
+		case BAND_2G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			mlme_err("Band %d Not 2G or 5G", operating_band);
+			return QDF_STATUS_E_INVAL;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc,
 				    struct wlan_objmgr_vdev *vdev,
 				    uint8_t *tx_nss)
@@ -5204,6 +5235,56 @@ QDF_STATUS wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS wlan_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc,
+					   struct wlan_objmgr_vdev *vdev,
+					   uint8_t *rx_chains)
+{
+	bool dynamic_nss_chains_support;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	QDF_STATUS status;
+	struct vdev_mlme_obj *vdev_mlme;
+
+	status = wlan_mlme_cfg_get_dynamic_nss_chains_support
+					(psoc, &dynamic_nss_chains_support);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("Failed to get dynamic_nss_chains_support");
+		return QDF_STATUS_E_INVAL;
+	}
+	vdev_mlme =
+		wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						      WLAN_UMAC_COMP_MLME);
+	if (!vdev_mlme) {
+		QDF_ASSERT(0);
+		return false;
+	}
+
+	if (dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			mlme_err("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		operating_band = ucfg_cm_get_connected_band(vdev);
+		switch (operating_band) {
+		case BAND_2G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			mlme_err("Band %d Not 2G or 5G", operating_band);
+			return QDF_STATUS_E_INVAL;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS wlan_mlme_get_sta_rx_nss(struct wlan_objmgr_psoc *psoc,
 				    struct wlan_objmgr_vdev *vdev,
 				    uint8_t *rx_nss)

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

@@ -1561,6 +1561,8 @@ static void mlme_ext_handler_destroy(struct vdev_mlme_obj *vdev_mlme)
 		&vdev_mlme->ext_vdev_ptr->bss_color_change_runtime_lock);
 	qdf_wake_lock_destroy(
 		&vdev_mlme->ext_vdev_ptr->bss_color_change_wakelock);
+	qdf_runtime_lock_deinit(
+		&vdev_mlme->ext_vdev_ptr->disconnect_runtime_lock);
 	mlme_free_self_disconnect_ies(vdev_mlme->vdev);
 	mlme_free_peer_disconnect_ies(vdev_mlme->vdev);
 	mlme_free_sae_auth_retry(vdev_mlme->vdev);
@@ -1600,6 +1602,8 @@ QDF_STATUS vdevmgr_mlme_ext_hdl_create(struct vdev_mlme_obj *vdev_mlme)
 			"bss_color_change_wakelock");
 	qdf_runtime_lock_init(
 		&vdev_mlme->ext_vdev_ptr->bss_color_change_runtime_lock);
+	qdf_runtime_lock_init(
+		&vdev_mlme->ext_vdev_ptr->disconnect_runtime_lock);
 
 	sme_get_vdev_type_nss(wlan_vdev_mlme_get_opmode(vdev_mlme->vdev),
 			      &vdev_mlme->proto.generic.nss_2g,

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

@@ -420,6 +420,15 @@ wlan_mlme_set_ap_policy(struct wlan_objmgr_vdev *vdev,
 enum host_concurrent_ap_policy
 wlan_mlme_get_ap_policy(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * wlan_mlme_ll_lt_sap_send_oce_flags_fw() - Send the oce flags to FW for
+ * ll_lt_sap
+ * @vdev: pointer to vdev object
+ *
+ * Return: void
+ */
+void wlan_mlme_ll_lt_sap_send_oce_flags_fw(struct wlan_objmgr_vdev *vdev);
+
 /**
  * wlan_mlme_get_prevent_link_down() - Get the prevent link down config
  * @psoc: pointer to psoc object

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

@@ -3000,4 +3000,36 @@ enum ll_ap_type {
 	LL_AP_TYPE_LT = 1,
 	LL_AP_TYPE_ANY = 2,
 };
+
+/**
+ * struct sap_ch_info - Structure holding all the information required to make
+ * a decision for the best operating channel based on dfs formula.
+ * @chan_freq: Channel frequency found in scanresult
+ * @bss_count: Bss found in scanresult for this channel
+ * @rssi_agr: Max value of rssi among all BSS(es) from scan result
+ * for this channel.
+ * @weight: Weightage of this channel
+ * @weight_copy: copy of the original weight
+ * @valid: Is this a valid center frequency for regulatory domain
+ * @weight_calc_done: Weight calculation done for this channel
+ */
+struct sap_ch_info {
+	uint32_t chan_freq;
+	uint16_t bss_count;
+	int32_t rssi_agr;
+	uint32_t weight;
+	uint32_t weight_copy;
+	bool valid;
+	bool weight_calc_done;
+};
+
+/**
+ * struct sap_sel_ch_info - Wrapper of sap_ch_info structure.
+ * @ch_info: Ptr to the channel information.
+ * @num_ch: Total num of channels.
+ */
+struct sap_sel_ch_info {
+	struct sap_ch_info *ch_info;
+	uint8_t num_ch;
+};
 #endif

+ 37 - 1
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -2738,6 +2738,40 @@ ucfg_mlme_update_dynamic_nss_chains_support(struct wlan_objmgr_psoc *psoc,
 	return wlan_mlme_cfg_set_dynamic_nss_chains_support(psoc, val);
 }
 
+/**
+ * ucfg_mlme_get_sta_num_tx_chains() - UCFG API to get station num tx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @tx_chains : tx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+static inline QDF_STATUS
+ucfg_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *tx_chains)
+{
+	return wlan_mlme_get_sta_num_tx_chains(psoc, vdev, tx_chains);
+}
+
+/**
+ * ucfg_mlme_get_sta_num_rx_chains() - UCFG API to get station num rx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @rx_chains : rx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+static inline QDF_STATUS
+ucfg_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *rx_chains)
+{
+	return wlan_mlme_get_sta_num_rx_chains(psoc, vdev, rx_chains);
+}
+
 /**
  * ucfg_mlme_get_sta_tx_nss() - UCFG API to get station tx NSS
  *
@@ -4776,13 +4810,15 @@ QDF_STATUS ucfg_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc,
  * @psoc: pointer to psoc object
  * @vdev_id: Vdev id
  * @ch_width: channel width to update
+ * @link_id: mlo link id
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS
 ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 					   uint8_t vdev_id,
-					   enum phy_ch_width ch_width);
+					   enum phy_ch_width ch_width,
+					   uint8_t link_id);
 
 /**
  * ucfg_mlme_is_chwidth_with_notify_supported() - Get chwidth with notify

+ 52 - 10
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -353,6 +353,33 @@ wlan_mlme_convert_ap_policy_config(
 	}
 }
 
+void wlan_mlme_ll_lt_sap_send_oce_flags_fw(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc = NULL;
+	uint8_t vdev_id;
+	uint8_t updated_fw_value = 0;
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc)
+		return;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+
+	if (!mlme_obj)
+		return;
+
+	updated_fw_value = mlme_obj->cfg.oce.feature_bitmap;
+	vdev_id = wlan_vdev_get_id(vdev);
+	wma_debug("Disable FILS discovery for vdev %d",
+		  vdev_id);
+	updated_fw_value &= ~(WMI_VDEV_OCE_FILS_DISCOVERY_FRAME_FEATURE_BITMAP);
+	if (wma_cli_set_command(vdev_id,
+				wmi_vdev_param_enable_disable_oce_features,
+				updated_fw_value, VDEV_CMD))
+		mlme_legacy_err("Failed to send OCE update to FW");
+}
+
 QDF_STATUS wlan_mlme_set_ap_policy(struct wlan_objmgr_vdev *vdev,
 				   enum host_concurrent_ap_policy ap_cfg_policy)
 
@@ -820,7 +847,7 @@ QDF_STATUS mlme_update_tgt_he_caps_in_cfg(struct wlan_objmgr_psoc *psoc,
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	tDot11fIEhe_cap *he_cap = &wma_cfg->he_cap;
 	struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc);
-	uint8_t value;
+	uint8_t value, twt_req, twt_resp;
 	uint16_t tx_mcs_map = 0;
 	uint16_t rx_mcs_map = 0;
 	uint8_t nss;
@@ -831,9 +858,13 @@ QDF_STATUS mlme_update_tgt_he_caps_in_cfg(struct wlan_objmgr_psoc *psoc,
 	mlme_obj->cfg.he_caps.dot11_he_cap.present = 1;
 	mlme_obj->cfg.he_caps.dot11_he_cap.htc_he = he_cap->htc_he;
 
-	value = QDF_MIN(he_cap->twt_request,
-			mlme_obj->cfg.he_caps.dot11_he_cap.twt_request);
-	mlme_obj->cfg.he_caps.dot11_he_cap.twt_request = value;
+	twt_req = QDF_MIN(he_cap->twt_request,
+			  mlme_obj->cfg.he_caps.dot11_he_cap.twt_request);
+	mlme_obj->cfg.he_caps.dot11_he_cap.twt_request = twt_req;
+
+	twt_resp = QDF_MIN(he_cap->twt_responder,
+			   mlme_obj->cfg.he_caps.dot11_he_cap.twt_responder);
+	mlme_obj->cfg.he_caps.dot11_he_cap.twt_responder = twt_resp;
 
 	value = QDF_MIN(he_cap->fragmentation,
 			mlme_obj->cfg.he_caps.he_dynamic_fragmentation);
@@ -870,8 +901,16 @@ QDF_STATUS mlme_update_tgt_he_caps_in_cfg(struct wlan_objmgr_psoc *psoc,
 			mlme_obj->cfg.he_caps.dot11_he_cap.broadcast_twt);
 	mlme_obj->cfg.he_caps.dot11_he_cap.broadcast_twt = value;
 
-	mlme_obj->cfg.he_caps.dot11_he_cap.flex_twt_sched =
-			he_cap->flex_twt_sched;
+	/*
+	 * As per 802.11ax spec, Flexible TWT capability can be set
+	 * independent of TWT Requestor/Responder capability.
+	 * But currently we don't have any such usecase and firmware
+	 * does not support it. Hence enabling Flexible TWT only when
+	 * either or both of the TWT Requestor/Responder capability
+	 * is set/enabled.
+	 */
+	value = QDF_MIN(he_cap->flex_twt_sched, (twt_req || twt_resp));
+	mlme_obj->cfg.he_caps.dot11_he_cap.flex_twt_sched = value;
 
 	mlme_obj->cfg.he_caps.dot11_he_cap.ba_32bit_bitmap =
 					he_cap->ba_32bit_bitmap;
@@ -6933,7 +6972,7 @@ void wlan_mlme_get_feature_info(struct wlan_objmgr_psoc *psoc,
 	wlan_mlme_get_sap_max_peers(psoc, &sap_max_num_clients);
 	mlme_feature_set->sap_max_num_clients = sap_max_num_clients;
 	mlme_feature_set->vendor_req_1_version =
-					WMI_HOST_VENDOR1_REQ1_VERSION_3_40;
+					WMI_HOST_VENDOR1_REQ1_VERSION_4_00;
 	roam_triggers = wlan_mlme_get_roaming_triggers(psoc);
 
 	wlan_mlme_get_bss_load_enabled(psoc, &is_bss_load_enabled);
@@ -6966,7 +7005,7 @@ void wlan_mlme_get_feature_info(struct wlan_objmgr_psoc *psoc,
 	mlme_feature_set->roaming_ctrl_get_cu = true;
 
 	mlme_feature_set->vendor_req_2_version =
-					WMI_HOST_VENDOR1_REQ2_VERSION_3_20;
+					WMI_HOST_VENDOR1_REQ2_VERSION_3_50;
 	mlme_feature_set->sta_dual_p2p_support =
 				wlan_mlme_get_p2p_p2p_host_conc_support();
 	wlan_mlme_get_vht_enable2x2(psoc, &mlme_feature_set->enable2x2);
@@ -6988,7 +7027,7 @@ static QDF_STATUS
 wlan_mlme_update_vdev_chwidth_with_notify(struct wlan_objmgr_psoc *psoc,
 					  struct wlan_objmgr_vdev *vdev,
 					  uint8_t vdev_id,
-					  enum phy_ch_width ch_width)
+					  wmi_host_channel_width ch_width)
 {
 	struct vdev_mlme_obj *vdev_mlme;
 	struct vdev_set_params param = {0};
@@ -7254,6 +7293,7 @@ wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 					   enum phy_ch_width ch_width)
 {
 	QDF_STATUS status;
+	wmi_host_channel_width wmi_chan_width;
 	enum phy_ch_width associated_ch_width;
 	struct wlan_channel *des_chan;
 	struct mlme_legacy_priv *mlme_priv;
@@ -7289,9 +7329,11 @@ wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 		return status;
 	}
 
+	wmi_chan_width = target_if_phy_ch_width_to_wmi_chan_width(ch_width);
+
 	/* update ch width to fw */
 	status = wlan_mlme_update_vdev_chwidth_with_notify(psoc, vdev, vdev_id,
-							   ch_width);
+							   wmi_chan_width);
 	if (QDF_IS_STATUS_ERROR(status))
 		mlme_err("vdev %d: Failed to update CW:%d to fw, status:%d",
 			 vdev_id, ch_width, status);

+ 28 - 9
components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c

@@ -396,12 +396,15 @@ QDF_STATUS ucfg_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS
 ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 					   uint8_t vdev_id,
-					   enum phy_ch_width ch_width)
+					   enum phy_ch_width ch_width,
+					   uint8_t link_id)
 {
 	struct wlan_objmgr_vdev *vdev;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	enum QDF_OPMODE op_mode;
-	bool is_mlo_vdev;
+	struct wlan_objmgr_vdev *link_vdev;
+	bool is_mlo_link = false;
+	uint8_t link_vdev_id;
 
 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
 						    WLAN_MLME_OBJMGR_ID);
@@ -411,16 +414,32 @@ ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 	}
 
 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
-	is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev);
-	if (op_mode != QDF_STA_MODE || is_mlo_vdev) {
-		mlme_legacy_debug("vdev %d: op mode %d, is_mlo_vdev:%d, CW update not supported",
-				  vdev_id, op_mode, is_mlo_vdev);
+	if (op_mode != QDF_STA_MODE) {
+		mlme_legacy_debug("vdev %d: op mode %d, CW update not supported",
+				  vdev_id, op_mode);
 		status = QDF_STATUS_E_NOSUPPORT;
 		goto release;
 	}
 
-	status = wlan_mlme_send_ch_width_update_with_notify(psoc, vdev,
-							    vdev_id, ch_width);
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev) && link_id != 0xFF) {
+		link_vdev = mlo_get_vdev_by_link_id(vdev, link_id);
+		if (!link_vdev) {
+			mlme_legacy_debug("vdev is null for the link id:%u",
+					  link_id);
+			goto release;
+		}
+		is_mlo_link = true;
+		link_vdev_id = wlan_vdev_get_id(link_vdev);
+	} else {
+		link_vdev = vdev;
+		link_vdev_id = vdev_id;
+		mlme_legacy_debug("vdev mlme is not mlo vdev");
+	}
+	status = wlan_mlme_send_ch_width_update_with_notify(psoc, link_vdev,
+							    link_vdev_id,
+							    ch_width);
+	if (is_mlo_link)
+		mlo_release_vdev_ref(link_vdev);
 
 release:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);

+ 1 - 2
components/nan/core/src/nan_main.c

@@ -1256,8 +1256,7 @@ QDF_STATUS nan_discovery_pre_enable(struct wlan_objmgr_pdev *pdev,
 		goto pre_enable_failure;
 	}
 
-	if (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE,
-						      NULL) &&
+	if ((policy_mgr_get_sap_mode_count(psoc, NULL)) &&
 	    !policy_mgr_nan_sap_pre_enable_conc_check(psoc, PM_NAN_DISC_MODE,
 						      nan_ch_freq)) {
 		nan_debug("NAN not enabled due to concurrency constraints");

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

@@ -44,6 +44,8 @@
 #include "cdp_txrx_bus.h"
 #include "wlan_pmo_ucfg_api.h"
 #include "hif.h"
+#include "target_type.h"
+
 /**
  * pmo_core_get_vdev_dtim_period() - Get vdev dtim period
  * @vdev: objmgr vdev handle
@@ -492,15 +494,25 @@ static QDF_STATUS pmo_core_psoc_configure_suspend(struct wlan_objmgr_psoc *psoc,
 						  bool is_runtime_pm)
 {
 	struct pmo_psoc_priv_obj *psoc_ctx;
+	struct hif_target_info *tgt_info;
+	struct hif_opaque_softc *hif_ctx;
 
 	psoc_ctx = pmo_psoc_get_priv(psoc);
 
 	if (is_runtime_pm)
 		pmo_core_enable_runtime_pm_offloads(psoc);
 
+	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
+	if (!hif_ctx) {
+		pmo_err("Invalid hif ctx");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tgt_info = hif_get_target_info_handle(hif_ctx);
+
 	if ((is_runtime_pm) ||
 	    (psoc_ctx->psoc_cfg.suspend_mode == PMO_SUSPEND_WOW &&
-	    pmo_core_is_wow_applicable(psoc))) {
+	    ((tgt_info->target_type == TARGET_TYPE_QCA6490) ||
+	    pmo_core_is_wow_applicable(psoc)))) {
 		pmo_debug("WOW Suspend");
 		pmo_core_apply_lphb(psoc);
 		/*

+ 16 - 8
components/tdls/core/src/wlan_tdls_ct.c

@@ -549,6 +549,16 @@ int tdls_recv_discovery_resp(struct tdls_vdev_priv_obj *tdls_vdev,
 		   QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
 		   curr_peer->link_status);
 
+	/* Since peer link status bases on vdev and stream goes through
+	 * vdev0 (assoc link) at start, rx/tx pkt count on vdev0, but
+	 * it choices vdev1 as tdls link, the peer status does not change on
+	 * vdev1 though it has been changed for vdev0 per the rx/tx pkt count.
+	 */
+	if (wlan_vdev_mlme_is_mlo_vdev(tdls_vdev->vdev) &&
+	    curr_peer->link_status == TDLS_LINK_IDLE)
+		tdls_set_peer_link_status(curr_peer, TDLS_LINK_DISCOVERING,
+					  TDLS_LINK_SUCCESS);
+
 	tdls_cfg = &tdls_vdev->threshold_config;
 	if (TDLS_LINK_DISCOVERING == curr_peer->link_status) {
 		/* Since we are here, it means Throughput threshold is
@@ -865,11 +875,11 @@ static void tdls_ct_process_cap_supported(struct tdls_peer *curr_peer,
 					struct tdls_soc_priv_obj *tdls_soc_obj)
 {
 	if (curr_peer->rx_pkt || curr_peer->tx_pkt)
-		tdls_debug(QDF_MAC_ADDR_FMT "link_status %d tdls_support %d tx %d rx %d rssi %d",
+		tdls_debug(QDF_MAC_ADDR_FMT "link_status %d tdls_support %d tx %d rx %d rssi %d vdev %d",
 			   QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
 			   curr_peer->link_status, curr_peer->tdls_support,
 			   curr_peer->tx_pkt, curr_peer->rx_pkt,
-			   curr_peer->rssi);
+			   curr_peer->rssi, wlan_vdev_get_id(tdls_vdev->vdev));
 
 	switch (curr_peer->link_status) {
 	case TDLS_LINK_IDLE:
@@ -910,10 +920,11 @@ static void tdls_ct_process_cap_unknown(struct tdls_peer *curr_peer,
 			return;
 
 	if (curr_peer->rx_pkt || curr_peer->tx_pkt)
-		tdls_debug(QDF_MAC_ADDR_FMT "link_status %d tdls_support %d tx %d rx %d",
+		tdls_debug(QDF_MAC_ADDR_FMT "link_status %d tdls_support %d tx %d rx %d vdev %d",
 			   QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
 			   curr_peer->link_status, curr_peer->tdls_support,
-			   curr_peer->tx_pkt, curr_peer->rx_pkt);
+			   curr_peer->tx_pkt, curr_peer->rx_pkt,
+			   wlan_vdev_get_id(tdls_vdev->vdev));
 
 	if (!TDLS_IS_LINK_CONNECTED(curr_peer) &&
 	    ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
@@ -1025,7 +1036,7 @@ void tdls_ct_handler(void *user_data)
 	if (!user_data)
 		return;
 
-	vdev = tdls_get_vdev(user_data, WLAN_TDLS_NB_ID);
+	vdev = (struct wlan_objmgr_vdev *)user_data;
 	if (!vdev)
 		return;
 
@@ -1040,9 +1051,6 @@ void tdls_ct_handler(void *user_data)
 	} else {
 		tdls_ct_process_handler(vdev);
 	}
-
-	wlan_objmgr_vdev_release_ref(vdev,
-				     WLAN_TDLS_NB_ID);
 }
 
 int tdls_set_tdls_offchannel(struct tdls_soc_priv_obj *tdls_soc,

+ 1 - 1
components/tdls/core/src/wlan_tdls_main.c

@@ -205,7 +205,7 @@ static QDF_STATUS tdls_vdev_init(struct tdls_vdev_priv_obj *vdev_obj)
 				WLAN_TDLS_PEER_SUB_LIST_SIZE);
 	}
 	qdf_mc_timer_init(&vdev_obj->peer_update_timer, QDF_TIMER_TYPE_SW,
-			  tdls_ct_handler, soc_obj->soc);
+			  tdls_ct_handler, vdev_obj->vdev);
 	qdf_mc_timer_init(&vdev_obj->peer_discovery_timer, QDF_TIMER_TYPE_SW,
 			  tdls_discovery_timeout_peer_cb, vdev_obj->vdev);
 

+ 42 - 33
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -4713,10 +4713,8 @@ cm_mlo_roam_switch_for_link(struct wlan_objmgr_pdev *pdev,
 }
 
 QDF_STATUS
-cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev,
-			       uint8_t *vdev_id,
-			       uint8_t reason,
-			       bool *is_rso_skip)
+cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev, uint8_t *vdev_id,
+			       uint8_t reason, bool *is_rso_skip)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct wlan_objmgr_vdev *vdev;
@@ -4728,10 +4726,23 @@ cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev,
 	if (!vdev)
 		return QDF_STATUS_E_FAILURE;
 
+	/*
+	 * When link switch is in progress, the MLO link flag would be reset and
+	 * set back on assoc vdev, so avoid any state transition during link
+	 * switch.
+	 */
+	if (wlan_vdev_mlme_get_is_mlo_vdev(psoc, *vdev_id) &&
+	    mlo_mgr_is_link_switch_in_progress(vdev)) {
+		mlme_debug("MLO ROAM: Link switch in prog! skip RSO cmd on vdev %d",
+			   *vdev_id);
+		*is_rso_skip = true;
+		goto end;
+	}
+
 	if (wlan_vdev_mlme_get_is_mlo_vdev(psoc, *vdev_id) &&
+	    cm_is_vdev_disconnecting(vdev) &&
 	    (reason == REASON_DISCONNECTED ||
-	     reason == REASON_DRIVER_DISABLED) &&
-	    cm_is_vdev_disconnecting(vdev)) {
+	     reason == REASON_DRIVER_DISABLED)) {
 		/*
 		 * Processing disconnect on assoc vdev but roaming is still
 		 * enabled. It's either due to single ML usecase or failed to
@@ -4749,36 +4760,34 @@ cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev,
 		}
 	}
 
-	if (wlan_vdev_mlme_get_is_mlo_link(wlan_pdev_get_psoc(pdev),
-					   *vdev_id)) {
-		if (reason == REASON_ROAM_HANDOFF_DONE ||
-		    reason == REASON_ROAM_ABORT) {
-			status = cm_mlo_roam_switch_for_link(pdev, *vdev_id,
-							     reason);
-			mlme_debug("MLO ROAM: update rso state on link vdev %d",
-				   *vdev_id);
+	if (!wlan_vdev_mlme_get_is_mlo_link(wlan_pdev_get_psoc(pdev),
+					    *vdev_id))
+		goto end;
+
+	if (reason == REASON_ROAM_HANDOFF_DONE || reason == REASON_ROAM_ABORT) {
+		status = cm_mlo_roam_switch_for_link(pdev, *vdev_id, reason);
+		mlme_debug("MLO ROAM: update rso state on link vdev %d",
+			   *vdev_id);
 			*is_rso_skip = true;
-		} else if ((reason == REASON_DISCONNECTED ||
-			    reason == REASON_DRIVER_DISABLED) &&
-			   (cm_is_vdev_disconnecting(vdev))) {
-			assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
-
-			if (!assoc_vdev) {
-				mlme_err("Assoc vdev is NULL");
-				status = QDF_STATUS_E_FAILURE;
-				goto end;
-			}
-			/* Update the vdev id to send RSO stop on assoc vdev */
-			*vdev_id = wlan_vdev_get_id(assoc_vdev);
-			*is_rso_skip = false;
-			mlme_debug("MLO ROAM: process RSO stop on assoc vdev %d",
-				   *vdev_id);
+	} else if ((reason == REASON_DISCONNECTED ||
+		    reason == REASON_DRIVER_DISABLED) &&
+		   cm_is_vdev_disconnecting(vdev)) {
+		assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
+
+		if (!assoc_vdev) {
+			mlme_err("Assoc vdev is NULL");
+			status = QDF_STATUS_E_FAILURE;
 			goto end;
-		} else {
-			mlme_debug("MLO ROAM: skip RSO cmd on link vdev %d",
-				   *vdev_id);
-			*is_rso_skip = true;
 		}
+		/* Update the vdev id to send RSO stop on assoc vdev */
+		*vdev_id = wlan_vdev_get_id(assoc_vdev);
+		*is_rso_skip = false;
+		mlme_debug("MLO ROAM: process RSO stop on assoc vdev %d",
+			   *vdev_id);
+		goto end;
+	} else {
+		mlme_debug("MLO ROAM: skip RSO cmd on link vdev %d", *vdev_id);
+		*is_rso_skip = true;
 	}
 end:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID);

+ 3 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h

@@ -756,13 +756,15 @@ cm_send_rso_stop(struct wlan_objmgr_vdev *vdev)
 #ifdef WLAN_FEATURE_11BE_MLO
 /**
  * cm_get_ml_partner_info() - Fill ML partner info from scan entry
+ * @pdev: PDEV object
  * @scan_entry: Scan entry
  * @partner_info: Partner info to be filled
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS
-cm_get_ml_partner_info(struct scan_cache_entry *scan_entry,
+cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev,
+		       struct scan_cache_entry *scan_entry,
 		       struct mlo_partner_info *partner_info);
 #endif
 #endif /* __WLAN_CM_VDEV_API_H__ */

+ 28 - 4
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c

@@ -1125,12 +1125,16 @@ QDF_STATUS cm_flush_join_req(struct scheduler_msg *msg)
 
 #ifdef WLAN_FEATURE_11BE_MLO
 QDF_STATUS
-cm_get_ml_partner_info(struct scan_cache_entry *scan_entry,
+cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev,
+		       struct scan_cache_entry *scan_entry,
 		       struct mlo_partner_info *partner_info)
 {
 	uint8_t i, j = 0;
 	uint8_t mlo_support_link_num;
 	struct wlan_objmgr_psoc *psoc;
+	struct scan_cache_entry *part_scan_entry = NULL;
+	bool is_security_allowed;
+	struct qdf_mac_addr *link_mac;
 
 	/* If ML IE is not present then return failure*/
 	if (!scan_entry->ie_list.multi_link_bv)
@@ -1140,9 +1144,9 @@ cm_get_ml_partner_info(struct scan_cache_entry *scan_entry,
 	if (!scan_entry->ml_info.num_links)
 		return QDF_STATUS_SUCCESS;
 
-	psoc = wlan_objmgr_get_psoc_by_id(0, WLAN_MLME_CM_ID);
+	psoc = wlan_pdev_get_psoc(pdev);
 	if (!psoc) {
-		mlme_debug("psoc is NULL");
+		mlme_err("psoc is NULL");
 		return QDF_STATUS_E_INVAL;
 	}
 
@@ -1167,6 +1171,27 @@ cm_get_ml_partner_info(struct scan_cache_entry *scan_entry,
 			break;
 
 		if (scan_entry->ml_info.link_info[i].is_valid_link) {
+			link_mac = &scan_entry->ml_info.link_info[i].link_addr;
+			part_scan_entry = wlan_scan_get_scan_entry_by_mac_freq(
+					pdev,
+					link_mac,
+					scan_entry->ml_info.link_info[i].freq);
+			if (!part_scan_entry) {
+				scm_debug("scan entry not found for link addr: "
+					  QDF_MAC_ADDR_FMT,
+					  QDF_MAC_ADDR_REF(link_mac->bytes));
+				continue;
+			}
+
+			is_security_allowed =
+				wlan_cm_is_eht_allowed_for_current_security(
+							part_scan_entry);
+			util_scan_free_cache_entry(part_scan_entry);
+			if (!is_security_allowed) {
+				mlme_debug("current security is not valid for partner link");
+				continue;
+			}
+
 			partner_info->partner_link_info[j].link_addr =
 				scan_entry->ml_info.link_info[i].link_addr;
 			partner_info->partner_link_info[j].link_id =
@@ -1182,7 +1207,6 @@ cm_get_ml_partner_info(struct scan_cache_entry *scan_entry,
 
 	partner_info->num_partner_links = j;
 	mlme_debug("sta and ap integrate link num: %d", j);
-	wlan_objmgr_psoc_release_ref(psoc, WLAN_MLME_CM_ID);
 
 	return QDF_STATUS_SUCCESS;
 }

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

@@ -45,6 +45,31 @@ const char *t2lm_get_event_str(enum wlan_t2lm_evt event)
 	}
 }
 
+static
+uint16_t t2lm_get_connected_link_id(struct wlan_objmgr_vdev *vdev)
+{
+	uint16_t ieee_link_mask = 0;
+	uint8_t i, link_id;
+	struct mlo_link_info *link_info = NULL;
+
+	if (!vdev->mlo_dev_ctx) {
+		t2lm_err("MLO dev context failed");
+		return false;
+	}
+
+	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
+
+	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
+		link_id = link_info[i].link_id;
+		if (link_id == WLAN_INVALID_LINK_ID)
+			continue;
+
+		ieee_link_mask |= BIT(link_id);
+	}
+
+	return ieee_link_mask;
+}
+
 static
 bool t2lm_is_valid_t2lm_link_map(struct wlan_objmgr_vdev *vdev,
 				 struct wlan_t2lm_onging_negotiation_info *t2lm,
@@ -55,31 +80,8 @@ bool t2lm_is_valid_t2lm_link_map(struct wlan_objmgr_vdev *vdev,
 	uint16_t ieee_link_mask = 0;
 	uint16_t provisioned_links = 0;
 	bool is_valid_link_mask = false;
-	struct wlan_objmgr_vdev *ml_vdev = NULL;
-	struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
-	uint16_t ml_vdev_cnt = 0;
-
-	/* Get the valid hw_link_id map from ML vdev list */
-	mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list);
-	if (!ml_vdev_cnt) {
-		t2lm_err("Number of VDEVs under MLD is reported as 0");
-		return false;
-	}
 
-	for (i = 0; i < ml_vdev_cnt; i++) {
-		ml_vdev = ml_vdev_list[i];
-		if (!ml_vdev || !wlan_cm_is_vdev_connected(ml_vdev)) {
-			t2lm_err("ML vdev is null");
-			continue;
-		}
-
-		ieee_link_mask |= BIT(wlan_vdev_get_link_id(ml_vdev));
-	}
-
-	if (ml_vdev_cnt) {
-		for (i = 0; i < ml_vdev_cnt; i++)
-			mlo_release_vdev_ref(ml_vdev_list[i]);
-	}
+	ieee_link_mask = t2lm_get_connected_link_id(vdev);
 
 	/* Check if the configured hw_link_id map is valid */
 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {

+ 4 - 0
configs/config_to_feature.h

@@ -2907,4 +2907,8 @@
 #define WLAN_TRACE_HIDE_MAC_ADDRESS (1)
 #endif
 
+#ifdef CONFIG_ENABLE_HAL_REG_WR_HISTORY
+#define ENABLE_HAL_REG_WR_HISTORY (1)
+#endif
+
 #endif /* CONFIG_TO_FEATURE_H */

+ 2 - 1
configs/default_defconfig

@@ -184,6 +184,7 @@ ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM)))
 	CONFIG_SYSTEM_PM_CHECK := y
 	CONFIG_DISABLE_EAPOL_INTRABSS_FWD := y
 	CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER := y
+	CONFIG_BCN_RATECODE_ENABLE := y
 endif
 
 ifeq ($(CONFIG_LITHIUM), y)
@@ -668,7 +669,7 @@ CONFIG_OL_RX_INDICATION_RECORD := y
 CONFIG_TSOSEG_DEBUG := y
 CONFIG_HIF_LARGE_CE_RING_HISTORY := 8192
 endif
-
+CONFIG_FEATURE_ENABLE_CE_DP_IRQ_AFFINE := y
 endif #CONFIG_HELIUMPLUS
 
 ifeq ($(CONFIG_LITHIUM), y)

+ 1 - 2
configs/pineapple_gki_kiwi-v2_defconfig

@@ -222,7 +222,6 @@ CONFIG_WLAN_DEBUGFS=y
 CONFIG_WLAN_DFS_MASTER_ENABLE=y
 CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y
 CONFIG_WLAN_DIAG_VERSION=y
-CONFIG_WLAN_DISABLE_EXPORT_SYMBOL=y
 CONFIG_WLAN_DL_MODES=y
 CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y
 CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y
@@ -328,6 +327,7 @@ CONFIG_WLAN_SYSFS_TDLS_PEERS=y
 CONFIG_WLAN_SYSFS_TEMPERATURE=y
 CONFIG_WLAN_SYSFS_TX_STBC=y
 CONFIG_WLAN_SYSFS_WLAN_DBG=y
+CONFIG_WLAN_SYSFS_BITRATES=y
 CONFIG_WLAN_THERMAL_CFG=y
 CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y
 CONFIG_WLAN_TRACEPOINTS=y
@@ -358,7 +358,6 @@ CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y
 CONFIG_WLAN_CTRL_NAME="wlan"
 CONFIG_MULTI_IF_NAME="kiwi_v2"
 CONFIG_NL80211_TESTMODE=y
-CONFIG_QCA_WIFI_FTM_IOCTL=y
 CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y
 CONFIG_WLAN_HOST_ARCH_ARM=y
 CONFIG_ARCH_MSM=y

+ 2 - 0
configs/qca6174_defconfig

@@ -725,6 +725,8 @@ CONFIG_SM_ENG_HIST := n
 #Enable Beacon Reception Stats
 ifeq ($(CONFIG_WLAN_SYSFS), y)
 CONFIG_FEATURE_BECN_STATS := y
+CONFIG_WLAN_WOWL_ADD_PTRN := y
+CONFIG_WLAN_WOWL_DEL_PTRN := y
 endif
 
 ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM)))

+ 1 - 0
configs/qca6390_defconfig

@@ -726,6 +726,7 @@ endif
 	CONFIG_UNIT_TEST := y
 	CONFIG_HAL_DEBUG := y
 	CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE := y
+	CONFIG_HIF_DEBUG := y
 endif
 
 ifeq ($(CONFIG_UNIT_TEST), y)

+ 1 - 0
configs/wcn6450_defconfig

@@ -93,6 +93,7 @@ CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE := y
 CONFIG_WIFI_MONITOR_SUPPORT := y
 CONFIG_QCA_MONITOR_PKT_SUPPORT := y
 CONFIG_MONITOR_MODULARIZED_ENABLE := n
+CONFIG_DP_CON_MON_MSI_ENABLED := y
 
 ifneq ($(CONFIG_MOBILE_ROUTER), y)
 #Flag to enable TDLS feature

+ 5 - 1
core/hdd/inc/hdd_config.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-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
@@ -193,8 +193,12 @@ enum hdd_dot11_mode {
 #ifdef QCA_WIFI_EMULATION
 #define CFG_INTERFACE_CHANGE_WAIT_DEFAULT	300000
 #else
+#ifdef SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND
+#define CFG_INTERFACE_CHANGE_WAIT_DEFAULT	10000
+#else
 #define CFG_INTERFACE_CHANGE_WAIT_DEFAULT	250
 #endif
+#endif
 
 /*
  * <ini>

+ 32 - 3
core/hdd/inc/hdd_dp_cfg.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2020 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
@@ -443,7 +443,7 @@
  * gWmiCreditCount - Credit count for WMI exchange
  * @0: Not allowed
  * @1: Serialize WMI commands, 1 command at a time
- * @Default: 2: As advertized by FW
+ * @Default: 2: As advertised by FW
  *
  * This ini is used to serialize the WMI commandsif required.
  *
@@ -479,9 +479,38 @@
 #define CFG_HDD_DP_LEGACY_TX_FLOW
 #endif
 
+#ifdef FEATURE_ENABLE_CE_DP_IRQ_AFFINE
+/*
+ * <ini>
+ * Enable_ce_dp_irq_affine - Enable/disable affinity on datapath CE IRQs
+ *
+ * @Min: 0
+ * @Max: 1
+ * Default: 0
+ *
+ * This ini param is used to enable/disable the affinity on datapath
+ * Copy Engine IRQs.
+ *
+ * Supported Feature: STA/SAP
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_CE_DP_IRQ_AFFINE CFG_INI_BOOL(\
+			"Enable_ce_dp_irq_affine", \
+			0, \
+			"Enable/disable irq affinity on datapath CEs")
+#define CFG_ENABLE_CE_DP_IRQ_AFFINE_ALL \
+	CFG(CFG_ENABLE_CE_DP_IRQ_AFFINE)
+#else
+#define CFG_ENABLE_CE_DP_IRQ_AFFINE_ALL
+#endif
+
 #define CFG_HDD_DP_ALL \
 	CFG(CFG_DP_NAPI_CE_CPU_MASK) \
 	CFG(CFG_DP_HTC_WMI_CREDIT_CNT) \
 	CFG_MSCS_FEATURE_ALL \
-	CFG_HDD_DP_LEGACY_TX_FLOW
+	CFG_HDD_DP_LEGACY_TX_FLOW \
+	CFG_ENABLE_CE_DP_IRQ_AFFINE_ALL
 #endif

+ 23 - 6
core/hdd/inc/hdd_sar_safety_config.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -25,6 +26,16 @@
 
 #ifdef SAR_SAFETY_FEATURE
 
+/*
+ * SAR_SAFETY_DISABLED - feature disabled
+ * SAR_SAFETY_ENABLED_TIMER - SAR feature enabled with timer mechanism
+ * SAR_SAFETY_ENABLED_INIT - SAR feature enabled at init time
+ * SAR_SAFETY_ENABLED_MAX - SAR max valid value
+ */
+#define SAR_SAFETY_DISABLED        0x0
+#define SAR_SAFETY_ENABLED_TIMER   BIT(0)
+#define SAR_SAFETY_ENABLED_INIT    BIT(1)
+#define SAR_SAFETY_ENABLED_MAX     0x3
 /*
  * <ini>
  * gSarSafetyTimeout - Specify SAR safety timeout value in milliseconds
@@ -198,24 +209,30 @@
 /*
  * <ini>
  * gEnableSarSafety - Enable/Disable SAR safety feature
+ * this ini is also used to set SAR index at init time
  *
  * @Min: 0
- * @Max: 1
+ * @Max: 3
  * Default: 0
  *
  * This ini is used to enable/disable SAR safety feature
- * Value 1 of this ini enables SAR safety feature and
- * value 0 of this ini disables SAR safety feature
+ * Value 0 of this ini disables SAR safety feature and
+ * value 1 of this ini enables SAR safety feature and
+ * value 2 of this ini enable setting SAR index at init time
+ * value 3 of this enables both modes
  *
  * Usage: External
  *
  * </ini>
  */
 
-#define CFG_ENABLE_SAR_SAFETY_FEATURE CFG_INI_BOOL( \
+#define CFG_ENABLE_SAR_SAFETY_FEATURE CFG_INI_UINT( \
 			"gEnableSarSafety", \
-			0, \
-			"Enable/Disable SAR safety feature")
+			SAR_SAFETY_DISABLED, \
+			SAR_SAFETY_ENABLED_MAX, \
+			SAR_SAFETY_DISABLED, \
+			CFG_VALUE_OR_DEFAULT, \
+			"Enable/Disable SAR safety feature type")
 
 /*
  * <ini>

+ 43 - 2
core/hdd/inc/wlan_hdd_cfg.h

@@ -191,7 +191,7 @@ struct hdd_config {
 	uint32_t sar_safety_req_resp_retry;
 	uint32_t sar_safety_index;
 	uint32_t sar_safety_sleep_index;
-	bool enable_sar_safety;
+	uint8_t enable_sar_safety;
 	bool config_sar_safety_sleep_index;
 #endif
 	uint8_t nb_commands_interval;
@@ -268,6 +268,19 @@ void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx);
 QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
 			  uint8_t tx_nss, uint8_t rx_nss);
 
+/**
+ * hdd_get_num_chains() - Get the number of chains supported by the adapter
+ *
+ * @adapter: the pointer to adapter
+ * @num_chains: the number of chains supported by the adapter
+ *
+ * This function is used to get the number of chains supported by
+ * the adapter.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_get_num_chains(struct hdd_adapter *adapter, uint8_t *num_chains);
+
 /**
  * hdd_get_nss() - Get the number of spatial streams supported by the adapter
  *
@@ -281,6 +294,20 @@ QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
  */
 QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss);
 
+/**
+ * hdd_get_num_tx_chains() - Get the number of tx chains supported by the
+ * adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @tx_chains: the number of Tx chains supported by the adapter
+ *
+ * This function is used to get the number of Tx chains supported by
+ * the adapter.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_get_num_tx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *tx_chains);
+
 /**
  * hdd_get_tx_nss() - Get the number of spatial streams supported by the adapter
  * @link_info: Link info pointer in HDD adapter
@@ -294,6 +321,19 @@ QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss);
 QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info,
 			  uint8_t *tx_nss);
 
+/**
+ * hdd_get_num_rx_chains() - Get the number of chains supported by the adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @rx_chains: the number of Rx chains supported by the adapter
+ *
+ * This function is used to get the number of Rx chains supported by
+ * the adapter.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_get_num_rx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *rx_chains);
+
 /**
  * hdd_get_rx_nss() - Get the number of spatial streams supported by the adapter
  * @link_info: Link info pointer in HDD adapter
@@ -465,10 +505,11 @@ int hdd_set_rx_stbc(struct wlan_hdd_link_info *link_info, int value);
  * @adapter: adapter being modified
  * @chwidth: new channel width of enum eSirMacHTChannelWidth
  * @bonding_mode: channel bonding mode of the new channel width
+ * @link_id: mlo link id
  *
  * Return: 0 on success, negative errno on failure
  */
 int hdd_update_channel_width(struct hdd_adapter *adapter,
 			     enum eSirMacHTChannelWidth chwidth,
-			     uint32_t bonding_mode);
+			     uint32_t bonding_mode, uint8_t link_id);
 #endif /* end #if !defined(HDD_CONFIG_H__) */

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

@@ -1078,6 +1078,7 @@ enum udp_qos_upgrade {
  * @hdd_stats: HDD statistics
  * @big_data_stats: Big data stats
  * @ll_iface_stats: Link Layer interface stats
+ * @hdd_sinfo: hdd vdev station stats that will be sent to userspace
  * @mscs_prev_tx_vo_pkts: count of prev VO AC packets transmitted
  * @mscs_counter: Counter on MSCS action frames sent
  * @link_flags: a bitmap of hdd_link_flags
@@ -1111,6 +1112,7 @@ struct wlan_hdd_link_info {
 #endif
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 	struct wifi_interface_stats ll_iface_stats;
+	struct wlan_hdd_station_stats_info hdd_sinfo;
 #endif
 
 #ifdef WLAN_FEATURE_MSCS
@@ -5397,4 +5399,16 @@ static inline void wlan_hdd_link_speed_update(struct wlan_objmgr_psoc *psoc,
  */
 void hdd_update_multicast_list(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * hdd_set_sar_init_index() - Set SAR safety index at init.
+ * @hdd_ctx: HDD context
+ *
+ */
+#ifdef SAR_SAFETY_FEATURE
+void hdd_set_sar_init_index(struct hdd_context *hdd_ctx);
+#else
+static inline void hdd_set_sar_init_index(struct hdd_context *hdd_ctx)
+{}
+#endif
+
 #endif /* end #if !defined(WLAN_HDD_MAIN_H) */

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

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2012,2016-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -125,6 +125,7 @@ enum hdd_wmm_linuxac {
  * @magic: magic number used to verify that this is a valid context when
  *	referenced anonymously
  * @is_inactivity_timer_running: true if inactivity timer is running
+ * @ts_id: identifier which gets used at time of DEL request
  */
 struct hdd_wmm_qos_context {
 	struct list_head node;
@@ -136,6 +137,7 @@ struct hdd_wmm_qos_context {
 	struct work_struct implicit_qos_work;
 	uint32_t magic;
 	bool is_inactivity_timer_running;
+	uint8_t ts_id;
 };
 
 /**

+ 214 - 2
core/hdd/src/wlan_hdd_cfg.c

@@ -1417,6 +1417,65 @@ QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss)
 	return status;
 }
 
+/**
+ * hdd_get_sap_num_tx_chains() - get the sap num tx chains
+ * @link_info: Pointer of link_info
+ * @tx_chains: pointer to tx_chains
+ *
+ * get the sap num tx chains
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sap_num_tx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *tx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	mac_handle_t mac_handle;
+
+	mac_handle = hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_debug("NULL MAC handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
+	if (operating_band == BAND_UNKNOWN)
+		return QDF_STATUS_E_INVAL;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	if (hdd_ctx->dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+			hdd_debug("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+		switch (operating_band) {
+		case BAND_2G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			hdd_debug("Band %d Not 2G or 5G", operating_band);
+			break;
+		}
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return  QDF_STATUS_SUCCESS;
+}
+
 /**
  * hdd_get_sap_tx_nss() - get the sap tx nss
  * @link_info: Pointer of link_info
@@ -1477,6 +1536,37 @@ hdd_get_sap_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 	return  QDF_STATUS_SUCCESS;
 }
 
+/**
+ * hdd_get_sta_num_tx_chains() - get the sta num tx chains
+ * @link_info: Pointer of link_info
+ * @tx_chains: pointer to tx_chains
+ *
+ * get the STA num tx chains
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sta_num_tx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *tx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	status = ucfg_mlme_get_sta_num_tx_chains(hdd_ctx->psoc, vdev,
+						 tx_chains);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Failed to get sta_tx_nss");
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+	return status;
+}
+
 /**
  * hdd_get_sta_tx_nss() - get the sta tx nss
  * @link_info: Pointer of link_info
@@ -1506,6 +1596,21 @@ hdd_get_sta_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 	return status;
 }
 
+QDF_STATUS hdd_get_num_tx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *tx_chains)
+{
+	struct hdd_adapter *adapter = link_info->adapter;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (adapter->device_mode == QDF_SAP_MODE ||
+	    adapter->device_mode == QDF_P2P_GO_MODE)
+		status = hdd_get_sap_num_tx_chains(link_info, tx_chains);
+	else
+		status = hdd_get_sta_num_tx_chains(link_info, tx_chains);
+
+	return status;
+}
+
 QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 {
 	struct hdd_adapter *adapter = link_info->adapter;
@@ -1520,6 +1625,65 @@ QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 	return status;
 }
 
+/**
+ * hdd_get_sap_num_rx_chains() - get the sap num rx chains
+ * @link_info: Pointer to link_info
+ * @rx_chains: pointer to rx_chains
+ *
+ * get the sap num rx chains
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sap_num_rx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *rx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	mac_handle_t mac_handle;
+
+	mac_handle = hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_debug("NULL MAC handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
+	if (operating_band == BAND_UNKNOWN)
+		return QDF_STATUS_E_INVAL;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	if (hdd_ctx->dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+			hdd_debug("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+		switch (operating_band) {
+		case BAND_2G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			hdd_debug("Band %d Not 2G or 5G", operating_band);
+			break;
+		}
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return  QDF_STATUS_SUCCESS;
+}
+
 /**
  * hdd_get_sap_rx_nss() - get the sap rx nss
  * @link_info: Pointer to link_info
@@ -1580,6 +1744,38 @@ hdd_get_sap_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
 	return  QDF_STATUS_SUCCESS;
 }
 
+/**
+ * hdd_get_sta_num_rx_chains() - get the sta num rx chains
+ * @link_info: Pointer to link_info in adapter
+ * @rx_chains: pointer to rx_chains
+ *
+ * get the STA num rx chains
+ *
+ * Return: QDF_STATUS_SUCCESS if the RX NSS is returned, otherwise a suitable
+ *         QDF_STATUS_E_* error code
+ */
+static QDF_STATUS
+hdd_get_sta_num_rx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *rx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	status = ucfg_mlme_get_sta_num_rx_chains(hdd_ctx->psoc, vdev,
+						 rx_chains);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Failed to get sta_rx_nss");
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+	return status;
+}
+
 /**
  * hdd_get_sta_rx_nss() - get the sta rx nss
  * @link_info: Pointer to link_info in adapter
@@ -1610,6 +1806,21 @@ hdd_get_sta_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
 	return status;
 }
 
+QDF_STATUS hdd_get_num_rx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *rx_chains)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct hdd_adapter *adapter = link_info->adapter;
+
+	if (adapter->device_mode == QDF_SAP_MODE ||
+	    adapter->device_mode == QDF_P2P_GO_MODE)
+		status = hdd_get_sap_num_rx_chains(link_info, rx_chains);
+	else
+		status = hdd_get_sta_num_rx_chains(link_info, rx_chains);
+
+	return status;
+}
+
 QDF_STATUS hdd_get_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -2204,7 +2415,7 @@ static QDF_STATUS hdd_update_bss_rate_flags(struct hdd_adapter *adapter,
 
 int hdd_update_channel_width(struct hdd_adapter *adapter,
 			     enum eSirMacHTChannelWidth chwidth,
-			     uint32_t bonding_mode)
+			     uint32_t bonding_mode, uint8_t link_id)
 {
 	struct hdd_context *hdd_ctx;
 	struct sme_config_params *sme_config;
@@ -2225,7 +2436,8 @@ int hdd_update_channel_width(struct hdd_adapter *adapter,
 			  adapter->deflink->vdev_id, ch_width);
 		status =
 		    ucfg_mlme_send_ch_width_update_with_notify(hdd_ctx->psoc,
-					adapter->deflink->vdev_id, ch_width);
+					adapter->deflink->vdev_id, ch_width,
+					link_id);
 		if (QDF_IS_STATUS_ERROR(status))
 			return -EIO;
 		status = hdd_update_bss_rate_flags(adapter, hdd_ctx->psoc,

+ 440 - 28
core/hdd/src/wlan_hdd_cfg80211.c

@@ -455,6 +455,46 @@ static struct ieee80211_supported_band wlan_hdd_band_5_ghz = {
 	.vht_cap.vht_supported = 1,
 };
 
+enum hdd_hw_rate_cck {
+	HDD_HW_RATE_CCK_LP_11M = 0,
+	HDD_HW_RATE_CCK_LP_5_5M,
+	HDD_HW_RATE_CCK_LP_2M,
+	HDD_HW_RATE_CCK_LP_1M,
+	HDD_HW_RATE_CCK_SP_11M,
+	HDD_HW_RATE_CCK_SP_5_5M,
+	HDD_HW_RATE_CCK_SP_2M,
+};
+
+enum hdd_hw_rate_ofdm {
+	HDD_HW_RATE_OFDM_48M = 0,
+	HDD_HW_RATE_OFDM_24M,
+	HDD_HW_RATE_OFDM_12M,
+	HDD_HW_RATE_OFDM_6M,
+	HDD_HW_RATE_OFDM_54M,
+	HDD_HW_RATE_OFDM_36M,
+	HDD_HW_RATE_OFDM_18M,
+	HDD_HW_RATE_OFDM_9M,
+};
+
+static struct ieee80211_rate hdd_legacy_rates[] = {
+	{ .bitrate = 10,
+	  .hw_value = HDD_HW_RATE_CCK_LP_1M },
+	{ .bitrate = 20,
+	  .hw_value = HDD_HW_RATE_CCK_LP_2M },
+	{ .bitrate = 55,
+	  .hw_value = HDD_HW_RATE_CCK_LP_5_5M },
+	{ .bitrate = 110,
+	  .hw_value = HDD_HW_RATE_CCK_LP_11M },
+	{ .bitrate = 60, .hw_value = HDD_HW_RATE_OFDM_6M },
+	{ .bitrate = 90, .hw_value = HDD_HW_RATE_OFDM_9M },
+	{ .bitrate = 120, .hw_value = HDD_HW_RATE_OFDM_12M },
+	{ .bitrate = 180, .hw_value = HDD_HW_RATE_OFDM_18M },
+	{ .bitrate = 240, .hw_value = HDD_HW_RATE_OFDM_24M },
+	{ .bitrate = 360, .hw_value = HDD_HW_RATE_OFDM_36M },
+	{ .bitrate = 480, .hw_value = HDD_HW_RATE_OFDM_48M },
+	{ .bitrate = 540, .hw_value = HDD_HW_RATE_OFDM_54M },
+};
+
 #if defined(CONFIG_BAND_6GHZ) && (defined(CFG80211_6GHZ_BAND_SUPPORTED) || \
 	(KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE))
 
@@ -799,7 +839,7 @@ static const struct ieee80211_iface_limit
 static const struct ieee80211_iface_limit
 	wlan_hdd_mon_iface_limit[] = {
 	{
-		.max = 3,
+		.max = 2,
 		.types = BIT(NL80211_IFTYPE_MONITOR),
 	},
 };
@@ -932,7 +972,7 @@ static struct ieee80211_iface_combination
 	/* Monitor */
 	{
 		.limits = wlan_hdd_mon_iface_limit,
-		.max_interfaces = 3,
+		.max_interfaces = 2,
 		.num_different_channels = 2,
 		.n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit),
 	},
@@ -960,6 +1000,103 @@ static struct ieee80211_iface_combination
 #endif /* WLAN_FEATURE_NAN */
 };
 
+/* 1 and 2 port concurrencies */
+static struct ieee80211_iface_combination
+	wlan_hdd_derived_combination[] = {
+	/* STA */
+	{
+		.limits = wlan_hdd_sta_iface_limit,
+		.num_different_channels = 2,
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_sta_iface_limit),
+	},
+	/* AP */
+	{
+		.limits = wlan_hdd_ap_iface_limit,
+		.num_different_channels = 2,
+		.max_interfaces = (QDF_MAX_NO_OF_SAP_MODE),
+		.n_limits = ARRAY_SIZE(wlan_hdd_ap_iface_limit),
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) || \
+	defined(CFG80211_BEACON_INTERVAL_BACKPORT)
+		.beacon_int_min_gcd = 1,
+#endif
+	},
+#ifndef WLAN_FEATURE_NO_P2P_CONCURRENCY
+	/* P2P */
+	{
+		.limits = wlan_hdd_p2p_iface_limit,
+		.num_different_channels = 2,
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit),
+	},
+
+	/* SAP + P2P */
+	{
+		.limits = wlan_hdd_sap_p2p_iface_limit,
+		.num_different_channels = 2,
+		/* 1-SAP + 1-P2P */
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_sap_p2p_iface_limit),
+		.beacon_int_infra_match = true,
+	},
+	/* P2P + P2P */
+	{
+		.limits = wlan_hdd_p2p_p2p_iface_limit,
+		.num_different_channels = 2,
+		/* 2-P2P */
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit),
+		.beacon_int_infra_match = true,
+	},
+#endif
+	/* STA + P2P */
+	{
+		.limits = wlan_hdd_sta_p2p_iface_limit,
+		.num_different_channels = 2,
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit),
+		.beacon_int_infra_match = true,
+	},
+#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY
+	/* STA + SAP */
+	{
+		.limits = wlan_hdd_sta_ap_iface_limit,
+		.num_different_channels = 2,
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit),
+		.beacon_int_infra_match = true,
+	},
+#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */
+	/* Monitor */
+	{
+		.limits = wlan_hdd_mon_iface_limit,
+		.max_interfaces = 2,
+		.num_different_channels = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit),
+	},
+#if defined(WLAN_FEATURE_NAN) && \
+	   (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
+#ifndef WLAN_FEATURE_NO_STA_NAN_CONCURRENCY
+	/* NAN + STA */
+	{
+		.limits = wlan_hdd_sta_nan_iface_limit,
+		.max_interfaces = 2,
+		.num_different_channels = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_sta_nan_iface_limit),
+	},
+#endif /* WLAN_FEATURE_NO_STA_NAN_CONCURRENCY */
+#ifndef WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY
+	/* NAN + SAP */
+	{
+		.limits = wlan_hdd_sap_nan_iface_limit,
+		.num_different_channels = 2,
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(wlan_hdd_sap_nan_iface_limit),
+		.beacon_int_infra_match = true,
+	},
+#endif /* !WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY */
+#endif /* WLAN_FEATURE_NAN */
+};
 static struct cfg80211_ops wlan_hdd_cfg80211_ops;
 
 #ifdef WLAN_NL80211_TESTMODE
@@ -3817,6 +3954,8 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
 	bool is_vendor_unsafe_ch_present = false;
 	bool sap_force_11n_for_11ac = 0;
 	bool go_force_11n_for_11ac = 0;
+	bool is_ll_lt_sap = false;
+	bool sap_force_11n;
 	bool go_11ac_override = 0;
 	bool sap_11ac_override = 0;
 	uint8_t vht_ch_width;
@@ -3849,6 +3988,12 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
 	ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc,
 					    &channel_bonding_mode_2g);
 
+	if (policy_mgr_is_vdev_ll_lt_sap(hdd_ctx->psoc, link_info->vdev_id))
+		is_ll_lt_sap = true;
+
+	if (is_ll_lt_sap || sap_force_11n_for_11ac)
+		sap_force_11n = true;
+
 	if (!((adapter->device_mode == QDF_SAP_MODE) ||
 	      (adapter->device_mode == QDF_P2P_GO_MODE))) {
 		hdd_err("Invalid device mode %d", adapter->device_mode);
@@ -3915,7 +4060,7 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
 	sap_config->acs_cfg.master_acs_cfg.eht = eht_enabled;
 
 	if (((adapter->device_mode == QDF_SAP_MODE) &&
-	      sap_force_11n_for_11ac) ||
+	      sap_force_11n) ||
 	    ((adapter->device_mode == QDF_P2P_GO_MODE) &&
 	      go_force_11n_for_11ac)) {
 		vht_enabled = 0;
@@ -3951,6 +4096,8 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
 		else
 			ch_width = 20;
 	}
+	if (is_ll_lt_sap)
+		ch_width = 20;
 
 	if (tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME])
 		last_scan_ageout_time =
@@ -4148,7 +4295,7 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
 	    sap_config->acs_cfg.end_ch_freq >=
 		WLAN_REG_CH_TO_FREQ(CHAN_ENUM_5180) &&
 	    ((adapter->device_mode == QDF_SAP_MODE &&
-	      !sap_force_11n_for_11ac &&
+	      !sap_force_11n &&
 	      sap_11ac_override) ||
 	      (adapter->device_mode == QDF_P2P_GO_MODE &&
 	      !go_force_11n_for_11ac &&
@@ -8152,6 +8299,13 @@ void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx,
 #define RX_BLOCKSIZE_WINLIMIT \
 	QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_WINLIMIT
 
+#define CONFIG_CHANNEL_WIDTH \
+	QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH
+#define CONFIG_MLO_LINK_ID \
+	QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID
+#define CONFIG_MLO_LINKS \
+	QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS
+
 const struct nla_policy wlan_hdd_wifi_config_policy[
 			QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS] = {
@@ -8295,6 +8449,18 @@ const struct nla_policy wlan_hdd_wifi_config_policy[
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_UL_MU_CONFIG] = {.type = NLA_U8},
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST] = {
 		.type = NLA_NESTED},
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS] = {
+		.type = NLA_NESTED },
+};
+
+#define WLAN_MAX_LINK_ID 15
+
+static const struct nla_policy bandwidth_mlo_policy[
+			QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH] = {
+		.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID] = {
+		.type = NLA_U8 },
 };
 
 static const struct nla_policy
@@ -10713,36 +10879,88 @@ static uint32_t hdd_mac_chwidth_to_bonding_mode(
 }
 
 int hdd_set_mac_chan_width(struct hdd_adapter *adapter,
-			   enum eSirMacHTChannelWidth chwidth)
+			   enum eSirMacHTChannelWidth chwidth,
+			   uint8_t link_id)
 {
 	uint32_t bonding_mode;
 
 	bonding_mode = hdd_mac_chwidth_to_bonding_mode(chwidth);
 
-	return hdd_update_channel_width(adapter, chwidth, bonding_mode);
+	return hdd_update_channel_width(adapter, chwidth,
+					bonding_mode, link_id);
 }
 
 /**
  * hdd_set_channel_width() - set channel width
  * @link_info: Link info pointer in HDD adapter.
- * @attr: nla attr sent by supplicant
+ * @tb: array of pointer to struct nlattr
  *
  * Return: 0 on success, negative errno on failure
  */
 static int hdd_set_channel_width(struct wlan_hdd_link_info *link_info,
-				 const struct nlattr *attr)
+				 struct nlattr *tb[])
 {
-	uint8_t nl80211_chwidth;
-	enum eSirMacHTChannelWidth chwidth;
+	int rem;
+	uint8_t nl80211_chwidth = 0xFF;
+	uint8_t link_id = 0xFF;
+	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1];
+	struct nlattr *curr_attr;
+	struct nlattr *chn_bd = NULL;
+	struct nlattr *mlo_link_id;
 
-	nl80211_chwidth = nla_get_u8(attr);
-	chwidth = hdd_nl80211_chwidth_to_chwidth(nl80211_chwidth);
-	if (chwidth < 0) {
+	if (!tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS])
+		goto skip_mlo;
+
+	nla_for_each_nested(curr_attr,
+			    tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS], rem) {
+		if (wlan_cfg80211_nla_parse_nested(tb2,
+						QCA_WLAN_VENDOR_ATTR_CONFIG_MAX,
+						   curr_attr,
+						   bandwidth_mlo_policy)){
+			hdd_err_rl("nla_parse failed");
+			return -EINVAL;
+		}
+
+		chn_bd = tb2[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH];
+		mlo_link_id = tb2[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID];
+
+		if (!chn_bd || !mlo_link_id)
+			return 0;
+
+		nl80211_chwidth = nla_get_u8(chn_bd);
+		if (nl80211_chwidth < eHT_CHANNEL_WIDTH_20MHZ ||
+		    nl80211_chwidth > eHT_MAX_CHANNEL_WIDTH) {
+			hdd_err("Invalid channel width:%u", nl80211_chwidth);
+			return -EINVAL;
+		}
+
+		link_id = nla_get_u8(mlo_link_id);
+		if (link_id > WLAN_MAX_LINK_ID) {
+			hdd_debug("invalid link_id:%u", link_id);
+			return -EINVAL;
+		}
+	}
+
+	if (link_id != 0xFF)
+		goto set_chan_width;
+
+skip_mlo:
+	chn_bd = tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH];
+
+	if (!chn_bd)
+		return 0;
+
+	nl80211_chwidth = nla_get_u8(chn_bd);
+
+	if (nl80211_chwidth < eHT_CHANNEL_WIDTH_20MHZ ||
+	    nl80211_chwidth > eHT_MAX_CHANNEL_WIDTH) {
 		hdd_err("Invalid channel width");
 		return -EINVAL;
 	}
 
-	return hdd_set_mac_chan_width(link_info->adapter, chwidth);
+set_chan_width:
+	return hdd_set_mac_chan_width(link_info->adapter,
+				      nl80211_chwidth, link_id);
 }
 
 /**
@@ -11686,8 +11904,6 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_config_tx_stbc},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC,
 	 hdd_config_rx_stbc},
-	{QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH,
-	 hdd_set_channel_width},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW,
 	 hdd_set_dynamic_bw},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_NSS,
@@ -12020,6 +12236,89 @@ static int hdd_get_channel_width(struct wlan_hdd_link_info *link_info,
 	return 0;
 }
 
+/**
+ * hdd_get_mlo_max_band_info() - Get channel width
+ * @link_info: Link info pointer in HDD adapter
+ * @skb: sk buffer to hold nl80211 attributes
+ * @attr: Pointer to struct nlattr
+ *
+ * Return: 0 on success; error number otherwise
+ */
+static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
+				     struct sk_buff *skb,
+				     const struct nlattr *attr)
+{
+	enum eSirMacHTChannelWidth chwidth;
+	struct nlattr *mlo_bd = NULL;
+	struct nlattr *mlo_bd_info = NULL;
+	uint32_t i = 0;
+	uint32_t link_id = 0;
+	struct wlan_objmgr_vdev *vdev, *link_vdev;
+	struct wlan_channel *bss_chan;
+
+	chwidth = wma_cli_get_command(link_info->vdev_id,
+				      wmi_vdev_param_chwidth, VDEV_CMD);
+	if (chwidth < 0) {
+		hdd_err("Failed to get chwidth %u", chwidth);
+		return -EINVAL;
+	}
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return -EINVAL;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
+
+		if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH,
+			       (uint8_t)bss_chan->ch_width)) {
+			hdd_err("nla_put chn width failure");
+		}
+	} else {
+		mlo_bd_info = nla_nest_start(skb, CONFIG_MLO_LINKS);
+		for (link_id = 0; link_id < WLAN_MAX_LINK_ID; link_id++) {
+			link_vdev = mlo_get_vdev_by_link_id(vdev, link_id);
+			if (!link_vdev)
+				continue;
+
+			mlo_bd = nla_nest_start(skb, i);
+			if (!mlo_bd) {
+				hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+				mlo_release_vdev_ref(link_vdev);
+				hdd_err("nla_nest_start fail");
+				return -EINVAL;
+			}
+			bss_chan = wlan_vdev_mlme_get_bss_chan(link_vdev);
+			if (!bss_chan) {
+				hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+				mlo_release_vdev_ref(link_vdev);
+				hdd_err("fail to get bss_chan info");
+				return QDF_STATUS_E_FAILURE;
+			}
+			if (nla_put_u8(skb, CONFIG_MLO_LINK_ID, link_id)) {
+				hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+				mlo_release_vdev_ref(link_vdev);
+				hdd_err("nla_put failure");
+				return -EINVAL;
+			}
+
+			if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH,
+				       (uint8_t)bss_chan->ch_width)) {
+				hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+				mlo_release_vdev_ref(link_vdev);
+				hdd_err("nla_put failure");
+				return -EINVAL;
+			}
+			nla_nest_end(skb, mlo_bd);
+			i++;
+			mlo_release_vdev_ref(link_vdev);
+		}
+		nla_nest_end(skb, mlo_bd_info);
+	}
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return 0;
+}
+
 /**
  * hdd_get_dynamic_bw() - Get dynamic bandwidth disabled / enabled
  * @link_info: Link info pointer in HDD adapter
@@ -12094,6 +12393,43 @@ static int hdd_get_nss_config(struct wlan_hdd_link_info *link_info,
 	return 0;
 }
 
+/**
+ * hdd_get_num_tx_chains_config() - Get the number of tx chains supported by
+ * the adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @skb: sk buffer to hold nl80211 attributes
+ * @attr: Pointer to struct nlattr
+ *
+ * Return: 0 on success; error number otherwise
+ */
+static int hdd_get_num_tx_chains_config(struct wlan_hdd_link_info *link_info,
+					struct sk_buff *skb,
+					const struct nlattr *attr)
+{
+	uint8_t tx_chains;
+	QDF_STATUS status;
+
+	if (!hdd_is_vdev_in_conn_state(link_info)) {
+		hdd_err("Not in connected state");
+		return -EINVAL;
+	}
+
+	status = hdd_get_num_tx_chains(link_info, &tx_chains);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to get num tx chains");
+		return -EINVAL;
+	}
+
+	hdd_debug("num_tx_chains %d", tx_chains);
+	if (nla_put_u8(skb,
+		       QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS, tx_chains)) {
+		hdd_err("nla_put failure");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * hdd_get_tx_nss_config() - Get the number of tx spatial streams supported by
  * the adapter
@@ -12129,6 +12465,43 @@ static int hdd_get_tx_nss_config(struct wlan_hdd_link_info *link_info,
 	return 0;
 }
 
+/**
+ * hdd_get_num_rx_chains_config() - Get the number of rx chains supported by
+ * the adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @skb: sk buffer to hold nl80211 attributes
+ * @attr: Pointer to struct nlattr
+ *
+ * Return: 0 on success; error number otherwise
+ */
+static int hdd_get_num_rx_chains_config(struct wlan_hdd_link_info *link_info,
+					struct sk_buff *skb,
+					const struct nlattr *attr)
+{
+	uint8_t rx_chains;
+	QDF_STATUS status;
+
+	if (!hdd_is_vdev_in_conn_state(link_info)) {
+		hdd_err("Not in connected state");
+		return -EINVAL;
+	}
+
+	status = hdd_get_num_rx_chains(link_info, &rx_chains);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to get num rx chains");
+		return -EINVAL;
+	}
+
+	hdd_debug("num_rx_chains %d", rx_chains);
+	if (nla_put_u8(skb,
+		       QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS, rx_chains)) {
+		hdd_err("nla_put failure");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * hdd_get_rx_nss_config() - Get the number of rx spatial streams supported by
  * the adapter
@@ -12320,6 +12693,15 @@ static const struct config_getters config_getters[] = {
 	 {QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL,
 	 sizeof(uint32_t),
 	 hdd_get_listen_interval_config},
+	 {QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS,
+	 sizeof(uint8_t),
+	 hdd_get_num_tx_chains_config},
+	 {QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS,
+	 sizeof(uint8_t),
+	 hdd_get_num_rx_chains_config},
+	 {QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS,
+	 WLAN_MAX_ML_BSS_LINKS * sizeof(uint8_t) * 2,
+	 hdd_get_mlo_max_band_info},
 };
 
 /**
@@ -12453,6 +12835,7 @@ static const interdependent_setter_fn interdependent_setters[] = {
 	hdd_process_generic_set_cmd,
 	hdd_config_phy_mode,
 	hdd_config_power,
+	hdd_set_channel_width,
 };
 
 /**
@@ -12753,6 +13136,7 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 	uint8_t wmm_mode = 0;
 	uint32_t bss_max_idle_period = 0;
 	uint32_t cmd_id;
+	uint8_t link_id = 0xFF;
 	struct keep_alive_req keep_alive_req = {0};
 	struct set_wfatest_params wfa_param = {0};
 	struct wlan_hdd_link_info *link_info = adapter->link_info;
@@ -13467,7 +13851,8 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 		if (cfg_val)
 			hdd_update_channel_width(
 					adapter, eHT_CHANNEL_WIDTH_20MHZ,
-					WNI_CFG_CHANNEL_BONDING_MODE_DISABLE);
+					WNI_CFG_CHANNEL_BONDING_MODE_DISABLE,
+					link_id);
 	}
 
 	cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ER_SU_PPDU_TYPE;
@@ -13477,7 +13862,8 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 		if (cfg_val) {
 			hdd_update_channel_width(
 					adapter, eHT_CHANNEL_WIDTH_20MHZ,
-					WNI_CFG_CHANNEL_BONDING_MODE_DISABLE);
+					WNI_CFG_CHANNEL_BONDING_MODE_DISABLE,
+					link_id);
 			hdd_set_tx_stbc(link_info, 0);
 			hdd_set_11ax_rate(adapter, 0x400, NULL);
 			status = wma_cli_set_command(
@@ -13497,6 +13883,7 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 		} else {
 			hdd_update_channel_width(
 					adapter, eHT_CHANNEL_WIDTH_160MHZ,
+					link_id,
 					WNI_CFG_CHANNEL_BONDING_MODE_ENABLE);
 			hdd_set_tx_stbc(link_info, 1);
 			hdd_set_11ax_rate(adapter, 0xFFFF, NULL);
@@ -14762,7 +15149,7 @@ static uint32_t wlan_hdd_populate_weigh_pcl(
 		w_pcl[i].freq = chan_weights->pcl_list[i];
 		w_pcl[i].weight = chan_weights->weight_list[i];
 
-		if (intf_mode == PM_SAP_MODE || intf_mode == PM_P2P_GO_MODE)
+		if (policy_mgr_is_beaconing_mode(intf_mode))
 			w_pcl[i].flag = PCL_CHANNEL_SUPPORT_GO;
 		else
 			w_pcl[i].flag = PCL_CHANNEL_SUPPORT_CLI;
@@ -14797,8 +15184,8 @@ static uint32_t wlan_hdd_populate_weigh_pcl(
 						PCL_CHANNEL_EXCLUDE_IN_GO_NEG;
 					w_pcl[chan_idx].weight = 0;
 				} else {
-					if (intf_mode == PM_SAP_MODE ||
-					    intf_mode == PM_P2P_GO_MODE)
+					if (policy_mgr_is_beaconing_mode(
+								intf_mode))
 						w_pcl[chan_idx].flag =
 						      PCL_CHANNEL_SUPPORT_GO;
 					else
@@ -15836,6 +16223,10 @@ static int __wlan_hdd_cfg80211_ap_policy(struct hdd_adapter *adapter,
 		hdd_err("failed to set MLME ap config");
 		return -EINVAL;
 	}
+
+	wlan_mlme_ll_lt_sap_send_oce_flags_fw(adapter->deflink->vdev);
+	wlan_vdev_mlme_feat_ext_cap_clear(adapter->deflink->vdev,
+					  WLAN_VDEV_FEXT_FILS_DISC_6G_SAP);
 	return 0;
 }
 
@@ -18278,9 +18669,6 @@ hdd_fill_usable_channels_data(struct sk_buff *skb, struct nlattr **tb,
 			return -EINVAL;
 		j++;
 		bw = hdd_convert_phy_bw_to_nl_bw(res_msg[i].bw);
-		hdd_debug("populating chan_params freq %d bw %d iface mode %d, seg0 %d",
-			  res_msg[i].freq, bw, res_msg[i].iface_mode_mask,
-			  res_msg[i].seg0_freq);
 		if (nla_put_u32(skb,
 				QCA_WLAN_VENDOR_ATTR_CHAN_INFO_PRIMARY_FREQ,
 				res_msg[i].freq) ||
@@ -21086,6 +21474,7 @@ void wlan_hdd_update_wiphy(struct hdd_context *hdd_ctx)
 	uint8_t allow_mcc_go_diff_bi = 0, enable_mcc = 0;
 	bool is_bigtk_supported;
 	bool is_ocv_supported;
+	uint8_t iface_num;
 
 	if (!wiphy) {
 		hdd_err("Invalid wiphy");
@@ -21153,9 +21542,17 @@ void wlan_hdd_update_wiphy(struct hdd_context *hdd_ctx)
 					beacon_int_infra_match = true;
 			}
 		}
-		wiphy->n_iface_combinations =
-			ARRAY_SIZE(wlan_hdd_iface_combination);
-		wiphy->iface_combinations = wlan_hdd_iface_combination;
+
+		if (!ucfg_policy_mgr_is_fw_supports_dbs(hdd_ctx->psoc)) {
+			wiphy->iface_combinations =
+						wlan_hdd_derived_combination;
+			iface_num = ARRAY_SIZE(wlan_hdd_derived_combination);
+		} else {
+			wiphy->iface_combinations = wlan_hdd_iface_combination;
+			iface_num = ARRAY_SIZE(wlan_hdd_iface_combination);
+		}
+
+		wiphy->n_iface_combinations = iface_num;
 	}
 
 	mac_spoofing_enabled = ucfg_scan_is_mac_spoofing_enabled(hdd_ctx->psoc);
@@ -27846,7 +28243,7 @@ static int __wlan_hdd_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
 			continue;
 		}
 
-		if (!hweight32(mask->control[band].legacy)) {
+		if (!qdf_get_hweight32(mask->control[band].legacy)) {
 			hdd_err("Legacy bit rate setting not supported for band %u",
 				band);
 			errno = -EINVAL;
@@ -27881,6 +28278,21 @@ static int __wlan_hdd_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
 			}
 		}
 
+		if (qdf_get_hweight32(mask->control[band].legacy) == 1) {
+			rate_index = (ffs(mask->control[band].legacy) - 1);
+			nss = 0;
+			if (band == NL80211_BAND_5GHZ)
+				rate_index += 4;
+			if (rate_index >= 0 && rate_index < 4)
+				bit_rate = hdd_assemble_rate_code(
+					WMI_RATE_PREAMBLE_CCK, nss,
+					hdd_legacy_rates[rate_index].hw_value);
+			else if (rate_index >= 4 && rate_index < 12)
+				bit_rate = hdd_assemble_rate_code(
+					WMI_RATE_PREAMBLE_OFDM, nss,
+					hdd_legacy_rates[rate_index].hw_value);
+		}
+
 		hdd_get_he_bitrate_params_for_band(band, mask, &nss,
 						   &rate_index, &bit_rate);
 

+ 3 - 1
core/hdd/src/wlan_hdd_cfg80211.h

@@ -967,11 +967,13 @@ int hdd_set_phy_mode(struct hdd_adapter *adapter,
  * hdd_set_mac_chan_width() - set channel width
  * @adapter: Handle to hdd_adapter
  * @chwidth: given channel width
+ * @link_id: mlo link id
  *
  * Return: 0 on success, negative errno on failure
  */
 int hdd_set_mac_chan_width(struct hdd_adapter *adapter,
-			   enum eSirMacHTChannelWidth chwidth);
+			   enum eSirMacHTChannelWidth chwidth,
+			   uint8_t link_id);
 
 /**
  * hdd_is_legacy_connection() - Is adapter connection is legacy

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

@@ -1117,7 +1117,7 @@ static void hdd_cm_save_bss_info(struct wlan_hdd_link_info *link_info,
 	} else {
 		hdd_sta_ctx->conn_info.conn_flag.ht_present = false;
 	}
-	if (hdd_is_roam_sync_in_progress(hdd_ctx, link_info->vdev_id))
+	if (rsp->is_reassoc)
 		hdd_sta_ctx->conn_info.roam_count++;
 
 	if (assoc_resp->HTInfo.present) {

+ 2 - 1
core/hdd/src/wlan_hdd_cm_disconnect.c

@@ -513,6 +513,7 @@ static void hdd_cm_restore_ch_width(struct wlan_objmgr_vdev *vdev,
 	struct mlme_legacy_priv *mlme_priv;
 	enum eSirMacHTChannelWidth max_bw;
 	struct wlan_channel *des_chan;
+	uint8_t link_id = 0xFF;
 	int ret;
 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
 	enum phy_ch_width assoc_ch_width;
@@ -533,7 +534,7 @@ static void hdd_cm_restore_ch_width(struct wlan_objmgr_vdev *vdev,
 	cm_update_associated_ch_info(vdev, false);
 
 	max_bw = get_max_bw();
-	ret = hdd_set_mac_chan_width(adapter, max_bw);
+	ret = hdd_set_mac_chan_width(adapter, max_bw, link_id);
 	if (ret) {
 		hdd_err("vdev %d : fail to set max ch width", vdev_id);
 		return;

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

@@ -746,6 +746,7 @@ static int __hdd_soc_probe(struct device *dev,
 	hdd_start_complete(0);
 	hdd_thermal_mitigation_register(hdd_ctx, dev);
 
+	hdd_set_sar_init_index(hdd_ctx);
 	hdd_soc_load_unlock(dev);
 
 	return 0;
@@ -2181,6 +2182,7 @@ static void
 wlan_hdd_pld_uevent(struct device *dev, struct pld_uevent_data *event_data)
 {
 	struct qdf_notifer_data hang_evt_data;
+	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
 	enum qdf_hang_reason reason = QDF_REASON_UNSPECIFIED;
 	uint8_t bus_type;
 
@@ -2224,6 +2226,12 @@ wlan_hdd_pld_uevent(struct device *dev, struct pld_uevent_data *event_data)
 	case PLD_FW_HANG_EVENT:
 		hdd_info("Received firmware hang event");
 		cds_get_recovery_reason(&reason);
+
+		if ((reason == QDF_REASON_UNSPECIFIED) && hif_ctx) {
+			hif_display_ctrl_traffic_pipes_state(hif_ctx);
+			hif_display_latest_desc_hist(hif_ctx);
+		}
+
 		qdf_mem_zero(&g_fw_host_hang_event, QDF_HANG_EVENT_DATA_SIZE);
 		hang_evt_data.hang_data = g_fw_host_hang_event;
 		hang_evt_data.offset = 0;

+ 19 - 10
core/hdd/src/wlan_hdd_hostapd.c

@@ -2033,12 +2033,7 @@ hdd_hostapd_check_channel_post_csa(struct hdd_context *hdd_ctx,
 		return;
 	}
 
-	sap_cnt = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc,
-							    PM_SAP_MODE,
-							    NULL);
-	sap_cnt += policy_mgr_mode_specific_connection_count(hdd_ctx->psoc,
-							     PM_P2P_GO_MODE,
-							     NULL);
+	sap_cnt = policy_mgr_get_beaconing_mode_count(hdd_ctx->psoc, NULL);
 	if (sap_cnt > 1)
 		policy_mgr_check_concurrent_intf_and_restart_sap(
 				hdd_ctx->psoc,
@@ -4058,7 +4053,7 @@ uint32_t hdd_get_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
 	con_mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc,
 							ap_adapter->device_mode,
 							vdev_id);
-	if ((con_mode != PM_SAP_MODE && con_mode != PM_P2P_GO_MODE) ||
+	if (!policy_mgr_is_beaconing_mode(con_mode) ||
 	    !policy_mgr_is_6ghz_conc_mode_supported(psoc, con_mode)) {
 		hdd_err("unexpected device mode %d", ap_adapter->device_mode);
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
@@ -6226,6 +6221,17 @@ wlan_hdd_set_multipass(struct wlan_objmgr_vdev *vdev)
 }
 #endif
 
+static void wlan_hdd_update_ll_lt_sap_configs(struct wlan_objmgr_psoc *psoc,
+					      uint8_t vdev_id,
+					      struct sap_config *config)
+{
+	if (!policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id))
+		return;
+
+	config->SapHw_mode = eCSR_DOT11_MODE_11n;
+	config->ch_width_orig = CH_WIDTH_20MHZ;
+}
+
 /**
  * wlan_hdd_cfg80211_start_bss() - start bss
  * @link_info: Link info pointer in HDD adapter
@@ -6761,6 +6767,9 @@ int wlan_hdd_cfg80211_start_bss(struct wlan_hdd_link_info *link_info,
 			config->SapHw_mode = eCSR_DOT11_MODE_11n;
 	}
 
+	wlan_hdd_update_ll_lt_sap_configs(hdd_ctx->psoc,
+					  link_info->vdev_id, config);
+
 	config->sap_orig_hw_mode = config->SapHw_mode;
 	reg_phy_mode = csr_convert_to_reg_phy_mode(config->SapHw_mode,
 						   config->chan_freq);
@@ -7864,9 +7873,9 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 	sta_cnt = policy_mgr_get_mode_specific_conn_info(hdd_ctx->psoc, NULL,
 							 vdev_id_list,
 							 PM_STA_MODE);
-	sap_cnt = policy_mgr_get_mode_specific_conn_info(hdd_ctx->psoc, NULL,
-							 &vdev_id_list[sta_cnt],
-							 PM_SAP_MODE);
+	sap_cnt = policy_mgr_get_sap_mode_info(hdd_ctx->psoc, NULL,
+					       &vdev_id_list[sta_cnt]);
+
 	/* Disable NAN Disc before starting P2P GO or STA+SAP or SAP+SAP */
 	if (adapter->device_mode == QDF_P2P_GO_MODE || sta_cnt ||
 	    (sap_cnt > (MAX_SAP_NUM_CONCURRENCY_WITH_NAN - 1))) {

+ 100 - 20
core/hdd/src/wlan_hdd_main.c

@@ -6815,7 +6815,8 @@ free_net_dev:
 	return NULL;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) || \
+	(defined CFG80211_CHANGE_NETDEV_REGISTRATION_SEMANTICS))
 static int
 hdd_register_netdevice(struct hdd_adapter *adapter, struct net_device *dev,
 		       struct hdd_adapter_create_param *params)
@@ -7786,7 +7787,8 @@ static void hdd_sta_destroy_ctx_all(struct hdd_context *hdd_ctx)
 	}
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) || \
+	(defined CFG80211_CHANGE_NETDEV_REGISTRATION_SEMANTICS))
 static void
 hdd_unregister_netdevice(struct hdd_adapter *adapter, struct net_device *dev)
 {
@@ -10830,12 +10832,30 @@ hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx)
 #define SHUTDOWN_IN_SUSPEND_RETRY 10
 
 	int count = 0;
+	enum pmo_suspend_mode mode;
 
-	if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) != PMO_SUSPEND_SHUTDOWN) {
-		hdd_debug("shutdown in suspend not supported");
+	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
+		hdd_debug("Driver Modules not Enabled ");
+		return 0;
+	}
+
+	mode = ucfg_pmo_get_suspend_mode(hdd_ctx->psoc);
+	hdd_debug("suspend mode is %d", mode);
+
+	if (mode == PMO_SUSPEND_NONE || PMO_SUSPEND_LEGENCY) {
+		hdd_debug("needn't shutdown in suspend");
 		return 0;
 	}
 
+	if (!hdd_is_any_interface_open(hdd_ctx)) {
+		return pld_idle_shutdown(hdd_ctx->parent_dev,
+					 hdd_psoc_idle_shutdown);
+	} else {
+		if (mode == PMO_SUSPEND_WOW)
+			return 0;
+	}
+
+	/*try to wait interfacee down for PMO_SUSPEND_SHUTDOWN mode*/
 	while (hdd_is_any_interface_open(hdd_ctx) &&
 	       count < SHUTDOWN_IN_SUSPEND_RETRY) {
 		count++;
@@ -10846,8 +10866,6 @@ hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx)
 		hdd_err("some adapters not stopped");
 		return -EBUSY;
 	}
-
-	hdd_debug("call pld idle shutdown directly");
 	return pld_idle_shutdown(hdd_ctx->parent_dev, hdd_psoc_idle_shutdown);
 }
 
@@ -13593,13 +13611,30 @@ list_destroy:
 	return ret;
 }
 
-void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx)
+#ifdef SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND
+static void hdd_idle_timer_in_active(uint32_t timeout_ms)
+{
+	/* do nothing because idle shutdown will be called in system
+	 * suspend prepare
+	 */
+}
+#else
+/* ensure idle shutdown can be called/finished once timer started */
+static void hdd_idle_timer_in_active(uint32_t timeout_ms)
 {
-	uint32_t timeout_ms = hdd_ctx->config->iface_change_wait_time;
 	uint32_t suspend_timeout_ms;
 	enum wake_lock_reason reason =
 		WIFI_POWER_EVENT_WAKELOCK_IFACE_CHANGE_TIMER;
 
+	suspend_timeout_ms = timeout_ms + HDD_PSOC_IDLE_SHUTDOWN_SUSPEND_DELAY;
+	hdd_prevent_suspend_timeout(suspend_timeout_ms, reason);
+}
+#endif
+
+void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx)
+{
+	uint32_t timeout_ms = hdd_ctx->config->iface_change_wait_time;
+
 	if (!timeout_ms) {
 		hdd_info("psoc idle timer is disabled");
 		return;
@@ -13616,8 +13651,7 @@ void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx)
 	}
 
 	qdf_delayed_work_start(&hdd_ctx->psoc_idle_timeout_work, timeout_ms);
-	suspend_timeout_ms = timeout_ms + HDD_PSOC_IDLE_SHUTDOWN_SUSPEND_DELAY;
-	hdd_prevent_suspend_timeout(suspend_timeout_ms, reason);
+	hdd_idle_timer_in_active(timeout_ms);
 }
 
 void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx)
@@ -13963,6 +13997,25 @@ static void hdd_sar_cfg_update(struct hdd_config *config,
 	config->config_sar_safety_sleep_index =
 			cfg_get(psoc, CFG_CONFIG_SAR_SAFETY_SLEEP_MODE_INDEX);
 }
+
+void hdd_set_sar_init_index(struct hdd_context *hdd_ctx)
+{
+	uint32_t index, enable = 0;
+
+	if (!hdd_ctx) {
+		hdd_err("hdd_ctx NULL");
+		return;
+	}
+	if (hdd_ctx->sar_version == SAR_VERSION_1) {
+		hdd_nofl_debug("FW SAR version: %d", hdd_ctx->sar_version);
+		return;
+	}
+
+	enable = hdd_ctx->config->enable_sar_safety;
+	index = hdd_ctx->config->sar_safety_index;
+	if (enable & SAR_SAFETY_ENABLED_INIT)
+		hdd_configure_sar_index(hdd_ctx, index);
+}
 #else
 static void hdd_sar_cfg_update(struct hdd_config *config,
 			       struct wlan_objmgr_psoc *psoc)
@@ -19794,8 +19847,8 @@ void hdd_driver_unload(void)
 	 * trans are rejected via wlan_hdd_validate_context.
 	 */
 	status = osif_driver_sync_trans_start_wait(&driver_sync);
-	QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
-	if (QDF_IS_STATUS_ERROR(status)) {
+	if (QDF_IS_STATUS_ERROR(status) && status != -ETIMEDOUT) {
+		QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
 		hdd_err("Unable to unload wlan; status:%u", status);
 		hdd_place_marker(NULL, "UNLOAD FAILURE", NULL);
 		return;
@@ -19827,7 +19880,8 @@ void hdd_driver_unload(void)
 	 * Stop the trans before calling unregister_driver as that involves a
 	 * call to pld_remove which in itself is a psoc transaction
 	 */
-	osif_driver_sync_trans_stop(driver_sync);
+	if (driver_sync)
+		osif_driver_sync_trans_stop(driver_sync);
 
 	hdd_distroy_wifi_feature_interface();
 	if (!soft_unload)
@@ -19837,15 +19891,16 @@ void hdd_driver_unload(void)
 	wlan_hdd_unregister_driver();
 
 	status = osif_driver_sync_trans_start_wait(&driver_sync);
-	QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
-	if (QDF_IS_STATUS_ERROR(status)) {
+	if (QDF_IS_STATUS_ERROR(status) && status != -ETIMEDOUT) {
+		QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
 		hdd_err("Unable to unload wlan; status:%u", status);
 		hdd_place_marker(NULL, "UNLOAD FAILURE", NULL);
 		return;
 	}
 
 	osif_driver_sync_unregister();
-	osif_driver_sync_wait_for_ops(driver_sync);
+	if (driver_sync)
+		osif_driver_sync_wait_for_ops(driver_sync);
 
 	hdd_driver_mode_change_unregister();
 	pld_deinit();
@@ -19855,9 +19910,10 @@ void hdd_driver_unload(void)
 	hdd_component_cb_deinit();
 	hdd_deinit();
 
-	osif_driver_sync_trans_stop(driver_sync);
-	osif_driver_sync_destroy(driver_sync);
-
+	if (driver_sync) {
+		osif_driver_sync_trans_stop(driver_sync);
+		osif_driver_sync_destroy(driver_sync);
+	}
 	osif_sync_deinit();
 
 	hdd_qdf_deinit();
@@ -20190,6 +20246,27 @@ static void hdd_populate_runtime_cfg(struct hdd_context *hdd_ctx,
 }
 #endif
 
+#ifdef FEATURE_ENABLE_CE_DP_IRQ_AFFINE
+/**
+ * hdd_populate_ce_dp_irq_affine_cfg() - populate ce irq affine configuration
+ * @hdd_ctx: hdd context
+ * @cfg: pointer to the configuration memory being populated
+ *
+ * Return: void
+ */
+static void hdd_populate_ce_dp_irq_affine_cfg(struct hdd_context *hdd_ctx,
+					      struct hif_config_info *cfg)
+{
+	cfg->enable_ce_dp_irq_affine = cfg_get(hdd_ctx->psoc,
+					       CFG_ENABLE_CE_DP_IRQ_AFFINE);
+}
+#else
+static void hdd_populate_ce_dp_irq_affine_cfg(struct hdd_context *hdd_ctx,
+					      struct hif_config_info *cfg)
+{
+}
+#endif
+
 /**
  * hdd_update_hif_config - API to update HIF configuration parameters
  * @hdd_ctx: HDD Context
@@ -20220,6 +20297,7 @@ static void hdd_update_hif_config(struct hdd_context *hdd_ctx)
 	hdd_populate_runtime_cfg(hdd_ctx, &cfg);
 	cfg.rx_softirq_max_yield_duration_ns =
 		ucfg_dp_get_rx_softirq_yield_duration(hdd_ctx->psoc);
+	hdd_populate_ce_dp_irq_affine_cfg(hdd_ctx, &cfg);
 
 	hif_init_ini_config(scn, &cfg);
 	hif_set_enable_rpm(scn);
@@ -21342,6 +21420,7 @@ uint8_t *hdd_ch_width_str(enum phy_ch_width ch_width)
 int hdd_we_set_ch_width(struct wlan_hdd_link_info *link_info, int ch_width)
 {
 	int i;
+	uint8_t link_id = 0xFF;
 
 	/* updating channel bonding only on 5Ghz */
 	hdd_debug("wmi_vdev_param_chwidth val %d", ch_width);
@@ -21352,7 +21431,8 @@ int hdd_we_set_ch_width(struct wlan_hdd_link_info *link_info, int ch_width)
 			continue;
 
 		return hdd_update_channel_width(link_info->adapter, ch_width,
-						chwidth_info[i].bonding_mode);
+						chwidth_info[i].bonding_mode,
+						link_id);
 	}
 
 	hdd_err("Invalid ch_width %d", ch_width);

+ 3 - 1
core/hdd/src/wlan_hdd_medium_assess.c

@@ -404,12 +404,14 @@ void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx)
 	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
 		interval += medium_assess_info[i].config.interval;
 
-	if (!interval) {
+	if (!interval && timer_enable) {
 		ucfg_mc_cp_stats_reset_pending_req(hdd_ctx->psoc,
 						   TYPE_CONGESTION_STATS,
 						   &info, &pending);
 		qdf_mc_timer_stop(&hdd_medium_assess_timer);
 		hdd_debug("medium assess atimer stop");
+	} else {
+		hdd_debug("medium assess timer already disabled");
 	}
 }
 

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

@@ -277,12 +277,10 @@ QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void)
 QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev,
 						uint8_t non_trans_vdev_id)
 {
-	int errno;
 	bool found = false;
 	struct hdd_adapter *adapter;
 	struct vdev_osif_priv *osif_priv;
 	struct wlan_hdd_link_info *link_info, *iter_link_info;
-	struct osif_vdev_sync *vdev_sync;
 
 	osif_priv = wlan_vdev_get_ospriv(vdev);
 	if (!osif_priv) {
@@ -299,11 +297,6 @@ QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_INVAL;
 	}
 
-	errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync);
-	if (errno)
-		return QDF_STATUS_E_FAILURE;
-
-	osif_vdev_sync_wait_for_ops(vdev_sync);
 	hdd_adapter_for_each_link_info(adapter, iter_link_info) {
 		if (non_trans_vdev_id == iter_link_info->vdev_id) {
 			adapter->deflink = iter_link_info;
@@ -311,7 +304,6 @@ QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev,
 			break;
 		}
 	}
-	osif_vdev_sync_trans_stop(vdev_sync);
 
 	if (!found)
 		return QDF_STATUS_E_FAILURE;

+ 7 - 7
core/hdd/src/wlan_hdd_sar_limits.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-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
@@ -1093,7 +1093,7 @@ config_sar_failed:
 
 void hdd_configure_sar_sleep_index(struct hdd_context *hdd_ctx)
 {
-	if (!hdd_ctx->config->enable_sar_safety)
+	if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER))
 		return;
 
 	if (hdd_ctx->config->config_sar_safety_sleep_index) {
@@ -1110,7 +1110,7 @@ void hdd_configure_sar_sleep_index(struct hdd_context *hdd_ctx)
 
 void hdd_configure_sar_resume_index(struct hdd_context *hdd_ctx)
 {
-	if (!hdd_ctx->config->enable_sar_safety)
+	if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER))
 		return;
 
 	hdd_nofl_debug("Configure SAR safety index %d on wlan resume",
@@ -1199,7 +1199,7 @@ static void hdd_sar_safety_timer_cb(void *user_data)
 
 void wlan_hdd_sar_unsolicited_timer_start(struct hdd_context *hdd_ctx)
 {
-	if (!hdd_ctx->config->enable_sar_safety)
+	if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER))
 		return;
 
 	if (qdf_atomic_read(
@@ -1216,7 +1216,7 @@ void wlan_hdd_sar_timers_reset(struct hdd_context *hdd_ctx)
 {
 	QDF_STATUS status;
 
-	if (!hdd_ctx->config->enable_sar_safety)
+	if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER))
 		return;
 
 	if (hdd_ctx->sar_version == SAR_VERSION_1)
@@ -1245,7 +1245,7 @@ void wlan_hdd_sar_timers_init(struct hdd_context *hdd_ctx)
 {
 	QDF_STATUS status;
 
-	if (!hdd_ctx->config->enable_sar_safety)
+	if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER))
 		return;
 
 	hdd_enter();
@@ -1271,7 +1271,7 @@ hdd_exit:
 
 void wlan_hdd_sar_timers_deinit(struct hdd_context *hdd_ctx)
 {
-	if (!hdd_ctx->config->enable_sar_safety)
+	if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER))
 		return;
 
 	hdd_enter();

+ 2 - 1
core/hdd/src/wlan_hdd_son.c

@@ -145,6 +145,7 @@ static int hdd_son_set_chwidth(struct wlan_objmgr_vdev *vdev,
 {
 	enum eSirMacHTChannelWidth chwidth;
 	struct wlan_hdd_link_info *link_info;
+	uint8_t link_id = 0xFF;
 
 	if (!vdev) {
 		hdd_err("null vdev");
@@ -159,7 +160,7 @@ static int hdd_son_set_chwidth(struct wlan_objmgr_vdev *vdev,
 
 	chwidth = hdd_son_chan_width_to_chan_width(son_chwidth);
 
-	return hdd_set_mac_chan_width(link_info->adapter, chwidth);
+	return hdd_set_mac_chan_width(link_info->adapter, chwidth, link_id);
 }
 
 /**

+ 419 - 150
core/hdd/src/wlan_hdd_stats.c

@@ -493,7 +493,7 @@ hdd_get_link_info_by_bssid(struct hdd_context *hdd_ctx, const uint8_t *bssid)
 
 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
 					   dbgid) {
-		hdd_adapter_for_each_active_link_info(adapter, link_info) {
+		hdd_adapter_for_each_link_info(adapter, link_info) {
 			sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
 			if (qdf_is_macaddr_equal((struct qdf_mac_addr *)bssid,
 						 &sta_ctx->conn_info.bssid)) {
@@ -510,6 +510,7 @@ hdd_get_link_info_by_bssid(struct hdd_context *hdd_ctx, const uint8_t *bssid)
 }
 
 #if defined(WLAN_FEATURE_11BE_MLO)
+#define WLAN_INVALID_RSSI_VALUE -128
 /**
  * wlan_hdd_is_per_link_stats_supported - Check if FW supports per link stats
  * @hdd_ctx: Pointer to hdd context
@@ -555,6 +556,167 @@ wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
 	return status;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+static bool
+wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
+{
+	struct wlan_objmgr_vdev *vdev;
+	bool ret = false;
+
+	if (!link_info) {
+		hdd_err_rl("Invalid link info");
+		return ret;
+	}
+
+	if (!wlan_hdd_is_mlo_connection(link_info))
+		return ret;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
+	if (!vdev) {
+		hdd_err("invalid vdev");
+		return ret;
+	}
+
+	ret = mlo_mgr_is_link_switch_in_progress(vdev);
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
+	return ret;
+}
+#else
+static inline bool
+wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
+{
+	return false;
+}
+#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
+
+/**
+ * wlan_hdd_copy_sinfo_to_link_info() - Copy sinfo to link_info
+ * @link_info: Pointer to the hdd link info
+ * @sinfo: Pointer to kernel station info struct
+ *
+ * Return: none
+ */
+static void
+wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
+				 struct station_info *sinfo)
+{
+	struct wlan_hdd_station_stats_info *hdd_sinfo;
+	struct hdd_station_ctx *sta_ctx;
+	uint8_t i, *link_mac;
+
+	if (!wlan_hdd_is_mlo_connection(link_info))
+		return;
+
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+
+	hdd_sinfo = &link_info->hdd_sinfo;
+
+	hdd_sinfo->signal = sinfo->signal;
+	hdd_sinfo->signal_avg = sinfo->signal_avg;
+	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
+		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
+
+	qdf_mem_copy(&hdd_sinfo->txrate,
+		     &sinfo->txrate, sizeof(sinfo->txrate));
+
+	qdf_mem_copy(&hdd_sinfo->rxrate,
+		     &sinfo->rxrate, sizeof(sinfo->rxrate));
+	hdd_sinfo->rx_bytes = sinfo->rx_bytes;
+	hdd_sinfo->tx_bytes = sinfo->tx_bytes;
+	hdd_sinfo->rx_packets = sinfo->rx_packets;
+	hdd_sinfo->tx_packets = sinfo->tx_packets;
+	hdd_sinfo->tx_retries = sinfo->tx_retries;
+	hdd_sinfo->tx_failed = sinfo->tx_failed;
+	hdd_sinfo->rx_mpdu_count = sinfo->rx_mpdu_count;
+	hdd_sinfo->fcs_err_count = sinfo->fcs_err_count;
+
+	link_mac = sta_ctx->conn_info.bssid.bytes;
+	hdd_nofl_debug("copied sinfo for " QDF_MAC_ADDR_FMT " into link_info",
+		       QDF_MAC_ADDR_REF(link_mac));
+}
+
+/**
+ * wlan_hdd_copy_hdd_stats_to_sinfo() - Copy hdd station stats info to sinfo
+ * @sinfo: Pointer to kernel station info struct
+ * @hdd_sinfo: Pointer to the hdd station stats info struct
+ *
+ * Return: none
+ */
+static void
+wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info *sinfo,
+				 struct wlan_hdd_station_stats_info *hdd_sinfo)
+{
+	uint8_t i;
+
+	sinfo->signal = hdd_sinfo->signal;
+	sinfo->signal_avg = hdd_sinfo->signal_avg;
+	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
+		sinfo->chain_signal_avg[i] = hdd_sinfo->chain_signal_avg[i];
+
+	if (!hdd_sinfo->signal) {
+		sinfo->signal = WLAN_INVALID_RSSI_VALUE;
+		sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
+		for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
+			sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE;
+	}
+
+	qdf_mem_copy(&sinfo->txrate,
+		     &hdd_sinfo->txrate, sizeof(sinfo->txrate));
+
+	qdf_mem_copy(&sinfo->rxrate,
+		     &hdd_sinfo->rxrate, sizeof(sinfo->rxrate));
+	sinfo->rx_bytes = hdd_sinfo->rx_bytes;
+	sinfo->tx_bytes = hdd_sinfo->tx_bytes;
+	sinfo->rx_packets = hdd_sinfo->rx_packets;
+	sinfo->tx_packets = hdd_sinfo->tx_packets;
+	sinfo->tx_retries = hdd_sinfo->tx_retries;
+	sinfo->tx_failed = hdd_sinfo->tx_failed;
+	sinfo->rx_mpdu_count = hdd_sinfo->rx_mpdu_count;
+	sinfo->fcs_err_count = hdd_sinfo->fcs_err_count;
+}
+
+/**
+ * wlan_hdd_update_sinfo() - Function to update station info structure
+ * @sinfo: kernel station_info to populate
+ * @link_info: Pointer to the hdd link info
+ *
+ * Return: None
+ */
+static void wlan_hdd_update_sinfo(struct station_info *sinfo,
+				  struct wlan_hdd_link_info *link_info)
+{
+	if (!link_info) {
+		hdd_err("Invalid link_info");
+		return;
+	}
+
+	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &link_info->hdd_sinfo);
+
+	sinfo->filled |= HDD_INFO_SIGNAL | HDD_INFO_SIGNAL_AVG |
+			HDD_INFO_CHAIN_SIGNAL_AVG | HDD_INFO_TX_PACKETS |
+			HDD_INFO_TX_RETRIES | HDD_INFO_TX_FAILED |
+			HDD_INFO_TX_BITRATE | HDD_INFO_RX_BITRATE |
+			HDD_INFO_TX_BYTES | HDD_INFO_RX_BYTES |
+			HDD_INFO_RX_PACKETS | HDD_INFO_FCS_ERROR_COUNT |
+			HDD_INFO_RX_MPDUS;
+}
+
+static void
+wlan_hdd_get_mlo_peers_count(struct hdd_adapter *adapter, uint32_t *num_links)
+{
+	struct wlan_hdd_link_info *link_info;
+	struct hdd_station_ctx *sta_ctx;
+	u32 num_peers = 0;
+
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+		if (sta_ctx->conn_info.ieee_link_id != WLAN_INVALID_LINK_ID)
+			num_peers++;
+	}
+
+	*num_links = num_peers;
+}
 #else
 static inline bool
 wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
@@ -568,6 +730,29 @@ wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
 {
 	return QDF_STATUS_E_FAILURE;
 }
+
+static inline bool
+wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
+{
+	return false;
+}
+
+static inline void
+wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
+				 struct station_info *sinfo)
+{
+}
+
+static inline void
+wlan_hdd_update_sinfo(struct station_info *sinfo,
+		      struct wlan_hdd_link_info *link_info)
+{
+}
+
+static inline void
+wlan_hdd_get_mlo_peers_count(struct hdd_adapter *adapter, uint8_t *num_links)
+{
+}
 #endif
 
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
@@ -715,35 +900,6 @@ static bool put_wifi_peer_rates(struct wifi_peer_info *stats,
 }
 
 #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
- * @info: Pointer to wlan_hdd_mlo_iface_stats_info
- * @vdev_id: vdev_id of the mlo link
- *
- * Return: 0 on success, error on failure
- */
-static int
-wlan_hdd_update_mlo_iface_stats_info(struct hdd_context *hdd_ctx,
-				     struct wlan_hdd_mlo_iface_stats_info *info,
-				     uint8_t vdev_id)
-{
-	struct wlan_objmgr_vdev *vdev;
-
-	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc, vdev_id,
-						    WLAN_OSIF_STATS_ID);
-	if (!vdev) {
-		hdd_err("vdev object is NULL for vdev %d", vdev_id);
-		return -EINVAL;
-	}
-
-	info->link_id = wlan_vdev_get_link_id(vdev);
-	info->freq = vdev->vdev_mlme.des_chan->ch_freq;
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
-
-	return 0;
-}
-
 /**
  * wlan_hdd_put_mlo_link_iface_info() - Send per mlo link info to framework
  * @hdd_ctx: Pointer to hdd_context
@@ -758,19 +914,27 @@ wlan_hdd_put_mlo_link_iface_info(struct hdd_context *hdd_ctx,
 				 struct sk_buff *skb)
 {
 	struct wlan_hdd_mlo_iface_stats_info info = {0};
+	struct wlan_hdd_link_info *link_info;
+	struct hdd_station_ctx *sta_ctx;
 
 	if (!if_stat) {
 		hdd_err("invalid wifi interface stats");
 		return false;
 	}
 
-	if (wlan_hdd_update_mlo_iface_stats_info(hdd_ctx, &info,
-						 if_stat->vdev_id)) {
-		hdd_err("Unable to get mlo link iface info for vdev_id[%u]",
-			if_stat->vdev_id);
+	link_info = hdd_get_link_info_by_bssid(hdd_ctx,
+			(const uint8_t *)if_stat->info.bssid.bytes);
+
+	if (!link_info) {
+		hdd_err("invalid link_info");
 		return false;
 	}
 
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+
+	info.link_id = sta_ctx->conn_info.ieee_link_id;
+	info.freq = sta_ctx->conn_info.chan_freq;
+
 	if (if_stat->info.state != WIFI_ASSOCIATED) {
 		hdd_debug_rl("vdev_id[%u] is not associated", if_stat->vdev_id);
 		return false;
@@ -805,7 +969,7 @@ wlan_hdd_put_mlo_peer_link_id(struct sk_buff *vendor_event,
 {
 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
 	struct wlan_hdd_link_info *link_info;
-	struct wlan_hdd_mlo_iface_stats_info info = {0};
+	struct hdd_station_ctx *sta_ctx;
 
 	if (wlan_hdd_validate_context(hdd_ctx))
 		return false;
@@ -817,16 +981,11 @@ wlan_hdd_put_mlo_peer_link_id(struct sk_buff *vendor_event,
 		return false;
 	}
 
-	if (wlan_hdd_update_mlo_iface_stats_info(hdd_ctx, &info,
-						 link_info->vdev_id)) {
-		hdd_err("Unable to get mlo link iface info for vdev_id[%u]",
-			link_info->vdev_id);
-		return false;
-	}
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
 
 	if (nla_put_u8(vendor_event,
 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID,
-		       info.link_id))
+		       sta_ctx->conn_info.ieee_link_id))
 		return false;
 
 	return true;
@@ -1123,13 +1282,13 @@ static bool put_wifi_iface_stats(struct wifi_interface_stats *if_stat,
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
 			link_stats->mgmt_action_tx) ||
-	    nla_put_s32(vendor_event,
+	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
 			link_stats->rssi_mgmt) ||
-	    nla_put_s32(vendor_event,
+	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
 			link_stats->rssi_data) ||
-	    nla_put_s32(vendor_event,
+	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
 			link_stats->rssi_ack) ||
 	    nla_put_u32(vendor_event,
@@ -1256,7 +1415,8 @@ bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info,
 				QDF_MAC_ADDR_REF(mac->bytes));
 			info->state = WIFI_AUTHENTICATING;
 		}
-		if (hdd_cm_is_vdev_associated(link_info)) {
+		if (hdd_cm_is_vdev_associated(link_info) ||
+		    link_info->vdev_id == WLAN_UMAC_VDEV_ID_MAX) {
 			info->state = WIFI_ASSOCIATED;
 			qdf_copy_macaddr(&info->bssid,
 					 &sta_ctx->conn_info.bssid);
@@ -1436,6 +1596,9 @@ static int wlan_hdd_get_iface_stats(struct wlan_hdd_link_info *link_info,
 		return -EINVAL;
 	}
 
+	if (link_info->vdev_id == WLAN_UMAC_VDEV_ID_MAX)
+		link_info->ll_iface_stats.vdev_id = WLAN_UMAC_VDEV_ID_MAX;
+
 	qdf_mem_copy(if_stat, &link_info->ll_iface_stats,
 		     sizeof(link_info->ll_iface_stats));
 
@@ -1671,6 +1834,7 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 
 	link_info = ml_adapter->deflink;
 	rssi = link_info->rssi;
+	wlan_hdd_get_mlo_peers_count(adapter, &num_peers);
 	num_peers = hdd_ctx->num_mlo_peers;
 
 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
@@ -1687,7 +1851,7 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 		goto err;
 	}
 
-	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data");
+	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_peers = %u", num_peers);
 
 	if (!hdd_get_interface_info(link_info, &cumulative_if_stat.info)) {
 		hdd_err("hdd_get_interface_info get fail for ml_adapter");
@@ -1716,12 +1880,16 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 						     &link_if_stat[j]))
 				goto err;
 			j++;
+			if (j == num_peers)
+				break;
 			continue;
 		}
 
 		if (wlan_hdd_get_iface_stats(link_info, &link_if_stat[i]))
 			goto err;
 		j++;
+		if (j == num_peers)
+			break;
 
 		if (rssi <= link_info->rssi) {
 			rssi = link_info->rssi;
@@ -1779,6 +1947,7 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 
 	wlan_cfg80211_vendor_cmd_reply(skb);
 	qdf_mem_free(link_if_stat);
+	hdd_nofl_debug("Sent mlo interface stats to userspace");
 	return;
 err:
 	wlan_cfg80211_vendor_free_skb(skb);
@@ -1817,8 +1986,9 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 		return;
 	}
 
-	link_info = adapter->deflink;
-	num_peers = hdd_ctx->num_mlo_peers;
+	wlan_hdd_get_mlo_peers_count(adapter, &num_peers);
+
+	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_peers = %u", num_peers);
 
 	link_if_stat = qdf_mem_malloc(sizeof(*link_if_stat) * num_peers);
 	if (!link_if_stat) {
@@ -1826,21 +1996,15 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 		goto err;
 	}
 
-	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_peers = %u", num_peers);
-
-	if (!hdd_get_interface_info(link_info, &cumulative_if_stat.info)) {
+	if (!hdd_get_interface_info(adapter->deflink,
+				    &cumulative_if_stat.info)) {
 		hdd_err("hdd_get_interface_info get fail for ml_adapter");
 		goto err;
 	}
 
-	hdd_adapter_for_each_active_link_info(adapter, link_info) {
-		if (!hdd_cm_is_vdev_associated(link_info)) {
-			hdd_debug_rl("vdev_id[%u] is Not associated",
-				     link_info->vdev_id);
-			continue;
-		}
-
-		if (rssi <= link_info->rssi) {
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		if (link_info->rssi != 0 &&
+		    rssi <= link_info->rssi) {
 			rssi = link_info->rssi;
 			update_stats = true;
 		} else {
@@ -1850,10 +2014,17 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 		if (wlan_hdd_get_iface_stats(link_info, &link_if_stat[i]))
 			goto err;
 
+		if (link_info->vdev_id != WLAN_UMAC_VDEV_ID_MAX)
+			qdf_mem_copy(&link_info->ll_iface_stats,
+				     &link_if_stat[i],
+				     sizeof(*link_if_stat));
+
 		wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat,
 						 update_stats);
 
 		i++;
+		if (i == num_peers)
+			break;
 	}
 
 	netdev_addr = hdd_adapter_get_netdev_mac_addr(adapter);
@@ -1903,6 +2074,7 @@ static void wlan_hdd_send_mlo_ll_iface_stats(struct hdd_adapter *adapter)
 
 	wlan_cfg80211_vendor_cmd_reply(skb);
 	qdf_mem_free(link_if_stat);
+	hdd_nofl_debug("Sent mlo interface stats to userspace");
 	return;
 err:
 	wlan_cfg80211_vendor_free_skb(skb);
@@ -3161,7 +3333,7 @@ static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
 	struct hdd_ll_stats *stats = NULL;
 	struct osif_request *request;
 	qdf_list_node_t *ll_node;
-	QDF_STATUS status;
+	QDF_STATUS status, vdev_req_status;
 	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	void *cookie;
@@ -3178,8 +3350,9 @@ static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
 	if (QDF_IS_STATUS_ERROR(status))
 		return qdf_status_to_os_return(status);
 
-	status = wlan_hdd_set_station_stats_request_pending(link_info, req);
-	if (QDF_IS_STATUS_ERROR(status))
+	vdev_req_status = wlan_hdd_set_station_stats_request_pending(link_info,
+								     req);
+	if (QDF_IS_STATUS_ERROR(vdev_req_status))
 		hdd_nofl_debug("Requesting LL_STATS only");
 
 	/*
@@ -3237,7 +3410,9 @@ static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
 		sme_radio_tx_mem_free();
 		ret = -ETIMEDOUT;
 	} else {
-		hdd_update_station_stats_cached_timestamp(adapter);
+		if (QDF_IS_STATUS_SUCCESS(vdev_req_status))
+			hdd_update_station_stats_cached_timestamp(adapter);
+
 		adapter->ll_stats_failure_count = 0;
 	}
 
@@ -3365,6 +3540,11 @@ __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
 		return -EBUSY;
 	}
 
+	if (wlan_hdd_is_link_switch_in_progress(link_info)) {
+		hdd_debug("Link Switch in progress, can't process the request");
+		return -EBUSY;
+	}
+
 	if (wlan_cfg80211_nla_parse(tb_vendor,
 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
 				    (struct nlattr *)data, data_len,
@@ -5505,8 +5685,7 @@ static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
 
 	info->filled |= HDD_INFO_TX_PACKETS |
 			HDD_INFO_TX_RETRIES |
-			HDD_INFO_TX_FAILED  |
-			HDD_INFO_RX_PACKETS;
+			HDD_INFO_TX_FAILED;
 }
 
 /**
@@ -7463,12 +7642,20 @@ static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info,
 {
 	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	struct hdd_station_ctx *sta_ctx;
+	uint8_t *link_mac;
 	int32_t rcpi_value;
 
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
 		   TRACE_CODE_HDD_CFG80211_GET_STA,
 		   link_info->vdev_id, 0);
 
+	if (link_info->vdev_id == WLAN_UMAC_VDEV_ID_MAX) {
+		wlan_hdd_update_sinfo(sinfo, link_info);
+		hdd_debug_rl("Sending Cached stats for standby link");
+		return 0;
+	}
+
 	if (!hdd_cm_is_vdev_associated(link_info)) {
 		hdd_debug("Not associated");
 		/*To keep GUI happy */
@@ -7513,48 +7700,19 @@ static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info,
 
 	hdd_wlan_fill_per_chain_rssi_stats(sinfo, link_info);
 
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+	link_mac = sta_ctx->conn_info.bssid.bytes;
 	hdd_nofl_debug("Sending station stats for link " QDF_MAC_ADDR_FMT,
-		       QDF_MAC_ADDR_REF(mac));
+		       QDF_MAC_ADDR_REF(link_mac));
+
+	wlan_hdd_copy_sinfo_to_link_info(link_info, sinfo);
+
 	hdd_exit();
 
 	return 0;
 }
 
 #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
- * @sinfo: Pointer to kernel station info struct
- * @hdd_sinfo: Pointer to the hdd station stats info struct
- *
- * Return: none
- */
-static void
-wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info *sinfo,
-				 struct wlan_hdd_station_stats_info *hdd_sinfo)
-{
-	uint8_t i;
-
-	sinfo->signal = hdd_sinfo->signal;
-	sinfo->signal_avg = hdd_sinfo->signal_avg;
-	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
-		sinfo->chain_signal_avg[i] = hdd_sinfo->chain_signal_avg[i];
-
-	qdf_mem_copy(&sinfo->txrate,
-		     &hdd_sinfo->txrate, sizeof(sinfo->txrate));
-
-	qdf_mem_copy(&sinfo->rxrate,
-		     &hdd_sinfo->rxrate, sizeof(sinfo->rxrate));
-	sinfo->rx_bytes = hdd_sinfo->rx_bytes;
-	sinfo->tx_bytes = hdd_sinfo->tx_bytes;
-	sinfo->rx_packets = hdd_sinfo->rx_packets;
-	sinfo->tx_packets = hdd_sinfo->tx_packets;
-	sinfo->tx_retries = hdd_sinfo->tx_retries;
-	sinfo->tx_failed = hdd_sinfo->tx_failed;
-	sinfo->rx_mpdu_count = hdd_sinfo->rx_mpdu_count;
-	sinfo->fcs_err_count = hdd_sinfo->fcs_err_count;
-}
-
 /*
  * wlan_hdd_update_mlo_rate_info() - Populate mlo station stats rate info
  * @hdd_sinfo: Pointer to hdd stats station info struct
@@ -7593,6 +7751,10 @@ wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info *link_info,
 			  struct wlan_hdd_station_stats_info *hdd_sinfo,
 			  struct station_info *sinfo)
 {
+	struct hdd_station_ctx *sta_ctx;
+
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+
 	if (!link_info->is_mlo_vdev_active) {
 		hdd_nofl_debug("vdev_id[%d] is inactive", link_info->vdev_id);
 		return;
@@ -7600,8 +7762,8 @@ wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info *link_info,
 
 	/* Update the rate info for link with best RSSI */
 	if (sinfo->signal > hdd_sinfo->signal) {
-		hdd_nofl_debug("Updating rates for vdev_id[%d]",
-			       link_info->vdev_id);
+		hdd_nofl_debug("Updating rates for link_id %d",
+			       sta_ctx->conn_info.ieee_link_id);
 		wlan_hdd_update_mlo_rate_info(hdd_sinfo, sinfo);
 	}
 
@@ -7659,6 +7821,9 @@ static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
 	}
 
 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
+	hdd_nofl_debug("Sending aggregated mlo station stats");
+
+	hdd_exit();
 
 	return 0;
 }
@@ -7669,16 +7834,26 @@ static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
 {
 	struct wlan_hdd_link_info *link_info;
 	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
+	struct hdd_station_ctx *sta_ctx;
 
 	/* Initialize the signal value to a default RSSI of -128dBm */
 	hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE;
 
-	hdd_adapter_for_each_active_link_info(adapter, link_info) {
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+		if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID)
+			continue;
 		wlan_hdd_get_sta_stats(link_info, mac, sinfo);
+		if (link_info->vdev_id != WLAN_UMAC_VDEV_ID_MAX)
+			wlan_hdd_copy_hdd_stats_to_sinfo(sinfo,
+							 &link_info->hdd_sinfo);
 		wlan_hdd_update_mlo_sinfo(link_info, &hdd_sinfo, sinfo);
 	}
 
 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
+	hdd_nofl_debug("Sending aggregated mlo station stats");
+
+	hdd_exit();
 
 	return 0;
 }
@@ -7694,32 +7869,27 @@ static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
 
 /*
  * wlan_hdd_send_mlo_aggregated_stats() - Whether to send aggregated stats
- * @link_info: Link info pointer of STA adapter
+ * @adapter: HDD adapter
  * @mac: mac address
  *
  * Return: True if req is on mld_mac and FW supports per link stats, else False
  */
 static bool
-wlan_hdd_send_mlo_aggregated_stats(struct wlan_hdd_link_info *link_info,
+wlan_hdd_send_mlo_aggregated_stats(struct hdd_adapter *adapter,
 				   const uint8_t *mac)
 {
-	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	bool is_mld_req = false;
 	bool per_link_stats_cap = false;
 	struct qdf_mac_addr peer_mld_mac;
 	QDF_STATUS status;
 
-	if (!link_info) {
-		hdd_err("Invalid link_info");
-		return false;
-	}
-
-	if (!wlan_hdd_is_mlo_connection(link_info)) {
-		hdd_nofl_debug("Fetching station stats for legacy connection");
+	if (!hdd_ctx) {
+		hdd_err("invalid hdd_ctx");
 		return false;
 	}
 
-	status = wlan_hdd_get_bss_peer_mld_mac(link_info, &peer_mld_mac);
+	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink, &peer_mld_mac);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err_rl("mlo_vdev_stats: failed to get bss peer mld mac");
 		return false;
@@ -7737,6 +7907,38 @@ wlan_hdd_send_mlo_aggregated_stats(struct wlan_hdd_link_info *link_info,
 	return false;
 }
 
+/**
+ * wlan_hdd_send_mlo_station_stats() - send station stats to userspace
+ * @adapter: Pointer to hdd adapter
+ * @hdd_ctx: Pointer to hdd context
+ * @mac: mac address
+ * @sinfo: kernel station_info struct to populate
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int wlan_hdd_send_mlo_station_stats(struct hdd_adapter *adapter,
+					   struct hdd_context *hdd_ctx,
+					   const uint8_t *mac,
+					   struct station_info *sinfo)
+{
+	struct wlan_hdd_link_info *link_info;
+
+	if (!wlan_hdd_is_mlo_connection(adapter->deflink)) {
+		hdd_nofl_debug("Fetching station stats for legacy connection");
+		return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
+	}
+
+	if (!wlan_hdd_send_mlo_aggregated_stats(adapter, mac)) {
+		link_info = hdd_get_link_info_by_bssid(hdd_ctx, mac);
+		if (!link_info) {
+			hdd_debug_rl("Invalid bssid");
+			return -EINVAL;
+		}
+	}
+
+	return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
+}
+
 /**
  * __wlan_hdd_cfg80211_get_station() - get station statistics
  * @wiphy: Pointer to wiphy
@@ -7772,6 +7974,9 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
 		return -EINVAL;
 
+	hdd_debug_rl("Stats request on MAC: " QDF_MAC_ADDR_FMT,
+		     QDF_MAC_ADDR_REF(mac));
+
 	if (!mac || qdf_is_macaddr_zero((struct qdf_mac_addr *)mac)) {
 		hdd_err("Invalid MAC addr");
 		return -EINVAL;
@@ -7801,24 +8006,9 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
 				return 0;
 		}
 		return wlan_hdd_get_sap_stats(link_info, sinfo);
-	} else {
-		link_info = hdd_get_link_info_by_bssid(hdd_ctx, mac);
-		if (!link_info) {
-			adapter = WLAN_HDD_GET_PRIV_PTR(dev);
-			link_info = adapter->deflink;
-			hdd_err_rl("the bssid is invalid");
-		}
-
-		if (!wlan_hdd_send_mlo_aggregated_stats(link_info, mac)) {
-			hdd_nofl_debug("Station stats requested for vdev_[%u]",
-				       link_info->vdev_id);
-			return wlan_hdd_get_sta_stats(link_info,
-						      mac, sinfo);
-		}
-
-		return wlan_hdd_get_mlo_sta_stats(link_info->adapter,
-						  mac, sinfo);
 	}
+
+	return wlan_hdd_send_mlo_station_stats(adapter, hdd_ctx, mac, sinfo);
 }
 
 /**
@@ -7848,6 +8038,11 @@ static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
 	if (errno)
 		return errno;
 
+	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
+		hdd_debug("Link Switch in progress, can't process request");
+		return -EBUSY;
+	}
+
 	status = wlan_hdd_stats_request_needed(adapter);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		if (status == QDF_STATUS_E_ALREADY)
@@ -7936,6 +8131,11 @@ static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
 		return -EINVAL;
 
+	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
+		hdd_debug("Link Switch in progress, can't process request");
+		return -EBUSY;
+	}
+
 	if (adapter->device_mode == QDF_SAP_MODE ||
 	    adapter->device_mode == QDF_P2P_GO_MODE) {
 		qdf_status = ucfg_mlme_get_sap_get_peer_info(
@@ -8735,19 +8935,98 @@ return_cached_value:
 	return ret;
 }
 
+static uint32_t
+wlan_hdd_get_per_link_speed(struct wlan_hdd_link_info *link_info)
+{
+	uint32_t link_speed;
+	struct qdf_mac_addr bssid;
+
+	if (!hdd_cm_is_vdev_associated(link_info)) {
+		/* we are not connected so we don't have a classAstats */
+		hdd_debug("Not connected");
+		return 0;
+	}
+	qdf_copy_macaddr(&bssid,
+			 &link_info->session.station.conn_info.bssid);
+
+	if (wlan_hdd_get_linkspeed_for_peermac(link_info,
+					       &bssid, &link_speed)) {
+		hdd_err("Unable to retrieve SME linkspeed");
+		return 0;
+	}
+	hdd_debug("linkspeed = %d", link_speed);
+	return link_speed;
+}
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+static uint32_t
+wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
+{
+	struct hdd_adapter *ml_adapter = NULL;
+	struct hdd_adapter *link_adapter = NULL;
+	struct hdd_mlo_adapter_info *mlo_adapter_info = NULL;
+	uint32_t link_speed = 0;
+	uint32_t per_speed;
+	uint8_t link_id;
+
+	ml_adapter = adapter;
+	if (hdd_adapter_is_link_adapter(ml_adapter))
+		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
+
+	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
+	for (link_id = 0; link_id < WLAN_MAX_MLD; link_id++) {
+		link_adapter = mlo_adapter_info->link_adapter[link_id];
+		if (qdf_unlikely(!link_adapter)) {
+			hdd_err("link_adapter[%d] is Null", link_id);
+			continue;
+		}
+		per_speed = wlan_hdd_get_per_link_speed(ml_adapter->deflink);
+		link_speed += per_speed;
+		hdd_debug("Link%d speed=%d, total speed=%d",
+			  link_id, per_speed, link_speed);
+	}
+	return link_speed;
+}
+#else
+static uint32_t
+wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
+{
+	struct wlan_hdd_link_info *link_info = NULL;
+	uint32_t link_speed = 0;
+	uint32_t per_speed;
+
+	hdd_adapter_for_each_active_link_info(adapter, link_info) {
+		per_speed = wlan_hdd_get_per_link_speed(link_info);
+		link_speed += per_speed;
+		hdd_debug("per_speed=%d, link_speed=%d", per_speed, link_speed);
+	}
+	return link_speed;
+}
+#endif
+
+#else
+static uint32_t
+wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
+{
+	uint32_t link_speed = wlan_hdd_get_per_link_speed(adapter->deflink);
+
+	hdd_debug("Not support MLO, linkspeed = %d", link_speed);
+	return link_speed;
+}
+#endif
+
 int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info,
 			    uint32_t *link_speed)
 {
 	struct hdd_adapter *adapter =  link_info->adapter;
 	struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
-	struct hdd_station_ctx *hdd_stactx;
 	int ret;
 
 	ret = wlan_hdd_validate_context(hddctx);
 	if (ret)
 		return ret;
 
-	hdd_stactx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
 	/* Linkspeed is allowed for CLIENT/STA mode */
 	if (adapter->device_mode != QDF_P2P_CLIENT_MODE &&
 	    adapter->device_mode != QDF_STA_MODE) {
@@ -8757,23 +9036,13 @@ int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info,
 		return -ENOTSUPP;
 	}
 
-	if (!hdd_cm_is_vdev_associated(link_info)) {
-		/* we are not connected so we don't have a classAstats */
-		*link_speed = 0;
-	} else {
-		struct qdf_mac_addr bssid;
-
-		qdf_copy_macaddr(&bssid, &hdd_stactx->conn_info.bssid);
+	if (wlan_hdd_is_mlo_connection(link_info))
+		*link_speed = wlan_hdd_get_mlo_link_speed(adapter);
+	else
+		*link_speed = wlan_hdd_get_per_link_speed(link_info);
 
-		ret = wlan_hdd_get_linkspeed_for_peermac(link_info,
-							 &bssid, link_speed);
-		if (ret) {
-			hdd_err("Unable to retrieve SME linkspeed");
-			return ret;
-		}
-		/* linkspeed in units of 500 kbps */
-		*link_speed = (*link_speed) / 500;
-	}
+	/* linkspeed in units of 500 kbps */
+	*link_speed = (*link_speed) / 500;
 	return 0;
 }
 

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

@@ -94,6 +94,7 @@
 #include <wlan_hdd_sysfs_dfsnol.h>
 #include <wlan_hdd_sysfs_wds_mode.h>
 #include <wlan_hdd_sysfs_roam_trigger_bitmap.h>
+#include <wlan_hdd_sysfs_bitrates.h>
 
 #define MAX_PSOC_ID_SIZE 10
 
@@ -824,11 +825,13 @@ hdd_sysfs_create_sta_adapter_root_obj(struct hdd_adapter *adapter)
 	hdd_sysfs_bmiss_create(adapter);
 	hdd_sysfs_dp_tx_delay_stats_create(adapter);
 	hdd_sysfs_direct_link_ut_cmd_create(adapter);
+	hdd_sysfs_sta_bitrates_create(adapter);
 }
 
 static void
 hdd_sysfs_destroy_sta_adapter_root_obj(struct hdd_adapter *adapter)
 {
+	hdd_sysfs_sta_bitrates_destroy(adapter);
 	hdd_sysfs_direct_link_ut_destroy(adapter);
 	hdd_sysfs_dp_tx_delay_stats_destroy(adapter);
 	hdd_sysfs_bmiss_destroy(adapter);
@@ -887,11 +890,13 @@ hdd_sysfs_create_sap_adapter_root_obj(struct hdd_adapter *adapter)
 	hdd_sysfs_dp_traffic_end_indication_create(adapter);
 	hdd_sysfs_direct_link_ut_cmd_create(adapter);
 	hdd_sysfs_dfsnol_create(adapter);
+	hdd_sysfs_sap_bitrates_create(adapter);
 }
 
 static void
 hdd_sysfs_destroy_sap_adapter_root_obj(struct hdd_adapter *adapter)
 {
+	hdd_sysfs_sap_bitrates_destroy(adapter);
 	hdd_sysfs_dfsnol_destroy(adapter);
 	hdd_sysfs_direct_link_ut_destroy(adapter);
 	hdd_sysfs_dp_traffic_end_indication_destroy(adapter);

+ 446 - 0
core/hdd/src/wlan_hdd_sysfs_bitrates.c

@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2011-2021 The Linux Foundation. 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
+ * 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.
+ */
+
+/**
+ * DOC: wlan_hdd_sysfs_sta_bitrates.c
+ *
+ * implementation for creating sysfs file sta_bitrates and sap_bitrates
+ */
+
+#include <wlan_hdd_includes.h>
+#include <wlan_hdd_sysfs.h>
+#include <wlan_hdd_sysfs_bitrates.h>
+#include "osif_psoc_sync.h"
+#include "osif_vdev_sync.h"
+#include "sme_api.h"
+#include "qc_sap_ioctl.h"
+#include "wma_api.h"
+
+static int wlan_hdd_sta_set_11n_rate(struct hdd_adapter *adapter, int rate_code)
+{
+	uint8_t preamble = 0, nss = 0, rix = 0;
+	int ret;
+	QDF_STATUS status;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	enum wlan_phymode peer_phymode;
+	uint8_t *peer_mac = adapter->deflink->session.station.conn_info.bssid.bytes;
+
+	hdd_debug("Rate code %d", rate_code);
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	if (!wlan_hdd_validate_modules_state(hdd_ctx))
+		return -EINVAL;
+
+	if (rate_code != 0xffff) {
+		rix = RC_2_RATE_IDX(rate_code);
+		if (rate_code & 0x80) {
+			preamble = WMI_RATE_PREAMBLE_HT;
+			nss = HT_RC_2_STREAMS(rate_code) - 1;
+		} else {
+			status = ucfg_mlme_get_peer_phymode(hdd_ctx->psoc,
+							    peer_mac,
+							    &peer_phymode);
+			if (QDF_IS_STATUS_ERROR(status)) {
+				hdd_err("Failed to set rate");
+				return -EINVAL;
+			}
+			if (IS_WLAN_PHYMODE_HE(peer_phymode)) {
+				hdd_err("Do not set legacy rate %d in HE mode",
+					rate_code);
+				return -EINVAL;
+			}
+			nss = 0;
+			rix = RC_2_RATE_IDX(rate_code);
+			if (rate_code & 0x10) {
+				preamble = WMI_RATE_PREAMBLE_CCK;
+				if (rix != 0x3)
+					/* Enable Short preamble
+					 * always for CCK except 1mbps
+					 */
+					rix |= 0x4;
+			} else {
+				preamble = WMI_RATE_PREAMBLE_OFDM;
+			}
+		}
+		rate_code = hdd_assemble_rate_code(preamble, nss, rix);
+	}
+
+	hdd_debug("wmi_vdev_param_fixed_rate val %d rix %d preamble %x nss %d",
+		  rate_code, rix, preamble, nss);
+
+	ret = wma_cli_set_command(adapter->deflink->vdev_id,
+				  wmi_vdev_param_fixed_rate,
+				  rate_code, VDEV_CMD);
+
+	return ret;
+}
+
+static int wlan_hdd_sta_set_vht_rate(struct hdd_adapter *adapter, int rate_code)
+{
+	uint8_t preamble = 0, nss = 0, rix = 0;
+	int ret;
+
+	hdd_debug("Rate code %d", rate_code);
+
+	if (rate_code != 0xffff) {
+		rix = RC_2_RATE_IDX_11AC(rate_code);
+		preamble = WMI_RATE_PREAMBLE_VHT;
+		nss = HT_RC_2_STREAMS_11AC(rate_code) - 1;
+		rate_code = hdd_assemble_rate_code(preamble, nss, rix);
+	}
+
+	hdd_debug("wmi_vdev_param_fixed_rate val %d rix %d preamble %x nss %d",
+		  rate_code, rix, preamble, nss);
+
+	ret = wma_cli_set_command(adapter->deflink->vdev_id,
+				  wmi_vdev_param_fixed_rate,
+				  rate_code, VDEV_CMD);
+
+	return ret;
+}
+
+static int wlan_hdd_sta_set_11ax_rate(struct hdd_adapter *adapter, int rate)
+{
+	return hdd_set_11ax_rate(adapter, rate, NULL);
+}
+
+static int wlan_hdd_sap_set_11n_rate(struct hdd_adapter *adapter, int rate_code)
+{
+	uint8_t preamble = 0, nss = 0, rix = 0;
+	struct sap_config *config = &adapter->deflink->session.ap.sap_config;
+	int ret;
+
+	hdd_debug("SET_HT_RATE val %d", rate_code);
+
+	if (rate_code != 0xff) {
+		rix = RC_2_RATE_IDX(rate_code);
+		if (rate_code & 0x80) {
+			if (config->SapHw_mode == eCSR_DOT11_MODE_11b ||
+			    config->SapHw_mode == eCSR_DOT11_MODE_11b_ONLY ||
+			    config->SapHw_mode == eCSR_DOT11_MODE_11g ||
+			    config->SapHw_mode == eCSR_DOT11_MODE_11g_ONLY ||
+			    config->SapHw_mode == eCSR_DOT11_MODE_abg ||
+			    config->SapHw_mode == eCSR_DOT11_MODE_11a) {
+				hdd_err("Not valid mode for HT");
+				ret = -EIO;
+				return ret;
+				}
+			preamble = WMI_RATE_PREAMBLE_HT;
+			nss = HT_RC_2_STREAMS(rate_code) - 1;
+		} else if (rate_code & 0x10) {
+			if (config->SapHw_mode == eCSR_DOT11_MODE_11a) {
+				hdd_err("Not valid for cck");
+				ret = -EIO;
+				return ret;
+				}
+			preamble = WMI_RATE_PREAMBLE_CCK;
+			/* Enable Short preamble always for CCK except 1mbps */
+			if (rix != 0x3)
+				rix |= 0x4;
+		} else {
+			if (config->SapHw_mode == eCSR_DOT11_MODE_11b ||
+			    config->SapHw_mode == eCSR_DOT11_MODE_11b_ONLY) {
+				hdd_err("Not valid for OFDM");
+				ret = -EIO;
+				return ret;
+				}
+			preamble = WMI_RATE_PREAMBLE_OFDM;
+		}
+		hdd_debug("SET_HT_RATE val %d rix %d preamble %x nss %d",
+			  rate_code, rix, preamble, nss);
+		ret = wma_cli_set_command(adapter->deflink->vdev_id,
+					  wmi_vdev_param_fixed_rate,
+					  rate_code, VDEV_CMD);
+		return ret;
+	}
+
+	return -EINVAL;
+}
+
+static int wlan_hdd_sap_set_vht_rate(struct hdd_adapter *adapter, int rate_code)
+{
+	uint8_t preamble = 0, nss = 0, rix = 0;
+	int ret;
+	struct sap_config *config = &adapter->deflink->session.ap.sap_config;
+
+	if (config->SapHw_mode < eCSR_DOT11_MODE_11ac ||
+	    config->SapHw_mode == eCSR_DOT11_MODE_11ax_ONLY ||
+	    config->SapHw_mode == eCSR_DOT11_MODE_11be_ONLY) {
+		hdd_err("SET_VHT_RATE: SapHw_mode= 0x%x, ch_freq: %d",
+			config->SapHw_mode, config->chan_freq);
+		ret = -EIO;
+		return ret;
+	}
+
+	if (rate_code != 0xff) {
+		rix = RC_2_RATE_IDX_11AC(rate_code);
+		preamble = WMI_RATE_PREAMBLE_VHT;
+		nss = HT_RC_2_STREAMS_11AC(rate_code) - 1;
+
+		rate_code = hdd_assemble_rate_code(preamble, nss, rix);
+	}
+	hdd_debug("SET_VHT_RATE val %d rix %d preamble %x nss %d",
+		  rate_code, rix, preamble, nss);
+
+	ret = wma_cli_set_command(adapter->deflink->vdev_id,
+				  wmi_vdev_param_fixed_rate,
+				  rate_code, VDEV_CMD);
+
+	return ret;
+}
+
+static int
+wlan_hdd_sap_set_11ax_rate(struct hdd_adapter *adapter, int rate_code)
+{
+	struct sap_config *config = &adapter->deflink->session.ap.sap_config;
+
+	return  hdd_set_11ax_rate(adapter, rate_code, config);
+}
+
+static ssize_t
+__hdd_sysfs_sta_bitrates_store(struct net_device *net_dev,
+			       char const *buf, size_t count)
+{
+	struct hdd_adapter *adapter = netdev_priv(net_dev);
+	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
+	struct hdd_context *hdd_ctx;
+	char *sptr, *token;
+	int ret, rate, rate_code;
+
+	if (hdd_validate_adapter(adapter))
+		return -EINVAL;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	if (!wlan_hdd_validate_modules_state(hdd_ctx))
+		return -EINVAL;
+
+	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;
+	hdd_debug("sta_bitrates: count %zu buf_local:(%s)", count, buf_local);
+
+	/* Get rate_type */
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoint(token, 0, &rate))
+		return -EINVAL;
+
+	/* Get rate */
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoint(token, 0, &rate_code))
+		return -EINVAL;
+
+	switch (rate) {
+	case SET_11N_RATES:
+		ret = wlan_hdd_sta_set_11n_rate(adapter, rate_code);
+		if (ret) {
+			hdd_err_rl("failed to set 11n rates");
+			return ret;
+		}
+		break;
+	case SET_11AC_RATES:
+		ret = wlan_hdd_sta_set_vht_rate(adapter, rate_code);
+		if (ret) {
+			hdd_err_rl("failed to set 11ac rates");
+			return ret;
+		}
+		break;
+	case SET_11AX_RATES:
+		ret = wlan_hdd_sta_set_11ax_rate(adapter, rate_code);
+		if (ret) {
+			hdd_err_rl("failed to set 11ax rates");
+			return ret;
+		}
+		break;
+	default:
+		hdd_err("Invalid rate mode %u", rate);
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static ssize_t
+__hdd_sysfs_sap_bitrates_store(struct net_device *net_dev,
+			       char const *buf, size_t count)
+{
+	struct hdd_adapter *adapter = netdev_priv(net_dev);
+	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
+	struct hdd_context *hdd_ctx;
+	char *sptr, *token;
+	int ret, rate, rate_code;
+
+	if (hdd_validate_adapter(adapter))
+		return -EINVAL;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	if (!wlan_hdd_validate_modules_state(hdd_ctx))
+		return -EINVAL;
+
+	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;
+	hdd_debug("sta_bitrates: count %zu buf_local:(%s)", count, buf_local);
+
+	/* Get rate_type */
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoint(token, 0, &rate))
+		return -EINVAL;
+
+	/* Get rate */
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoint(token, 0, &rate_code))
+		return -EINVAL;
+
+	switch (rate) {
+	case SET_11N_RATES:
+		ret = wlan_hdd_sap_set_11n_rate(adapter, rate_code);
+		if (ret) {
+			hdd_err_rl("failed to set 11n rates");
+			return ret;
+		}
+		break;
+	case SET_11AC_RATES:
+		ret = wlan_hdd_sap_set_vht_rate(adapter, rate_code);
+		if (ret) {
+			hdd_err_rl("failed to set 11ac rates");
+			return ret;
+		}
+		break;
+	case SET_11AX_RATES:
+		ret = wlan_hdd_sap_set_11ax_rate(adapter, rate_code);
+		if (ret) {
+			hdd_err_rl("failed to set 11ax rates");
+			return ret;
+		}
+		break;
+	default:
+		hdd_err("Invalid rate mode %u", rate);
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static ssize_t
+hdd_sysfs_sap_bitrates_store(struct device *dev,
+			     struct device_attribute *attr,
+			     char const *buf, size_t count)
+{
+	struct net_device *net_dev = container_of(dev, struct net_device, dev);
+	struct osif_vdev_sync *vdev_sync;
+	ssize_t err_size;
+
+	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
+	if (err_size)
+		return err_size;
+
+	err_size = __hdd_sysfs_sap_bitrates_store(net_dev, buf, count);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return err_size;
+}
+
+static ssize_t
+hdd_sysfs_sta_bitrates_store(struct device *dev,
+			     struct device_attribute *attr,
+			     char const *buf, size_t count)
+{
+	struct net_device *net_dev = container_of(dev, struct net_device, dev);
+	struct osif_vdev_sync *vdev_sync;
+	ssize_t err_size;
+
+	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
+	if (err_size)
+		return err_size;
+
+	err_size = __hdd_sysfs_sta_bitrates_store(net_dev, buf, count);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return err_size;
+}
+
+static DEVICE_ATTR(sta_bitrates, 0220,
+		   NULL, hdd_sysfs_sta_bitrates_store);
+
+static DEVICE_ATTR(sap_bitrates, 0220,
+		   NULL, hdd_sysfs_sap_bitrates_store);
+
+int hdd_sysfs_sta_bitrates_create(struct hdd_adapter *adapter)
+{
+	int error;
+
+	error = device_create_file(&adapter->dev->dev,
+				   &dev_attr_sta_bitrates);
+	if (error)
+		hdd_err("could not create sta_bitrates sysfs file");
+
+	return error;
+}
+
+int hdd_sysfs_sap_bitrates_create(struct hdd_adapter *adapter)
+{
+	int error;
+
+	error = device_create_file(&adapter->dev->dev,
+				   &dev_attr_sap_bitrates);
+	if (error)
+		hdd_err("could not create sap_bitrates sysfs file");
+
+	return error;
+}
+void hdd_sysfs_sta_bitrates_destroy(struct hdd_adapter *adapter)
+{
+	device_remove_file(&adapter->dev->dev, &dev_attr_sta_bitrates);
+}
+
+void hdd_sysfs_sap_bitrates_destroy(struct hdd_adapter *adapter)
+{
+	device_remove_file(&adapter->dev->dev, &dev_attr_sap_bitrates);
+}

+ 90 - 0
core/hdd/src/wlan_hdd_sysfs_bitrates.h

@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/**
+ * DOC: wlan_hdd_sysfs_bitrates.h
+ *
+ * implementation for creating sysfs file bitrates
+ * file path: /sys/class/net/wlanxx/sta_bitrates
+ * file path: /sys/class/net/wlanxx/sap_bitrates
+ *
+ * usage:
+ *      echo [arg_0] [arg_1] > sta_bitrates
+ *      echo [arg_0] [arg_1] > sap_bitrates
+ */
+
+#ifndef _WLAN_HDD_SYSFS_BITRATES_H
+#define _WLAN_HDD_SYSFS_BITRATES_H
+
+#define SET_11N_RATES 0
+#define SET_11AC_RATES 1
+#define SET_11AX_RATES 2
+
+#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_BITRATES)
+/**
+ * hdd_sysfs_sta_bitrates_create() - API to create sta_bitrates
+ * @adapter: hdd adapter
+ *
+ * Return: 0 on success and errno on failure
+ */
+int hdd_sysfs_sta_bitrates_create(struct hdd_adapter *adapter);
+/**
+ * hdd_sysfs_sap_bitrates_create() - API to create sap_bitrates
+ * @adapter: hdd adapter
+ *
+ * Return: 0 on success and errno on failure
+ */
+int hdd_sysfs_sap_bitrates_create(struct hdd_adapter *adapter);
+/**
+ * hdd_sysfs_sta_bitrates_destroy() - API to destroy sta_bitrates
+ * @adapter: hdd adapter
+ *
+ * Return: none
+ */
+void
+hdd_sysfs_sta_bitrates_destroy(struct hdd_adapter *adapter);
+/**
+ * hdd_sysfs_sap_bitrates_destroy() - API to destroy sap_bitrates
+ * @adapter: hdd adapter
+ *
+ * Return: none
+ */
+void
+hdd_sysfs_sap_bitrates_destroy(struct hdd_adapter *adapter);
+#else
+static inline int
+hdd_sysfs_sta_bitrates_create(struct hdd_adapter *adapter)
+{
+	return 0;
+}
+
+static inline int
+hdd_sysfs_sap_bitrates_create(struct hdd_adapter *adapter)
+{
+	return 0;
+}
+
+static inline void
+hdd_sysfs_sta_bitrates_destroy(struct hdd_adapter *adapter)
+{
+}
+
+static inline void
+hdd_sysfs_sap_bitrates_destroy(struct hdd_adapter *adapter)
+{
+}
+#endif
+#endif /* #ifndef _WLAN_HDD_SYSFS_BITRATES_H */

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

@@ -60,7 +60,8 @@ static ssize_t __hdd_sysfs_direct_link_ut_cmd_store(struct net_device *net_dev,
 		return -EINVAL;
 	if (kstrtou32(token, 0, (uint32_t *)&cmd_info.cmd))
 		return -EINVAL;
-	if (cmd_info.cmd > WFDS_GET_STATS)
+
+	if (cmd_info.cmd >= WFDS_CMD_MAX)
 		return -EINVAL;
 
 	if (cmd_info.cmd == WFDS_STOP_TRAFFIC || cmd_info.cmd == WFDS_GET_STATS)

+ 4 - 2
core/hdd/src/wlan_hdd_tsf.c

@@ -1829,7 +1829,8 @@ static ssize_t __hdd_wlan_tsf_show(struct device *dev,
 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
 		mac = hdd_sta_ctx->conn_info.bssid.bytes;
 		size = scnprintf(buf, PAGE_SIZE,
-				 "%s%llu %llu " QDF_MAC_ADDR_FMT "%llu %llu %llu\n",
+				 "%s%llu %llu " QDF_MAC_ADDR_FMT
+				 " %llu %llu %llu\n",
 				 buf, adapter->tsf.last_target_time,
 				 tsf_sync_qtime,
 				 QDF_MAC_ADDR_REF(mac),
@@ -1837,7 +1838,8 @@ static ssize_t __hdd_wlan_tsf_show(struct device *dev,
 	} else {
 		mac = adapter->mac_addr.bytes;
 		size = scnprintf(buf, PAGE_SIZE,
-				 "%s%llu %llu " QDF_MAC_ADDR_FMT "%llu %llu %llu\n",
+				 "%s%llu %llu " QDF_MAC_ADDR_FMT
+				 " %llu %llu %llu\n",
 				 buf, adapter->tsf.last_target_time,
 				 tsf_sync_qtime,
 				 QDF_MAC_ADDR_REF(mac),

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

@@ -4776,9 +4776,7 @@ void __hdd_twt_update_work_handler(struct hdd_context *hdd_ctx)
 	sta_count = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc,
 							      PM_STA_MODE,
 							      NULL);
-	sap_count = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc,
-							      PM_SAP_MODE,
-							      NULL);
+	sap_count = policy_mgr_get_sap_mode_count(hdd_ctx->psoc, NULL);
 	twt_arg.hdd_ctx = hdd_ctx;
 
 	hdd_debug("Total connection %d, sta_count %d, sap_count %d",

+ 55 - 17
core/hdd/src/wlan_hdd_wmm.c

@@ -64,6 +64,8 @@
 
 #define HDD_WMM_UP_TO_AC_MAP_SIZE 8
 #define DSCP(x)	x
+#define MIN_HANDLE_VALUE 5000
+#define MAX_HANDLE_VALUE 6000
 
 const uint8_t hdd_wmm_up_to_ac_map[] = {
 	SME_AC_BE,
@@ -2648,16 +2650,6 @@ bool hdd_wmm_is_acm_allowed(uint8_t vdev_id)
 	return true;
 }
 
-/**
- * hdd_wmm_addts() - Function which will add a traffic spec at the
- * request of an application
- *
- * @adapter  : [in]  pointer to adapter context
- * @handle    : [in]  handle to uniquely identify a TS
- * @tspec    : [in]  pointer to the traffic spec
- *
- * Return: HDD_WLAN_WMM_STATUS_*
- */
 hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter,
 				    uint32_t handle,
 				    struct sme_qos_wmmtspecinfo *tspec)
@@ -2751,6 +2743,7 @@ hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter,
 	}
 	qos_context->adapter = adapter;
 	qos_context->flow_id = 0;
+	qos_context->ts_id = tspec->ts_info.tid;
 	qos_context->magic = HDD_WMM_CTX_MAGIC;
 	qos_context->is_inactivity_timer_running = false;
 
@@ -2864,9 +2857,9 @@ hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter,
 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
 
 	if (!qos_context) {
-		/* we didn't find the handle */
-		hdd_info("handle 0x%x not found", handle);
-		return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
+		/* we didn't find the handle, tid is already freed */
+		hdd_info("tid already freed for handle 0x%x", handle);
+		return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
 	}
 
 	ac_type = qos_context->ac_type;
@@ -2971,6 +2964,33 @@ hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter, uint32_t hand
 	return status;
 }
 
+/**
+ * hdd_get_handle_from_ts_id() - get handle from ts id
+ * @adapter : hdd adapter
+ * @ts_id: ts_id
+ * @del_tspec_handle: handle to delete the request
+ *
+ * Return: None
+ */
+static void
+hdd_get_handle_from_ts_id(struct hdd_adapter *adapter, uint8_t ts_id,
+			  uint32_t *del_tspec_handle)
+{
+	struct hdd_wmm_qos_context *cur_entry;
+
+	hdd_debug("Entered with ts_id 0x%x", ts_id);
+
+	mutex_lock(&adapter->hdd_wmm_status.mutex);
+	list_for_each_entry(cur_entry,
+			    &adapter->hdd_wmm_status.context_list, node) {
+		if (cur_entry->ts_id == ts_id) {
+			*del_tspec_handle = cur_entry->handle;
+			break;
+		}
+	}
+	mutex_unlock(&adapter->hdd_wmm_status.mutex);
+}
+
 /**
  * __wlan_hdd_cfg80211_config_tspec() - config tspec
  * @wiphy: pointer to wireless wiphy structure.
@@ -2990,6 +3010,8 @@ static int __wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy,
 	struct sme_qos_wmmtspecinfo tspec;
 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1];
 	uint8_t oper, ts_id;
+	static uint32_t add_tspec_handle = MIN_HANDLE_VALUE;
+	uint32_t del_tspec_handle = 0;
 	hdd_wlan_wmm_status_e status;
 	int ret;
 
@@ -3161,8 +3183,12 @@ static int __wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy,
 		if (tb[CONFIG_TSPEC_MINIMUM_PHY_RATE])
 			tspec.min_phy_rate = nla_get_u32(
 					     tb[CONFIG_TSPEC_MINIMUM_PHY_RATE]);
-
-		status = hdd_wmm_addts(adapter, ts_id, &tspec);
+		/*
+		 * ts_id send by upper layer is always same as handle and host
+		 * doesn't add new TS entry for same handle. To avoid this
+		 * issue host modifies handle internally.
+		 */
+		status = hdd_wmm_addts(adapter, add_tspec_handle, &tspec);
 		if (status == HDD_WLAN_WMM_STATUS_SETUP_FAILED ||
 		    status == HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM ||
 		    status == HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM ||
@@ -3174,11 +3200,23 @@ static int __wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy,
 			hdd_err_rl("hdd_wmm_addts failed %d", status);
 			return -EINVAL;
 		}
+
+		add_tspec_handle++;
+		if (add_tspec_handle >= MAX_HANDLE_VALUE)
+			add_tspec_handle = MIN_HANDLE_VALUE;
 		break;
 
 	case QCA_WLAN_TSPEC_DEL:
-
-		status = hdd_wmm_delts(adapter, ts_id);
+		/*
+		 * Host modifies handle internally. So, always
+		 * delete the entry for provided ts_id.
+		 */
+		hdd_get_handle_from_ts_id(adapter, ts_id, &del_tspec_handle);
+		if (!del_tspec_handle) {
+			hdd_err_rl("ts_id is already freed %d", ts_id);
+			break;
+		}
+		status = hdd_wmm_delts(adapter, del_tspec_handle);
 		if (status == HDD_WLAN_WMM_STATUS_RELEASE_FAILED ||
 		    status == HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM ||
 		    status == HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE) {

+ 2 - 0
core/mac/inc/ani_global.h

@@ -285,6 +285,8 @@ typedef struct sLimTimers {
 	/* SAE authentication related timer */
 	TX_TIMER sae_auth_timer;
 
+	/* RRM sta stats response related timer */
+	TX_TIMER rrm_sta_stats_resp_timer;
 /* ********************TIMER SECTION ENDS************************************************** */
 /* ALL THE FIELDS BELOW THIS CAN BE ZEROED OUT in lim_initialize */
 /* **************************************************************************************** */

+ 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            ""
-#define QWLAN_VERSION_BUILD            77
+#define QWLAN_VERSION_EXTRA            "D"
+#define QWLAN_VERSION_BUILD            78
 
-#define QWLAN_VERSIONSTR               "5.2.1.77"
+#define QWLAN_VERSIONSTR               "5.2.1.78D"
 
 #endif /* QWLAN_VERSION_H */

+ 114 - 0
core/mac/inc/sir_mac_prot_def.h

@@ -1347,6 +1347,118 @@ typedef struct sSirMacBeaconReport {
 
 } tSirMacBeaconReport, *tpSirMacBeaconReport;
 
+/**
+ * struct chan_load_report - channel load Report Structure
+ * @op_class: Regulatory Class
+ * @channel: Channel for which the current report is being sent
+ * @rrm_scan_tsf: RRM scan start time for this report
+ * @meas_duration: Scan duration for the current channel
+ * @chan_load: channel utilization measurement
+ */
+struct chan_load_report {
+	uint8_t op_class;
+	uint8_t channel;
+	qdf_time_t rrm_scan_tsf;
+	uint8_t meas_duration;
+	uint8_t chan_load;
+};
+
+/**
+ * sta_statistics_group_id - RRM STA STATISTICS TYPE related Refer IEEE
+ * P802.11-REVme/D2.1, January 2023, Table 9-144
+ * @STA_STAT_GROUP_ID_COUNTER_STATS: group id for counter stats
+ * @STA_STAT_GROUP_ID_MAC_STATS: group id for mac stats
+ * @STA_STAT_GROUP_ID_QOS_STATS: group id for qos stats
+ * @STA_STAT_GROUP_ID_DELAY_STATS: group id delay stats
+ */
+enum sta_statistics_group_id {
+	STA_STAT_GROUP_ID_COUNTER_STATS = 0,
+	STA_STAT_GROUP_ID_MAC_STATS = 1,
+	STA_STAT_GROUP_ID_QOS_STATS = 2,
+	STA_STAT_GROUP_ID_DELAY_STATS = 10,
+};
+
+/**
+ * counter_stats - structure to hold stats of group id 0
+ * @transmitted_fragment_count: transmitted fragment count
+ * @group_transmitted_frame_count: group transmitted frame count
+ * @failed_count: failed count
+ * @group_received_frame_count: group received frame count
+ * @fcs_error_count: face error count
+ * @transmitted_frame_count: transmitted frame count
+ * @received_fragment_count: received fragment count
+ */
+struct counter_stats {
+	uint32_t transmitted_fragment_count;
+	uint32_t group_transmitted_frame_count;
+	uint32_t failed_count;
+	uint32_t group_received_frame_count;
+	uint32_t fcs_error_count;
+	uint32_t transmitted_frame_count;
+	uint32_t received_fragment_count;
+};
+
+/**
+ * mac_stats - struct to hold group id 1 stats
+ * @retry_count: retry count
+ * @multiple_retry_count: multiple retry count
+ * @frame_duplicate_count: frame duplicate count
+ * @rts_success_count: rts success count
+ * @rts_failure_count: rts failure count
+ * @ack_failure_count: ack failure count
+ */
+struct mac_stats {
+	uint32_t retry_count;
+	uint32_t multiple_retry_count;
+	uint32_t frame_duplicate_count;
+	uint32_t rts_success_count;
+	uint32_t rts_failure_count;
+	uint32_t ack_failure_count;
+};
+
+/**
+ * struct access_delay_stats - struct for group id 10 stats
+ * @ap_average_access_delay: ap average access delay
+ * @average_access_delay_besteffort: access delay best effort
+ * @average_access_delay_background: average access delay background
+ * @average_access_delay_video: average access delay video
+ * @average_access_delay_voice: average access delay voice
+ * station_count: station count
+ * channel_utilization: channel utilization
+ */
+struct access_delay_stats {
+	uint8_t ap_average_access_delay;
+	uint8_t average_access_delay_besteffort;
+	uint8_t average_access_delay_background;
+	uint8_t average_access_delay_video;
+	uint8_t average_access_delay_voice;
+	uint16_t station_count;
+	uint8_t channel_utilization;
+};
+
+/**
+ * union stats_group_data - stats data for provided group id
+ * @counter stats - stats for group id 0
+ * @mac_stats - stats for group id 1
+ */
+union stats_group_data {
+	struct counter_stats counter_stats;
+	struct mac_stats mac_stats;
+	struct access_delay_stats access_delay_stats;
+};
+
+/**
+ * struct statistics_report - To store sta statistics report
+ * @meas_duration: measurement duration
+ * @group id: stats group id
+ * @group stats: stats data
+ */
+struct statistics_report {
+	uint8_t meas_duration;
+	uint8_t group_id;
+	union stats_group_data group_stats;
+};
+
 typedef struct sSirMacRadioMeasureReport {
 	uint8_t token;
 	uint8_t refused;
@@ -1354,6 +1466,8 @@ typedef struct sSirMacRadioMeasureReport {
 	uint8_t type;
 	union {
 		tSirMacBeaconReport beaconReport;
+		struct chan_load_report channel_load_report;
+		struct statistics_report statistics_report;
 	} report;
 
 } tSirMacRadioMeasureReport, *tpSirMacRadioMeasureReport;

+ 3 - 2
core/mac/inc/wni_api.h

@@ -85,9 +85,10 @@ enum eWniMsgTypes {
 	eWNI_SME_NEIGHBOR_REPORT_IND = SIR_SME_MSG_TYPES_BEGIN + 44,
 	eWNI_SME_BEACON_REPORT_REQ_IND = SIR_SME_MSG_TYPES_BEGIN + 45,
 	eWNI_SME_BEACON_REPORT_RESP_XMIT_IND = SIR_SME_MSG_TYPES_BEGIN + 46,
+	eWNI_SME_CHAN_LOAD_REQ_IND = SIR_SME_MSG_TYPES_BEGIN + 47,
+	eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND = SIR_SME_MSG_TYPES_BEGIN + 48,
 
-	/* unused SIR_SME_MSG_TYPES_BEGIN + 47, */
-	/* unused SIR_SME_MSG_TYPES_BEGIN + 48, */
+	/* unused SIR_SME_MSG_TYPES_BEGIN + 49, */
 	eWNI_SME_FT_AGGR_QOS_REQ = SIR_SME_MSG_TYPES_BEGIN + 52,
 	eWNI_SME_FT_AGGR_QOS_RSP = SIR_SME_MSG_TYPES_BEGIN + 53,
 

+ 102 - 6
core/mac/src/cfg/cfgUtil/dot11f.frms

@@ -1666,6 +1666,21 @@ IE last_beacon_report_indication (EID_BCN_REPORT_LAST_BEACON_REPORT_INDICATION)
     last_fragment, 1;
 }
 
+const EID_REPORTING_REASON = 1;
+IE reporting_reason (EID_REPORTING_REASON)
+{
+   {
+      failed_count: 1;
+      fcs_error: 1;
+      multiple_retry: 1;
+      frame_duplicate: 1;
+      rts_failure: 1;
+      ack_failure: 1;
+      retry: 1;
+      reserved: 1;
+   }
+}
+
 IE MeasurementReport (EID_MEAS_REPORT)    // 7.3.2.22
 {
     token, 1;
@@ -1715,6 +1730,14 @@ IE MeasurementReport (EID_MEAS_REPORT)    // 7.3.2.22
             rpi6_density,    1;
             rpi7_density,    1;
         }
+        channel_load_report (type IS 3)
+        {
+            op_class,          1;
+            channel,           1;
+            meas_start_time,   8;
+            meas_duration,     2;
+            chan_load,         1;
+        }
        Beacon (type IS 5)
        {
            regClass,               1;
@@ -1736,7 +1759,62 @@ IE MeasurementReport (EID_MEAS_REPORT)    // 7.3.2.22
            OPTIE last_beacon_report_indication;
            //IE vendor_specific
      }
-    };
+     sta_stats (type IS 7)
+     {
+           meas_duration,          2;
+           group_id, 1;
+           UNION statsgroupdata (DISCRIMINATOR group_id)
+           {
+                dot11_counter_stats (group_id IS 0)
+                {
+                        transmitted_fragment_count, 4;
+                        group_transmitted_frame_count, 4;
+                        failed_count, 4;
+                        received_fragment_count, 4;
+                        group_received_frame_count, 4;
+                        fcs_error_count, 4;
+                        transmitted_frame_count, 4;
+                }
+                dot11_mac_stats (group_id IS 1)
+                {
+                        retry_count, 4;
+                        multiple_retry_count, 4;
+                        frame_duplicate_count, 4;
+                        rts_success_count, 4;
+                        rts_failure_count, 4;
+                        ack_failure_count, 4;
+                }
+                dot11_qos_counter (group_id IS 2)
+                {
+                        qos_transmitted_fragment_count, 4;
+                        qos_failed_count, 4;
+                        qos_retry_count, 4;
+                        qos_multiple_retry_count, 4;
+                        qos_frame_duplicate_count, 4;
+                        qos_rts_success_count, 4;
+                        qos_rts_failure_count, 4;
+                        qos_ack_failure_count, 4;
+                        qos_received_fragment_count, 4;
+                        qos_transmitted_frame_count, 4;
+                        qos_discarded_frame_count, 4;
+                        qos_mpdus_received_count, 4;
+                        qos_retries_received_count, 4;
+                }
+                dot11_bss_average_access_delay (group_id IS 10)
+                {
+                        ap_average_access_delay, 2;
+                        average_access_delay_besteffort, 2;
+                        average_access_delay_background, 2;
+                        average_access_delay_video, 2;
+                        average_access_delay_voice, 2;
+                        station_count, 2;
+                        channel_utilization, 2;
+                }
+            };
+            OPTIE reporting_reason;
+      }
+
+   };
 }
 
 IE TSDelay (EID_TS_DELAY)                 // 7.3.2.32
@@ -2905,7 +2983,7 @@ IE dh_parameter_element (EID_EXTN_ID_ELEMENT) OUI ( 0x20 )
     public_key[0..255];
 }
 
-const EID_RRM_BEACON_REPORTING     = 1;
+const EID_RRM_REPORTING     = 1;
 const EID_RRM_BCN_REPORTING_DETAIL = 2;
 
 const SUB_EID_AZIMUTH_REQ = 1;
@@ -2913,11 +2991,12 @@ const SUB_EID_REQ_MAC_ADDR = 2;
 const SUB_EID_TGT_MAC_ADDR = 3;
 const SUB_EID_MAX_AGE = 4;
 const SUB_EID_NEIGHBOR_RPT = 52;
+//const SUB_EID_TRIGGERED_REPORTING = 1;
 
-IE BeaconReporting (EID_RRM_BEACON_REPORTING)
+IE rrm_reporting (EID_RRM_REPORTING)
 {
-     reportingCondition, 1;
-     threshold,          1;
+     reporting_condition, 1;
+     threshold,           1;
 }
 
 IE BcnReportingDetail (EID_RRM_BCN_REPORTING_DETAIL)
@@ -3019,6 +3098,14 @@ IE MeasurementRequest (EID_MEAS_REQUEST)  // 7.3.2.21
            meas_start_time[8];
            meas_duration,    2;
        }
+       channel_load (measurement_type IS 3)
+       {
+           op_class,                1;
+           channel,                 1;
+           randomization_intv,      2;
+           meas_duration,           2;
+           OPTIE rrm_reporting;
+       }
        Beacon (measurement_type IS 5)
        {
           regClass,          1;
@@ -3028,7 +3115,7 @@ IE MeasurementRequest (EID_MEAS_REQUEST)  // 7.3.2.21
           meas_mode,         1;
           BSSID[6];
           OPTIE SSID;
-          OPTIE BeaconReporting;
+          OPTIE rrm_reporting;
           OPTIE BcnReportingDetail;
           OPTIE RequestedInfo;
           OPTIE APChannelReport[0..2];
@@ -3051,6 +3138,15 @@ IE MeasurementRequest (EID_MEAS_REQUEST)  // 7.3.2.21
           OPTIE neighbor_rpt;
           OPTIE max_age;
        }
+       sta_stats (measurement_type IS 7)
+       {
+          peer_mac_addr[6];
+          randomization,     2;
+          meas_duration,     2;
+          group_identity,    1;
+          //OPTIE triggered_reporting;
+         //OPTIONAL vendor_specific;
+       }
 
     };
 }

+ 157 - 43
core/mac/src/include/dot11f.h

@@ -27,7 +27,7 @@
  *
  *
  * This file was automatically generated by 'framesc'
- * Tue May 30 09:55:35 2023 from the following file(s):
+ * Wed Aug 16 05:58:15 2023 from the following file(s):
  *
  * dot11f.frms
  *
@@ -3276,46 +3276,6 @@ uint32_t dot11f_get_packed_ie_BeaconReportFrmBody(
 }; /* End extern "C". */
 #endif /* C++ */
 
-/* EID 1 (0x01) */
-typedef struct sDot11fIEBeaconReporting {
-	uint8_t             present;
-	uint8_t             reportingCondition;
-	uint8_t             threshold;
-} tDot11fIEBeaconReporting;
-
-#define DOT11F_EID_BEACONREPORTING (1)
-
-/* N.B. These #defines do *not* include the EID & length */
-#define DOT11F_IE_BEACONREPORTING_MIN_LEN (2)
-
-#define DOT11F_IE_BEACONREPORTING_MAX_LEN (2)
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* C++ */
-__must_check uint32_t dot11f_unpack_ie_beacon_reporting(
-	tpAniSirGlobal,
-	uint8_t *,
-	uint8_t,
-	tDot11fIEBeaconReporting*,
-	bool);
-
-uint32_t dot11f_pack_ie_beacon_reporting(
-	tpAniSirGlobal,
-	tDot11fIEBeaconReporting *,
-	uint8_t *,
-	uint32_t,
-	uint32_t*);
-
-uint32_t dot11f_get_packed_ie_BeaconReporting(
-	tpAniSirGlobal,
-	tDot11fIEBeaconReporting *,
-	uint32_t*);
-
-#ifdef __cplusplus
-}; /* End extern "C". */
-#endif /* C++ */
-
 /* EID 2 (0x02) */
 typedef struct sDot11fIECondensedCountryStr {
 	uint8_t             present;
@@ -4637,6 +4597,52 @@ uint32_t dot11f_get_packed_ie_neighbor_rpt(
 }; /* End extern "C". */
 #endif /* C++ */
 
+/* EID 1 (0x01) */
+typedef struct sDot11fIEreporting_reason {
+	uint8_t             present;
+	uint8_t         failed_count:1;
+	uint8_t            fcs_error:1;
+	uint8_t       multiple_retry:1;
+	uint8_t      frame_duplicate:1;
+	uint8_t          rts_failure:1;
+	uint8_t          ack_failure:1;
+	uint8_t                retry:1;
+	uint8_t             reserved:1;
+} tDot11fIEreporting_reason;
+
+#define DOT11F_EID_REPORTING_REASON (1)
+
+/* N.B. These #defines do *not* include the EID & length */
+#define DOT11F_IE_REPORTING_REASON_MIN_LEN (1)
+
+#define DOT11F_IE_REPORTING_REASON_MAX_LEN (1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* C++ */
+__must_check uint32_t dot11f_unpack_ie_reporting_reason(
+	tpAniSirGlobal,
+	uint8_t *,
+	uint8_t,
+	tDot11fIEreporting_reason*,
+	bool);
+
+uint32_t dot11f_pack_ie_reporting_reason(
+	tpAniSirGlobal,
+	tDot11fIEreporting_reason *,
+	uint8_t *,
+	uint32_t,
+	uint32_t*);
+
+uint32_t dot11f_get_packed_ie_reporting_reason(
+	tpAniSirGlobal,
+	tDot11fIEreporting_reason *,
+	uint32_t*);
+
+#ifdef __cplusplus
+}; /* End extern "C". */
+#endif /* C++ */
+
 /* EID 2 (0x02) */
 typedef struct sDot11fIEreq_mac_addr {
 	uint8_t             present;
@@ -4676,6 +4682,46 @@ uint32_t dot11f_get_packed_ie_req_mac_addr(
 }; /* End extern "C". */
 #endif /* C++ */
 
+/* EID 1 (0x01) */
+typedef struct sDot11fIErrm_reporting {
+	uint8_t             present;
+	uint8_t             reporting_condition;
+	uint8_t             threshold;
+} tDot11fIErrm_reporting;
+
+#define DOT11F_EID_RRM_REPORTING (1)
+
+/* N.B. These #defines do *not* include the EID & length */
+#define DOT11F_IE_RRM_REPORTING_MIN_LEN (2)
+
+#define DOT11F_IE_RRM_REPORTING_MAX_LEN (2)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* C++ */
+__must_check uint32_t dot11f_unpack_ie_rrm_reporting(
+	tpAniSirGlobal,
+	uint8_t *,
+	uint8_t,
+	tDot11fIErrm_reporting*,
+	bool);
+
+uint32_t dot11f_pack_ie_rrm_reporting(
+	tpAniSirGlobal,
+	tDot11fIErrm_reporting *,
+	uint8_t *,
+	uint32_t,
+	uint32_t*);
+
+uint32_t dot11f_get_packed_ie_rrm_reporting(
+	tpAniSirGlobal,
+	tDot11fIErrm_reporting *,
+	uint32_t*);
+
+#ifdef __cplusplus
+}; /* End extern "C". */
+#endif /* C++ */
+
 /* EID 255 (0xff) Extended EID 89 (0x59) */
 typedef struct sDot11fIEtclas_mask {
 	uint8_t             present;
@@ -5968,6 +6014,13 @@ typedef struct sDot11fIEMeasurementReport {
 			uint8_t rpi6_density;
 			uint8_t rpi7_density;
 		} RPIHistogram; /* type = 2 */
+		struct {
+			uint8_t op_class;
+			uint8_t channel;
+			tDOT11F_U64 meas_start_time;
+			uint16_t meas_duration;
+			uint8_t chan_load;
+		} channel_load_report; /* type = 3 */
 		struct {
 			uint8_t regClass;
 			uint8_t channel;
@@ -5984,6 +6037,54 @@ typedef struct sDot11fIEMeasurementReport {
 	tDot11fIEbeacon_report_frm_body_fragment_id beacon_report_frm_body_fragment_id;
 	tDot11fIElast_beacon_report_indication last_beacon_report_indication;
 		} Beacon; /* type = 5 */
+		struct {
+			uint16_t meas_duration;
+			uint8_t group_id;
+			union {
+				struct {
+					uint32_t transmitted_fragment_count;
+					uint32_t group_transmitted_frame_count;
+					uint32_t failed_count;
+					uint32_t received_fragment_count;
+					uint32_t group_received_frame_count;
+					uint32_t fcs_error_count;
+					uint32_t transmitted_frame_count;
+				} dot11_counter_stats; /* group_id = 0 */
+				struct {
+					uint32_t retry_count;
+					uint32_t multiple_retry_count;
+					uint32_t frame_duplicate_count;
+					uint32_t rts_success_count;
+					uint32_t rts_failure_count;
+					uint32_t ack_failure_count;
+				} dot11_mac_stats; /* group_id = 1 */
+				struct {
+					uint32_t qos_transmitted_fragment_count;
+					uint32_t qos_failed_count;
+					uint32_t qos_retry_count;
+					uint32_t qos_multiple_retry_count;
+					uint32_t qos_frame_duplicate_count;
+					uint32_t qos_rts_success_count;
+					uint32_t qos_rts_failure_count;
+					uint32_t qos_ack_failure_count;
+					uint32_t qos_received_fragment_count;
+					uint32_t qos_transmitted_frame_count;
+					uint32_t qos_discarded_frame_count;
+					uint32_t qos_mpdus_received_count;
+					uint32_t qos_retries_received_count;
+				} dot11_qos_counter; /* group_id = 2 */
+				struct {
+					uint16_t ap_average_access_delay;
+					uint16_t average_access_delay_besteffort;
+					uint16_t average_access_delay_background;
+					uint16_t average_access_delay_video;
+					uint16_t average_access_delay_voice;
+					uint16_t station_count;
+					uint16_t channel_utilization;
+				} dot11_bss_average_access_delay; /* group_id = 10 */
+			} statsgroupdata;
+	tDot11fIEreporting_reason reporting_reason;
+		} sta_stats; /* type = 7 */
 	} report;
 } tDot11fIEMeasurementReport;
 
@@ -5992,7 +6093,7 @@ typedef struct sDot11fIEMeasurementReport {
 /* N.B. These #defines do *not* include the EID & length */
 #define DOT11F_IE_MEASUREMENTREPORT_MIN_LEN (3)
 
-#define DOT11F_IE_MEASUREMENTREPORT_MAX_LEN (29)
+#define DOT11F_IE_MEASUREMENTREPORT_MAX_LEN (58)
 
 #ifdef __cplusplus
 extern "C" {
@@ -6047,6 +6148,13 @@ typedef struct sDot11fIEMeasurementRequest {
 			uint8_t meas_start_time[8];
 			uint16_t meas_duration;
 		} RPIHistogram; /* measurement_type = 2 */
+		struct {
+			uint8_t op_class;
+			uint8_t channel;
+			uint16_t randomization_intv;
+			uint16_t meas_duration;
+	tDot11fIErrm_reporting rrm_reporting;
+		} channel_load; /* measurement_type = 3 */
 		struct {
 			uint8_t regClass;
 			uint8_t channel;
@@ -6055,7 +6163,7 @@ typedef struct sDot11fIEMeasurementRequest {
 			uint8_t meas_mode;
 			uint8_t BSSID[6];
 	tDot11fIESSID SSID;
-	tDot11fIEBeaconReporting BeaconReporting;
+	tDot11fIErrm_reporting rrm_reporting;
 	tDot11fIEBcnReportingDetail BcnReportingDetail;
 	tDot11fIERequestedInfo RequestedInfo;
 	uint16_t num_APChannelReport;
@@ -6075,6 +6183,12 @@ typedef struct sDot11fIEMeasurementRequest {
 	tDot11fIEneighbor_rpt neighbor_rpt;
 	tDot11fIEmax_age max_age;
 		} ftmrr; /* measurement_type = 16 */
+		struct {
+			uint8_t peer_mac_addr[6];
+			uint16_t randomization;
+			uint16_t meas_duration;
+			uint8_t group_identity;
+		} sta_stats; /* measurement_type = 7 */
 	} measurement_request;
 } tDot11fIEMeasurementRequest;
 

+ 27 - 1
core/mac/src/include/parser_api.h

@@ -823,7 +823,7 @@ populate_dot11f_ext_supp_rates(struct mac_context *mac,
  * @pBeaconReport: Pointer to the Beacon Report structure
  * @is_last_frame: is the current report last or more reports to follow
  *
- * Return: Ret Status
+ * Return: QDF Status
  */
 QDF_STATUS
 populate_dot11f_beacon_report(struct mac_context *mac,
@@ -831,6 +831,32 @@ populate_dot11f_beacon_report(struct mac_context *mac,
 			tSirMacBeaconReport *pBeaconReport,
 			bool is_last_frame);
 
+/**
+ * populate_dot11f_chan_load_report() - populate the chan load Report IE
+ * @mac: pointer to the global MAC context
+ * @dot11f: pointer to the measurement report structure
+ * @channel_load_report: pointer to the chan load Report structure
+ *
+ * Return: none
+ */
+void
+populate_dot11f_chan_load_report(struct mac_context *mac,
+				 tDot11fIEMeasurementReport *dot11f,
+				 struct chan_load_report *channel_load_report);
+
+/**
+ * populate_dot11f_rrm_sta_stats_report() - Populate RRM STA STATS Report IE
+ * @mac: Pointer to the global MAC context
+ * @pdot11f: Pointer to the measurement report structure
+ * @statistics_report: Pointer to the RRM STA STATS Report structure
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+populate_dot11f_rrm_sta_stats_report(
+		struct mac_context *mac, tDot11fIEMeasurementReport *pdot11f,
+		struct statistics_report *statistics_report);
+
 /**
  * \brief Populate a tDot11fIEExtSuppRates
  *

+ 1 - 1
core/mac/src/include/sir_params.h

@@ -709,7 +709,7 @@ enum halmsgtype {
 #define SIR_LIM_WPS_OVERLAP_TIMEOUT      (SIR_LIM_TIMEOUT_MSG_START + 0x1D)
 #define SIR_LIM_FT_PREAUTH_RSP_TIMEOUT   (SIR_LIM_TIMEOUT_MSG_START + 0x1E)
 
-/* currently unused                     (SIR_LIM_TIMEOUT_MSG_START + 0x24) */
+#define SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT    (SIR_LIM_TIMEOUT_MSG_START + 0x24)
 /* currently unused                     (SIR_LIM_TIMEOUT_MSG_START + 0x25) */
 
 #define SIR_LIM_DISASSOC_ACK_TIMEOUT       (SIR_LIM_TIMEOUT_MSG_START + 0x26)

+ 52 - 0
core/mac/src/pe/include/rrm_api.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2011-2012, 2014-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -90,6 +91,17 @@ QDF_STATUS
 rrm_process_beacon_report_xmit(struct mac_context *mac_ctx,
 			       tpSirBeaconReportXmitInd beacon_xmit_ind);
 
+/**
+ * rrm_process_chan_load_report_xmit() - process channel load report xmit
+ * @mac_ctx: Mac context
+ * @chan_load_ind: channel load xmit structure
+ *
+ * Return: None
+ */
+void
+rrm_process_chan_load_report_xmit(struct mac_context *mac_ctx,
+				  struct chan_load_xmit_ind *chan_load_ind);
+
 /**
  * rrm_get_country_code_from_connected_profile() - get country code
  * from connected profile
@@ -121,4 +133,44 @@ QDF_STATUS rrm_reject_req(tpSirMacRadioMeasureReport *radiomes_report,
 			  uint8_t measurement_type);
 
 void lim_update_rrm_capability(struct mac_context *mac_ctx);
+
+#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
+/**
+ * rrm_send_sta_stats_req - Send RRM STA STATS request
+ * @mac: mac context
+ * @session: pe session
+ * @peer_mac: peer mac
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+rrm_send_sta_stats_req(struct mac_context *mac,
+		       struct pe_session *session,
+		       tSirMacAddr peer_mac);
+#else
+static inline QDF_STATUS
+rrm_send_sta_stats_req(struct mac_context *mac,
+		       struct pe_session *session,
+		       tSirMacAddr peer_mac)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
+/**
+ * rrm_process_rrm_sta_stats_request_failure: send RRM STA Stats report with
+ * failure
+ * @mac: mac context
+ * @pe_session: pe session
+ * @peer: peer mac
+ * @status: failure status
+ * @index: index of report
+ *
+ * Return: void
+ */
+void
+rrm_process_rrm_sta_stats_request_failure(struct mac_context *mac,
+					  struct pe_session *pe_session,
+					  tSirMacAddr peer,
+					  tRrmRetStatus status, uint8_t index);
 #endif

+ 72 - 1
core/mac/src/pe/include/rrm_global.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2012, 2014-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -52,6 +52,60 @@ struct sir_channel_info {
 	uint32_t chan_freq;
 };
 
+/**
+ * struct ch_load_ind - Contains info for channel load request received from AP
+ * @message_type: message type eWNI_SME_CHAN_LOAD_REQ_IND
+ * @length: size of struct chan_load_req_ind
+ * @measurement_idx: measurement index for channel load request
+ * @peer_addr: connected peer mac address
+ * @dialog_token: dialog token
+ * @msg_source: message source of type enum tRrmMsgReqSource
+ * @op_class: regulatory class
+ * @channel: channel number
+ * @randomization_intv: Random interval in ms
+ * @meas_duration: measurement duration in ms
+ */
+struct ch_load_ind {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t measurement_idx;
+	struct qdf_mac_addr peer_addr;
+	uint16_t dialog_token;
+	tRrmMsgReqSource msg_source;
+	uint8_t op_class;
+	uint8_t channel;
+	uint16_t randomization_intv;
+	uint16_t meas_duration;
+};
+
+/**
+ * struct chan_load_xmit_ind - Contains info for channel load xmit indication
+ * @message_type: message type eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND
+ * @length: size of struct chan_load_req_ind
+ * @measurement_idx: measurement index for channel load request
+ * @peer_addr: MAC address of the BSS
+ * @dialog_token: dialog token
+ * @op_class: regulatory class
+ * @channel: channel number
+ * @duration: measurement duration in ms
+ * @chan_load: channel utilization measurement
+ * @rrm_scan_tsf: time at which driver triggers rrm scan for channel load
+ * @is_report_success: need to send failure report or not
+ */
+struct chan_load_xmit_ind {
+	uint16_t messageType;
+	uint16_t length;
+	uint8_t measurement_idx;
+	struct qdf_mac_addr peer_addr;
+	uint16_t dialog_token;
+	uint8_t op_class;
+	uint8_t channel;
+	uint16_t duration;
+	uint8_t chan_load;
+	qdf_time_t rrm_scan_tsf;
+	bool is_report_success;
+};
+
 typedef struct sSirBeaconReportReqInd {
 	uint16_t messageType;   /* eWNI_SME_BEACON_REPORT_REQ_IND */
 	uint16_t length;
@@ -205,6 +259,22 @@ typedef struct sRRMCaps {
 	uint8_t reserved:4;
 } tRRMCaps, *tpRRMCaps;
 
+/**
+ * struct rrm_sta_stats - RRM sta stats structure
+ * @rrm_report: rrm_report
+ * @peer: peer address
+ * @index: current req index
+ * @rrm_sta_stats_res_count: sta stats response count
+ * @vdev_id: vdev_id
+ */
+struct rrm_sta_stats {
+	tSirMacRadioMeasureReport rrm_report;
+	tSirMacAddr peer;
+	uint8_t index;
+	uint8_t rrm_sta_stats_res_count;
+	uint8_t vdev_id;
+};
+
 typedef struct sRrmPEContext {
 	uint8_t rrmEnable;
 	/*
@@ -225,6 +295,7 @@ typedef struct sRrmPEContext {
 	tpRRMReq pCurrentReq[MAX_MEASUREMENT_REQUEST];
 	uint32_t beacon_rpt_chan_list[MAX_NUM_CHANNELS];
 	uint8_t beacon_rpt_chan_num;
+	struct rrm_sta_stats rrm_sta_stats;
 } tRrmPEContext, *tpRrmPEContext;
 
 /* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */

+ 12 - 28
core/mac/src/pe/lim/lim_api.c

@@ -509,7 +509,6 @@ static void lim_state_info_dump(char **buf_ptr, uint16_t *size)
 
 	mac = cds_get_context(QDF_MODULE_ID_PE);
 	if (!mac) {
-		QDF_ASSERT(0);
 		return;
 	}
 
@@ -3964,18 +3963,11 @@ lim_check_scan_db_for_join_req_partner_info(struct pe_session *session_entry,
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	cache_entry = qdf_mem_malloc(sizeof(struct scan_cache_entry));
-
-	if (!cache_entry)
-		return QDF_STATUS_E_FAILURE;
-
 	partner_link = qdf_mem_malloc(sizeof(struct partner_link_info) *
 			(MLD_MAX_LINKS - 1));
 
-	if (!partner_link) {
-		status = QDF_STATUS_E_FAILURE;
-		goto free_cache_entry;
-	}
+	if (!partner_link)
+		return QDF_STATUS_E_FAILURE;
 
 	qdf_mem_copy(&qdf_bssid,
 		     &(lim_join_req->bssDescription.bssId),
@@ -3983,12 +3975,11 @@ lim_check_scan_db_for_join_req_partner_info(struct pe_session *session_entry,
 
 	join_req_freq = lim_join_req->bssDescription.chan_freq;
 
-	status = wlan_scan_get_scan_entry_by_mac_freq(pdev,
-						      &qdf_bssid,
-						      join_req_freq,
-						      cache_entry);
+	cache_entry = wlan_scan_get_scan_entry_by_mac_freq(pdev,
+							   &qdf_bssid,
+							   join_req_freq);
 
-	if (!QDF_IS_STATUS_SUCCESS(status)) {
+	if (!cache_entry) {
 		pe_err("failed to get partner link info by mac addr");
 		status = QDF_STATUS_E_FAILURE;
 		goto free_mem;
@@ -3997,6 +3988,8 @@ lim_check_scan_db_for_join_req_partner_info(struct pe_session *session_entry,
 	qdf_mem_copy(partner_link, cache_entry->ml_info.link_info,
 		     sizeof(struct partner_link_info) * (MLD_MAX_LINKS - 1));
 
+	util_scan_free_cache_entry(cache_entry);
+
 	partner_info = &lim_join_req->partner_info;
 
 	status = lim_compare_scan_entry_partner_info_with_join_req(
@@ -4010,8 +4003,6 @@ lim_check_scan_db_for_join_req_partner_info(struct pe_session *session_entry,
 
 free_mem:
 	qdf_mem_free(partner_link);
-free_cache_entry:
-	qdf_mem_free(cache_entry);
 	return status;
 }
 
@@ -4031,29 +4022,22 @@ QDF_STATUS lim_update_mlo_mgr_info(struct mac_context *mac_ctx,
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	cache_entry = qdf_mem_malloc(sizeof(struct scan_cache_entry));
+	cache_entry = wlan_scan_get_scan_entry_by_mac_freq(pdev, link_addr,
+							   freq);
 	if (!cache_entry)
 		return QDF_STATUS_E_FAILURE;
 
-	status = wlan_scan_get_scan_entry_by_mac_freq(pdev, link_addr, freq,
-						      cache_entry);
-
-	if (!QDF_IS_STATUS_SUCCESS(status)) {
-		status = QDF_STATUS_E_FAILURE;
-		goto free_cache_entry;
-	}
-
 	channel.ch_freq = cache_entry->channel.chan_freq;
 	channel.ch_ieee = wlan_reg_freq_to_chan(pdev, channel.ch_freq);
 	channel.ch_phymode = cache_entry->phy_mode;
 	channel.ch_cfreq1 = cache_entry->channel.cfreq0;
 	channel.ch_cfreq2 = cache_entry->channel.cfreq1;
 
+	util_scan_free_cache_entry(cache_entry);
+
 	mlo_mgr_update_ap_channel_info(vdev, link_id, (uint8_t *)link_addr,
 				       channel);
 
-free_cache_entry:
-	qdf_mem_free(cache_entry);
 	return status;
 }
 #else

+ 8 - 0
core/mac/src/pe/lim/lim_process_message_queue.c

@@ -1149,6 +1149,12 @@ lim_check_mgmt_registered_frames(struct mac_context *mac_ctx, uint8_t *buff_desc
 				}
 			}
 		}
+
+		/*
+		 * Some frames like GAS_INITIAL_REQ are registered with
+		 * SME_SESSION_ID_ANY, and received without session.
+		 */
+		vdev_id = mgmt_frame->sessionId;
 		if (session_entry)
 			vdev_id = session_entry->vdev_id;
 
@@ -1755,6 +1761,7 @@ static void lim_process_messages(struct mac_context *mac_ctx,
 	case eWNI_SME_CHNG_MCC_BEACON_INTERVAL:
 	case eWNI_SME_NEIGHBOR_REPORT_REQ_IND:
 	case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND:
+	case eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND:
 #if defined FEATURE_WLAN_ESE
 	case eWNI_SME_ESE_ADJACENT_AP_REPORT:
 #endif
@@ -1854,6 +1861,7 @@ static void lim_process_messages(struct mac_context *mac_ctx,
 	case SIR_LIM_DISASSOC_ACK_TIMEOUT:
 	case SIR_LIM_AUTH_RETRY_TIMEOUT:
 	case SIR_LIM_AUTH_SAE_TIMEOUT:
+	case SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT:
 		/* These timeout messages are handled by MLM sub module */
 		lim_process_mlm_req_messages(mac_ctx, msg);
 		break;

+ 75 - 0
core/mac/src/pe/lim/lim_process_mlm_req_messages.c

@@ -43,12 +43,15 @@
 #include "wlan_mlme_public_struct.h"
 #include "../../core/src/vdev_mgr_ops.h"
 #include "wlan_pmo_ucfg_api.h"
+#include "wlan_cp_stats_utils_api.h"
 #include "wlan_objmgr_vdev_obj.h"
 #include <wlan_cm_api.h>
 #include <lim_mlo.h>
 #include "wlan_mlo_mgr_peer.h"
 #include <son_api.h>
 #include "wifi_pos_pasn_api.h"
+#include "rrm_api.h"
+#include "../../core/src/wlan_cp_stats_obj_mgr_handler.h"
 
 static void lim_process_mlm_auth_req(struct mac_context *, uint32_t *);
 static void lim_process_mlm_assoc_req(struct mac_context *, uint32_t *);
@@ -96,6 +99,75 @@ static void lim_fill_status_code(uint8_t frame_type,
 	}
 }
 
+void lim_process_rrm_sta_stats_rsp_timeout(struct mac_context *mac)
+{
+	struct pe_session *session;
+	tSirMacRadioMeasureReport rrm_report;
+	QDF_STATUS status;
+	uint8_t index;
+	tpRRMReq pcurrent_req = NULL;
+	tRrmRetStatus rrm_status;
+
+	session = pe_find_session_by_session_id(mac,
+		mac->lim.lim_timers.rrm_sta_stats_resp_timer.sessionId);
+	if (!session) {
+		pe_err("Session does not exist for given session id %d",
+		       mac->lim.lim_timers.rrm_sta_stats_resp_timer.sessionId);
+		rrm_cleanup(mac, mac->rrm.rrmPEContext.rrm_sta_stats.index);
+		return;
+	}
+
+	pe_warn("STA STATS RSP timeout vdev_id %d", session->vdev_id);
+	index = mac->rrm.rrmPEContext.rrm_sta_stats.index;
+	pcurrent_req = mac->rrm.rrmPEContext.pCurrentReq[index];
+	if (!pcurrent_req) {
+		pe_err("Current request is NULL for index %d", index);
+		qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats,
+			     sizeof(mac->rrm.rrmPEContext.rrm_sta_stats));
+		return;
+	}
+
+	if (!mac->rrm.rrmPEContext.rrm_sta_stats.rrm_sta_stats_res_count) {
+		pe_err("response not received for previous req");
+		rrm_status = eRRM_INCAPABLE;
+		goto err;
+	}
+
+	rrm_report = mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report;
+	switch (rrm_report.report.statistics_report.group_id) {
+	/*
+	 * For Counter stats and Mac stats some stats will be received
+	 * via FW and some via DP. So, same handling is required for both
+	 * cases.
+	 */
+	case STA_STAT_GROUP_ID_COUNTER_STATS:
+	case STA_STAT_GROUP_ID_MAC_STATS:
+		status = wlan_cp_stats_infra_cp_deregister_resp_cb(mac->psoc);
+		if (QDF_IS_STATUS_ERROR(status))
+			pe_err("failed to deregister callback %d", status);
+
+		status =
+			rrm_send_sta_stats_req(
+				mac, session,
+				mac->rrm.rrmPEContext.rrm_sta_stats.peer);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("fail to send stats req");
+			rrm_status = eRRM_FAILURE;
+			goto err;
+		}
+		break;
+	case STA_STAT_GROUP_ID_DELAY_STATS:
+		/* TOdo: fetch from scan ie */
+		break;
+	}
+	return;
+err:
+	rrm_process_rrm_sta_stats_request_failure(
+		mac, session, mac->rrm.rrmPEContext.rrm_sta_stats.peer,
+		rrm_status, mac->rrm.rrmPEContext.rrm_sta_stats.index);
+	rrm_cleanup(mac, mac->rrm.rrmPEContext.rrm_sta_stats.index);
+}
+
 void lim_process_sae_auth_timeout(struct mac_context *mac_ctx)
 {
 	struct pe_session *session;
@@ -194,6 +266,9 @@ void lim_process_mlm_req_messages(struct mac_context *mac_ctx,
 	case SIR_LIM_AUTH_SAE_TIMEOUT:
 		lim_process_sae_auth_timeout(mac_ctx);
 		break;
+	case SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT:
+		lim_process_rrm_sta_stats_rsp_timeout(mac_ctx);
+		break;
 	case LIM_MLM_TSPEC_REQ:
 	default:
 		break;

+ 96 - 48
core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c

@@ -2763,9 +2763,15 @@ lim_process_switch_channel_join_mlo(struct pe_session *session_entry,
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct mlo_partner_info *partner_info;
-	struct element_info assoc_rsp;
+	struct element_info assoc_rsp, link_assoc_rsp;
+	tLimMlmJoinCnf mlm_join_cnf;
+	tLimMlmAssocCnf assoc_cnf;
+	uint8_t *frame_ie_buf, *mlie;
+	qdf_size_t frame_ie_len, mlie_len;
+	bool link_id_found = false;
 	struct qdf_mac_addr sta_link_addr;
-	uint8_t link_id = 0;
+	uint8_t assoc_link_id, link_id;
+	struct wlan_frame_hdr *link_frame_hdr;
 
 	assoc_rsp.len = 0;
 	mlo_get_assoc_rsp(session_entry->vdev, &assoc_rsp);
@@ -2780,59 +2786,101 @@ lim_process_switch_channel_join_mlo(struct pe_session *session_entry,
 	qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr,
 		     QDF_MAC_ADDR_SIZE);
 
-	if (assoc_rsp.len) {
-		struct element_info link_assoc_rsp;
-		tLimMlmJoinCnf mlm_join_cnf;
-		tLimMlmAssocCnf assoc_cnf;
+	if (!assoc_rsp.len)
+		return status;
 
-		mlm_join_cnf.resultCode = eSIR_SME_SUCCESS;
-		mlm_join_cnf.protStatusCode = STATUS_SUCCESS;
-		/* Update PE sessionId */
-		mlm_join_cnf.sessionId = session_entry->peSessionId;
-		lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF,
-				     (uint32_t *)&mlm_join_cnf);
+	mlm_join_cnf.resultCode = eSIR_SME_SUCCESS;
+	mlm_join_cnf.protStatusCode = STATUS_SUCCESS;
+	/* Update PE sessionId */
+	mlm_join_cnf.sessionId = session_entry->peSessionId;
+	lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF,
+			     (uint32_t *)&mlm_join_cnf);
 
-		session_entry->limSmeState = eLIM_SME_WT_ASSOC_STATE;
-		assoc_rsp.len += SIR_MAC_HDR_LEN_3A;
-		pe_debug("MLO:assoc rsp len + hdr %d ", assoc_rsp.len);
+	session_entry->limSmeState = eLIM_SME_WT_ASSOC_STATE;
+	assoc_rsp.len += SIR_MAC_HDR_LEN_3A;
+	pe_debug("MLO:assoc rsp len + hdr %d ", assoc_rsp.len);
 
-		link_assoc_rsp.ptr = qdf_mem_malloc(assoc_rsp.len);
-		if (!link_assoc_rsp.ptr)
-			return QDF_STATUS_E_NOMEM;
+	link_assoc_rsp.ptr = qdf_mem_malloc(assoc_rsp.len);
+	if (!link_assoc_rsp.ptr)
+		return QDF_STATUS_E_NOMEM;
 
-		link_assoc_rsp.len = assoc_rsp.len + 24;
-		session_entry->limMlmState = eLIM_MLM_WT_ASSOC_RSP_STATE;
+	link_assoc_rsp.len = assoc_rsp.len + 24;
+	session_entry->limMlmState = eLIM_MLM_WT_ASSOC_RSP_STATE;
 
-		link_id = wlan_vdev_get_link_id(session_entry->vdev);
-		pe_debug("MLO: Generate and process assoc rsp for link vdev %d",
-			 link_id);
-		status = util_gen_link_assoc_rsp(assoc_rsp.ptr,
-						 assoc_rsp.len - 24,
-						 false, link_id, sta_link_addr,
-						 link_assoc_rsp.ptr,
-						 assoc_rsp.len,
-						 (qdf_size_t *)&link_assoc_rsp.len);
-		if (QDF_IS_STATUS_SUCCESS(status)) {
-			pe_debug("MLO: process assoc rsp for link vdev");
-			lim_process_assoc_rsp_frame(mac_ctx,
-					    link_assoc_rsp.ptr,
-					    (link_assoc_rsp.len - SIR_MAC_HDR_LEN_3A),
-					    LIM_ASSOC,
-					    session_entry);
-		} else {
-			pe_debug("MLO: link vdev assoc rsp generation failed");
-			assoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS;
-			assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE;
-			/* Update PE sessionId */
-			assoc_cnf.sessionId = session_entry->peSessionId;
-			lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF,
-					(uint32_t *)&assoc_cnf);
+	link_id = wlan_vdev_get_link_id(session_entry->vdev);
+	pe_debug("MLO: Generate and process assoc rsp for link vdev %d",
+		 link_id);
+
+	if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(session_entry->vdev)) {
+		frame_ie_buf = assoc_rsp.ptr + WLAN_ASSOC_RSP_IES_OFFSET;
+		frame_ie_len = assoc_rsp.len - 24 - WLAN_ASSOC_RSP_IES_OFFSET;
+
+		status = util_find_mlie(frame_ie_buf, frame_ie_len,
+					&mlie, &mlie_len);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_debug("ML IE not found");
+			goto rsp_gen_fail;
 		}
 
-		qdf_mem_free(link_assoc_rsp.ptr);
-		link_assoc_rsp.ptr = NULL;
-		link_assoc_rsp.len = 0;
-	}
+		status = util_get_bvmlie_primary_linkid(mlie, mlie_len,
+							&link_id_found,
+							&assoc_link_id);
+		if (QDF_IS_STATUS_ERROR(status) || !link_id_found) {
+			pe_debug("Assoc link ID not found");
+			goto rsp_gen_fail;
+		}
+
+		if (assoc_link_id != link_id)
+			goto gen_link_assoc_rsp;
+
+		pe_debug("Skip assoc rsp gen for link %d", link_id);
+		link_frame_hdr = (struct wlan_frame_hdr *)link_assoc_rsp.ptr;
+		qdf_ether_addr_copy(link_frame_hdr->i_addr3,
+				    session_entry->bssId);
+		qdf_ether_addr_copy(link_frame_hdr->i_addr2,
+				    session_entry->bssId);
+		qdf_ether_addr_copy(link_frame_hdr->i_addr1,
+				    &sta_link_addr.bytes[0]);
+		link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0;
+		link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1;
+
+		qdf_mem_copy(link_assoc_rsp.ptr + SIR_MAC_HDR_LEN_3A,
+			     assoc_rsp.ptr, assoc_rsp.len - SIR_MAC_HDR_LEN_3A);
+
+		goto process_assoc_rsp;
+	}
+
+gen_link_assoc_rsp:
+	status = util_gen_link_assoc_rsp(assoc_rsp.ptr,
+					 assoc_rsp.len - 24,
+					 false, link_id, sta_link_addr,
+					 link_assoc_rsp.ptr,
+					 assoc_rsp.len,
+					 (qdf_size_t *)&link_assoc_rsp.len);
+process_assoc_rsp:
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		pe_debug("MLO: process assoc rsp for link vdev");
+		lim_process_assoc_rsp_frame(mac_ctx,
+				    link_assoc_rsp.ptr,
+				    (link_assoc_rsp.len - SIR_MAC_HDR_LEN_3A),
+				    LIM_ASSOC,
+				    session_entry);
+		goto mem_free;
+	}
+
+rsp_gen_fail:
+	pe_debug("MLO: link vdev assoc rsp generation failed");
+	assoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS;
+	assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE;
+	/* Update PE sessionId */
+	assoc_cnf.sessionId = session_entry->peSessionId;
+	lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF,
+			(uint32_t *)&assoc_cnf);
+
+mem_free:
+	qdf_mem_free(link_assoc_rsp.ptr);
+	link_assoc_rsp.ptr = NULL;
+	link_assoc_rsp.len = 0;
 
 	return status;
 }

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

@@ -326,6 +326,8 @@ lim_process_probe_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_Packet_info
 
 	if (session_entry->limMlmState ==
 			eLIM_MLM_WT_JOIN_BEACON_STATE) {
+		uint8_t vdev_id = wlan_vdev_get_id(session_entry->vdev);
+
 		/*
 		 * Either Beacon/probe response is required.
 		 * Hence store it in same buffer.
@@ -355,6 +357,8 @@ lim_process_probe_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_Packet_info
 		lim_check_and_announce_join_success(mac_ctx, probe_rsp,
 						header,
 						session_entry);
+		wlan_connectivity_sta_info_event(mac_ctx->psoc, vdev_id);
+
 	} else if (session_entry->limMlmState ==
 		   eLIM_MLM_LINK_ESTABLISHED_STATE) {
 		/*

+ 44 - 5
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -885,7 +885,7 @@ __lim_handle_sme_start_bss_request(struct mac_context *mac_ctx, uint32_t *msg_bu
 	qdf_mem_copy(sme_start_bss_req, msg_buf, size);
 	vdev_id = sme_start_bss_req->vdev_id;
 
-	opmode = wlan_get_opmode_vdev_id(mac_ctx->pdev, vdev_id);
+	opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id);
 	if (opmode == QDF_NDI_MODE)
 		bss_type = eSIR_NDI_MODE;
 	else
@@ -2107,13 +2107,13 @@ lim_get_bss_11be_mode_allowed(struct mac_context *mac_ctx,
 	if (!ie_struct->eht_cap.present)
 		return false;
 
-	scan_entry = scm_scan_get_entry_by_bssid(mac_ctx->pdev,
-						 (struct qdf_mac_addr *)
-						 bss_desc->bssId);
+	scan_entry = wlan_scan_get_entry_by_bssid(mac_ctx->pdev,
+						  (struct qdf_mac_addr *)
+						  bss_desc->bssId);
 
 	if (scan_entry) {
 		is_eht_allowed =
-			cm_is_eht_allowed_for_current_security(scan_entry);
+			wlan_cm_is_eht_allowed_for_current_security(scan_entry);
 		util_scan_free_cache_entry(scan_entry);
 		if (!is_eht_allowed)
 			return false;
@@ -3130,6 +3130,39 @@ static void lim_reset_self_ocv_caps(struct pe_session *session)
 
 }
 
+/**
+ * lim_disable_bformee_for_iot_ap() - disable bformee for iot ap
+ *@mac_ctx: mac context
+ *@session: pe session
+ *@bss_desc: bss descriptor
+ *
+ * When connect IoT AP with BW 160MHz and NSS 2, disable Beamformee
+ *
+ * Return: None
+ */
+static void
+lim_disable_bformee_for_iot_ap(struct mac_context *mac_ctx,
+			       struct pe_session *session,
+			       struct bss_description *bss_desc)
+{
+	struct action_oui_search_attr vendor_ap_search_attr;
+	uint16_t ie_len;
+
+	ie_len = wlan_get_ielen_from_bss_description(bss_desc);
+
+	vendor_ap_search_attr.ie_data = (uint8_t *)&bss_desc->ieFields[0];
+	vendor_ap_search_attr.ie_length = ie_len;
+
+	if (wlan_action_oui_search(mac_ctx->psoc,
+				   &vendor_ap_search_attr,
+				   ACTION_OUI_DISABLE_BFORMEE) &&
+	    session->nss == 2 && CH_WIDTH_160MHZ == session->ch_width) {
+		session->vht_config.su_beam_formee = 0;
+		session->vht_config.mu_beam_formee = 0;
+		pe_debug("IoT ap with BW 160 MHz NSS 2, disable Beamformee");
+	}
+}
+
 QDF_STATUS
 lim_fill_pe_session(struct mac_context *mac_ctx, struct pe_session *session,
 		    struct bss_description *bss_desc)
@@ -3398,6 +3431,8 @@ lim_fill_pe_session(struct mac_context *mac_ctx, struct pe_session *session,
 		&session->gLimCurrentBssUapsd,
 		&local_power_constraint, session, &is_pwr_constraint);
 
+	lim_disable_bformee_for_iot_ap(mac_ctx, session, bss_desc);
+
 	mlme_obj->reg_tpc_obj.is_power_constraint_abs =
 						!is_pwr_constraint;
 
@@ -8018,6 +8053,9 @@ static void __lim_process_report_message(struct mac_context *mac,
 	case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND:
 		rrm_process_beacon_report_xmit(mac, pMsg->bodyptr);
 		break;
+	case eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND:
+		rrm_process_chan_load_report_xmit(mac, pMsg->bodyptr);
+		break;
 	default:
 		pe_err("Invalid msg type: %d", pMsg->type);
 	}
@@ -8731,6 +8769,7 @@ bool lim_process_sme_req_messages(struct mac_context *mac,
 
 	case eWNI_SME_NEIGHBOR_REPORT_REQ_IND:
 	case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND:
+	case eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND:
 		__lim_process_report_message(mac, pMsg);
 		break;
 	case eWNI_SME_FT_AGGR_QOS_REQ:

+ 40 - 8
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -4042,6 +4042,7 @@ QDF_STATUS lim_deauth_tx_complete_cnf(void *context,
 	pe_debug("tx_success: %d", tx_success);
 	if (mgmt_params)
 		vdev_id = mgmt_params->vdev_id;
+	qdf_mem_free(params);
 
 	return lim_send_deauth_cnf(mac_ctx, vdev_id);
 }
@@ -4092,6 +4093,7 @@ static QDF_STATUS lim_deauth_tx_complete_cnf_handler(void *context,
 	uint8_t vdev_id = WLAN_INVALID_VDEV_ID;
 	struct wmi_mgmt_params *mgmt_params =
 			(struct wmi_mgmt_params *)params;
+	struct wmi_mgmt_params *msg_params = NULL;
 
 	if (params)
 		wlan_send_tx_complete_event(context, buf, params, tx_success,
@@ -4137,14 +4139,26 @@ static QDF_STATUS lim_deauth_tx_complete_cnf_handler(void *context,
 		session->deauth_retry.retry_cnt--;
 		return QDF_STATUS_SUCCESS;
 	}
+
+	msg_params = qdf_mem_malloc(sizeof(struct wmi_mgmt_params));
+	if (!msg_params) {
+		pe_err("malloc failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_mem_copy(msg_params, mgmt_params, sizeof(struct wmi_mgmt_params));
+
 	msg.type = (uint16_t) WMA_DEAUTH_TX_COMP;
-	msg.bodyptr = params;
+	msg.bodyptr = msg_params;
 	msg.bodyval = tx_success;
 
 	status_code = lim_post_msg_high_priority(mac_ctx, &msg);
-	if (status_code != QDF_STATUS_SUCCESS)
+	if (status_code != QDF_STATUS_SUCCESS) {
+		qdf_mem_free(msg_params);
 		pe_err("posting message: %X to LIM failed, reason: %d",
 		       msg.type, status_code);
+	}
+
 	return status_code;
 }
 
@@ -5676,6 +5690,26 @@ lim_send_radio_measure_report_action_frame(struct mac_context *mac,
 				pRRMReport[i].refused;
 			frm->MeasurementReport[i].present = 1;
 			break;
+		case SIR_MAC_RRM_CHANNEL_LOAD_TYPE:
+			populate_dot11f_chan_load_report(mac,
+				&frm->MeasurementReport[i],
+				&pRRMReport[i].report.channel_load_report);
+			frm->MeasurementReport[i].incapable =
+				pRRMReport[i].incapable;
+			frm->MeasurementReport[i].refused =
+				pRRMReport[i].refused;
+			frm->MeasurementReport[i].present = 1;
+			break;
+		case SIR_MAC_RRM_STA_STATISTICS_TYPE:
+			populate_dot11f_rrm_sta_stats_report(
+				mac, &frm->MeasurementReport[i],
+				&pRRMReport[i].report.statistics_report);
+			frm->MeasurementReport[i].incapable =
+				pRRMReport[i].incapable;
+			frm->MeasurementReport[i].refused =
+				pRRMReport[i].refused;
+			frm->MeasurementReport[i].present = 1;
+			break;
 		default:
 			frm->MeasurementReport[i].incapable =
 				pRRMReport[i].incapable;
@@ -5751,14 +5785,12 @@ lim_send_radio_measure_report_action_frame(struct mac_context *mac,
 						 wlan_vdev_get_id(pe_session->vdev));
 	}
 
-	pe_nofl_info("TX: %s seq_no:%d dialog_token:%d no. of APs:%d is_last_rpt:%d num_report: %d peer:"QDF_MAC_ADDR_FMT,
-		     frm->MeasurementReport[0].type == SIR_MAC_RRM_BEACON_TYPE ?
-		     "[802.11 BCN_RPT]" : "[802.11 RRM]",
+	pe_nofl_info("TX: type:%d seq_no:%d dialog_token:%d no. of APs:%d is_last_rpt:%d num_report:%d peer:"QDF_MAC_ADDR_FMT,
+		     frm->MeasurementReport[0].type,
 		     (pMacHdr->seqControl.seqNumHi << HIGH_SEQ_NUM_OFFSET |
 		     pMacHdr->seqControl.seqNumLo),
 		     dialog_token, frm->num_MeasurementReport,
-		     is_last_report, num_report,
-		     QDF_MAC_ADDR_REF(peer));
+		     is_last_report, num_report, QDF_MAC_ADDR_REF(peer));
 
 	if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) ||
 	    pe_session->opmode == QDF_P2P_CLIENT_MODE ||
@@ -5775,7 +5807,7 @@ lim_send_radio_measure_report_action_frame(struct mac_context *mac,
 			 pe_session->peSessionId, qdf_status));
 	if (QDF_STATUS_SUCCESS != qdf_status) {
 		pe_nofl_err("TX: [802.11 RRM] Send FAILED! err_status [%d]",
-		       qdf_status);
+			    qdf_status);
 		status_code = QDF_STATUS_E_FAILURE;
 		/* Pkt will be freed up by the callback */
 	}

+ 32 - 0
core/mac/src/pe/lim/lim_timer_utils.c

@@ -49,6 +49,12 @@
  */
 #define LIM_AUTH_SAE_TIMER_MS 5000
 
+/*
+ * STA stats resp timer of 10secs. This is required for duration of RRM
+ * STA STATS report response from report request.
+ */
+#define LIM_RRM_STA_STATS_RSP_TIMER_MS 10000
+
 static bool lim_create_non_ap_timers(struct mac_context *mac)
 {
 	uint32_t cfgValue;
@@ -235,10 +241,21 @@ uint32_t lim_create_timers(struct mac_context *mac)
 		goto err_timer;
 	}
 
+	if ((tx_timer_create(mac,
+			     &mac->lim.lim_timers.rrm_sta_stats_resp_timer,
+			     "STA STATS RSP timer",
+			     lim_timer_handler,
+			     SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT,
+			     SYS_MS_TO_TICKS(LIM_RRM_STA_STATS_RSP_TIMER_MS), 0,
+			     TX_NO_ACTIVATE)) != TX_SUCCESS) {
+		pe_err("could not create STA STATS RSP Timer");
+		goto err_timer;
+	}
 	return TX_SUCCESS;
 
 err_timer:
 	lim_delete_timers_host_roam(mac);
+	tx_timer_delete(&mac->lim.lim_timers.rrm_sta_stats_resp_timer);
 	tx_timer_delete(&mac->lim.lim_timers.gLimDeauthAckTimer);
 	tx_timer_delete(&mac->lim.lim_timers.gLimDisassocAckTimer);
 	tx_timer_delete(&mac->lim.lim_timers.gLimUpdateOlbcCacheTimer);
@@ -677,6 +694,21 @@ void lim_deactivate_and_change_timer(struct mac_context *mac, uint32_t timerId)
 			pe_err("unable to change SAE auth timer");
 
 		break;
+	case eLIM_RRM_STA_STATS_RSP_TIMER:
+		if (tx_timer_deactivate
+		   (&mac->lim.lim_timers.rrm_sta_stats_resp_timer)
+		    != TX_SUCCESS)
+			pe_err("Unable to deactivate STA STATS RSP timer");
+
+		/* Change timer to reactivate it in future */
+		val = SYS_MS_TO_TICKS(LIM_RRM_STA_STATS_RSP_TIMER_MS);
+
+		if (tx_timer_change(
+			&mac->lim.lim_timers.rrm_sta_stats_resp_timer,
+			val, 0) != TX_SUCCESS)
+			pe_err("unable to change STA STATS RSP timer");
+
+		break;
 
 	default:
 		/* Invalid timerId. Log error */

+ 3 - 2
core/mac/src/pe/lim/lim_timer_utils.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2014, 2016-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -55,7 +55,8 @@ enum limtimertype {
 	eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER,
 	eLIM_INSERT_SINGLESHOT_NOA_TIMER,
 	eLIM_AUTH_RETRY_TIMER,
-	eLIM_AUTH_SAE_TIMER
+	eLIM_AUTH_SAE_TIMER,
+	eLIM_RRM_STA_STATS_RSP_TIMER
 };
 
 #define LIM_DISASSOC_DEAUTH_ACK_TIMEOUT         500

+ 2 - 1
core/mac/src/pe/lim/lim_trace.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -64,6 +64,7 @@ static uint8_t *__lim_trace_get_timer_string(uint16_t timerId)
 		CASE_RETURN_STRING(eLIM_DEAUTH_ACK_TIMER);
 		CASE_RETURN_STRING(eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER);
 		CASE_RETURN_STRING(eLIM_AUTH_RETRY_TIMER);
+		CASE_RETURN_STRING(eLIM_RRM_STA_STATS_RSP_TIMER);
 	default:
 		return "UNKNOWN";
 		break;

+ 9 - 0
core/mac/src/pe/lim/lim_types.h

@@ -1624,6 +1624,15 @@ void lim_process_assoc_failure_timeout(struct mac_context *mac_ctx,
  */
 void lim_process_sae_auth_timeout(struct mac_context *mac_ctx);
 
+/**
+ * lim_process_rrm_sta_stats_rsp_timeout() - This function is called to process
+ * sta stats response timeout
+ * @mac_ctx: Pointer to Global MAC structure
+ *
+ * @Return: None
+ */
+void lim_process_rrm_sta_stats_rsp_timeout(struct mac_context *mac_ctx);
+
 /**
  * lim_send_frame() - API to send frame
  * @mac_ctx Pointer to Global MAC structure

+ 31 - 7
core/mac/src/pe/lim/lim_utils.c

@@ -71,6 +71,7 @@
 #include <lim_assoc_utils.h>
 #include "wlan_mlme_ucfg_api.h"
 #include "nan_ucfg_api.h"
+#include "wlan_twt_ucfg_ext_cfg.h"
 #ifdef WLAN_FEATURE_11BE
 #include "wma_eht.h"
 #endif
@@ -496,8 +497,13 @@ void lim_deactivate_timers(struct mac_context *mac_ctx)
 		/* Cleanup as if SAE auth timer expired */
 		lim_timer_handler(mac_ctx, SIR_LIM_AUTH_SAE_TIMEOUT);
 	}
-
 	tx_timer_deactivate(&lim_timer->sae_auth_timer);
+
+	if (tx_timer_running(&lim_timer->rrm_sta_stats_resp_timer)) {
+		pe_err("sta stats resp timer running call the timeout API");
+		lim_timer_handler(mac_ctx, SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT);
+	}
+	tx_timer_deactivate(&lim_timer->rrm_sta_stats_resp_timer);
 }
 
 void lim_deactivate_timers_for_vdev(struct mac_context *mac_ctx,
@@ -663,6 +669,7 @@ void lim_cleanup_mlm(struct mac_context *mac_ctx)
 		tx_timer_delete(&lim_timer->gLimDeauthAckTimer);
 
 		tx_timer_delete(&lim_timer->sae_auth_timer);
+		tx_timer_delete(&lim_timer->rrm_sta_stats_resp_timer);
 
 		mac_ctx->lim.gLimTimersCreated = 0;
 	}
@@ -3827,8 +3834,8 @@ void lim_update_sta_run_time_ht_switch_chnl_params(struct mac_context *mac,
 		return;
 	}
 
-	if (wlan_cm_is_vdev_roaming(pe_session->vdev)) {
-		pe_err("Roaming is in progress");
+	if (!wlan_cm_is_vdev_connected(pe_session->vdev)) {
+		pe_err("vdev not connected, ignore HT IE BW update");
 		return;
 	}
 
@@ -7951,7 +7958,7 @@ QDF_STATUS lim_send_he_caps_ie(struct mac_context *mac_ctx,
 				   HE_CAP_80P80_MCS_MAP_LEN;
 	uint8_t num_ppe_th = 0;
 	bool nan_beamforming_supported;
-	bool disable_nan_tx_bf = false;
+	bool disable_nan_tx_bf = false, value = false;
 
 	/* Sending only minimal info(no PPET) to FW now, update if required */
 	qdf_mem_zero(he_caps, he_cap_total_len);
@@ -7995,6 +8002,24 @@ QDF_STATUS lim_send_he_caps_ie(struct mac_context *mac_ctx,
 		num_ppe_th = lim_set_he_caps_ppet(mac_ctx, he_caps,
 						  CDS_BAND_5GHZ);
 
+	if ((device_mode == QDF_STA_MODE) ||
+	    (device_mode == QDF_P2P_CLIENT_MODE)) {
+		ucfg_twt_cfg_get_requestor(mac_ctx->psoc, &value);
+		if (!value) {
+			he_cap->twt_request = false;
+			he_cap->flex_twt_sched = false;
+		}
+		he_cap->twt_responder = false;
+	} else if ((device_mode == QDF_SAP_MODE) ||
+		    (device_mode == QDF_P2P_GO_MODE)) {
+		ucfg_twt_cfg_get_responder(mac_ctx->psoc, &value);
+		if (!value) {
+			he_cap->twt_responder = false;
+			he_cap->flex_twt_sched = false;
+		}
+		he_cap->twt_request = false;
+	}
+
 	status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_CAP,
 			CDS_BAND_5GHZ, &he_caps[2],
 			he_caps[1] + 1 + num_ppe_th);
@@ -10368,9 +10393,8 @@ QDF_STATUS lim_ap_mlme_vdev_rnr_notify(struct pe_session *session)
 		return status;
 	pe_debug("vdev id %d non mlo 6G AP notify co-located AP to update RNR",
 		 wlan_vdev_get_id(session->vdev));
-	vdev_num = policy_mgr_get_mode_specific_conn_info(
-			mac_ctx->psoc, freq_list, vdev_id_list,
-			PM_SAP_MODE);
+	vdev_num = policy_mgr_get_sap_mode_info(mac_ctx->psoc, freq_list,
+						vdev_id_list);
 	for (i = 0; i < vdev_num; i++) {
 		if (vdev_id_list[i] == session->vdev_id)
 			continue;

+ 868 - 34
core/mac/src/pe/rrm/rrm_api.c

@@ -45,6 +45,18 @@
 #include "rrm_api.h"
 #include "wlan_lmac_if_def.h"
 #include "wlan_reg_services_api.h"
+#include "wlan_cp_stats_utils_api.h"
+#include "../../core/src/wlan_cp_stats_obj_mgr_handler.h"
+#include "../../core/src/wlan_cp_stats_defs.h"
+#include "cdp_txrx_host_stats.h"
+
+#define MAX_CTRL_STAT_VDEV_ENTRIES 1
+#define MAX_CTRL_STAT_MAC_ADDR_ENTRIES 1
+#define MAX_RMM_STA_STATS_REQUESTED 2
+#define MAX_MEAS_DURATION_FOR_STA_STATS 10
+
+/* Max passive scan dwell for wide band rrm scan, in milliseconds */
+#define RRM_SCAN_MAX_DWELL_TIME 110
 
 /* -------------------------------------------------------------------- */
 /**
@@ -608,7 +620,548 @@ wlan_diag_log_beacon_rpt_req_event(uint8_t token, uint8_t mode,
 #endif
 
 #define ABS(x)      ((x < 0) ? -x : x)
+
+#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
+/**
+ * rrm_update_mac_cp_stats: update stats of rrm structure of mac
+ * @ev: cp stats event
+ * @mac_ctx: mac context
+ *
+ * Return: None
+ */
+static inline void
+rrm_update_mac_cp_stats(struct infra_cp_stats_event *ev,
+			struct mac_context *mac_ctx)
+{
+	tpSirMacRadioMeasureReport rrm_report;
+	struct counter_stats *counter_stats;
+	struct group_id_0 ev_counter_stats;
+	struct mac_stats *mac_stats;
+	struct group_id_1 ev_mac_stats;
+
+	rrm_report = &mac_ctx->rrm.rrmPEContext.rrm_sta_stats.rrm_report;
+
+	counter_stats =
+		&rrm_report->report.statistics_report.group_stats.counter_stats;
+	mac_stats =
+		&rrm_report->report.statistics_report.group_stats.mac_stats;
+
+	ev_counter_stats = ev->sta_stats->group.counter_stats;
+	ev_mac_stats = ev->sta_stats->group.mac_stats;
+
+	switch (rrm_report->report.statistics_report.group_id) {
+	/*
+	 * Assign count diff in mac rrm sta stats report.
+	 * For first event callback stats will be same as
+	 * send by FW because memset is done for mac rrm sta
+	 * stats before sending rrm sta stats request to FW and
+	 * for second request stats will be the diff of stats send
+	 * by FW and previous stats.
+	 */
+	case STA_STAT_GROUP_ID_COUNTER_STATS:
+		counter_stats->group_transmitted_frame_count =
+			ev_counter_stats.group_transmitted_frame_count -
+			counter_stats->group_transmitted_frame_count;
+		counter_stats->failed_count =
+			ev_counter_stats.failed_count -
+			counter_stats->failed_count;
+		counter_stats->group_received_frame_count =
+			ev_counter_stats.group_received_frame_count -
+			counter_stats->group_received_frame_count;
+		counter_stats->fcs_error_count =
+			ev_counter_stats.fcs_error_count -
+			counter_stats->fcs_error_count;
+		counter_stats->transmitted_frame_count =
+			ev_counter_stats.transmitted_frame_count -
+			counter_stats->transmitted_frame_count;
+		break;
+	case STA_STAT_GROUP_ID_MAC_STATS:
+		mac_stats->rts_success_count =
+			ev_mac_stats.rts_success_count -
+			mac_stats->rts_success_count;
+		mac_stats->rts_failure_count =
+			ev_mac_stats.rts_failure_count -
+			mac_stats->rts_failure_count;
+		mac_stats->ack_failure_count =
+			ev_mac_stats.ack_failure_count -
+			mac_stats->ack_failure_count;
+		break;
+	default:
+		pe_debug("group id not supported");
+	}
+	pe_nofl_debug("counter stats: group frame count ( tx %d rx %d ) failed_count %d fcs_error %d tx frame count %d mac stats: rts success count %d rts fail count %d ack fail count %d",
+		      counter_stats->group_transmitted_frame_count,
+		      counter_stats->group_received_frame_count,
+		      counter_stats->failed_count,
+		      counter_stats->fcs_error_count,
+		      counter_stats->transmitted_frame_count,
+		      mac_stats->rts_success_count,
+		      mac_stats->rts_failure_count,
+		      mac_stats->ack_failure_count);
+}
+
+/**
+ * rmm_sta_stats_response_cb: RRM sta stats response callback
+ * @ev: cp stats event
+ * @cookie: NULL
+ *
+ * Return: None
+ */
+static inline
+void rmm_sta_stats_response_cb(struct infra_cp_stats_event *ev, void *cookie)
+{
+	struct mac_context *mac;
+	struct pe_session *session;
+	uint8_t vdev_id, index;
+	QDF_STATUS status;
+	tpRRMReq pcurrent_req;
+	tSirMacRadioMeasureReport *rrm_report;
+
+	mac = cds_get_context(QDF_MODULE_ID_PE);
+	if (!mac)
+		return;
+	index = mac->rrm.rrmPEContext.rrm_sta_stats.index;
+
+	/* Deregister callback registered in request */
+	status = wlan_cp_stats_infra_cp_deregister_resp_cb(mac->psoc);
+	if (QDF_IS_STATUS_ERROR(status))
+		pe_err("failed to deregister callback %d", status);
+
+	pcurrent_req = mac->rrm.rrmPEContext.pCurrentReq[index];
+	if (!pcurrent_req) {
+		pe_err("Current request is NULL");
+		qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats,
+			     sizeof(mac->rrm.rrmPEContext.rrm_sta_stats));
+		return;
+	}
+
+	vdev_id = mac->rrm.rrmPEContext.rrm_sta_stats.vdev_id;
+	session = pe_find_session_by_vdev_id(mac, vdev_id);
+	if (!session) {
+		pe_err("Session does not exist for given vdev id %d", vdev_id);
+		rrm_cleanup(mac, mac->rrm.rrmPEContext.rrm_sta_stats.index);
+		return;
+	}
+
+	rrm_report = &mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report;
+	rrm_update_mac_cp_stats(ev, mac);
+
+	/* Update resp counter for every response to find second resp*/
+	mac->rrm.rrmPEContext.rrm_sta_stats.rrm_sta_stats_res_count++;
+	/* Send current stats if meas duration is 0. */
+	if (mac->rrm.rrmPEContext.rrm_sta_stats.rrm_sta_stats_res_count ==
+	    MAX_RMM_STA_STATS_REQUESTED ||
+	   !rrm_report->report.statistics_report.meas_duration) {
+		lim_send_radio_measure_report_action_frame(
+			mac, pcurrent_req->dialog_token, 1, true,
+			&mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report,
+			mac->rrm.rrmPEContext.rrm_sta_stats.peer, session);
+
+		rrm_cleanup(mac, index);
+	}
+}
+
+/**
+ * rrm_update_vdev_stats: Update RRM stats from DP
+ * @rrm_report: RRM Measurement Report
+ * @vdev_id: vdev_id
+ *
+ * Return: QDF STATUS
+ */
+static QDF_STATUS
+rrm_update_vdev_stats(tpSirMacRadioMeasureReport rrm_report, uint8_t vdev_id)
+{
+	struct cdp_vdev_stats *stats;
+	QDF_STATUS status;
+	struct counter_stats *counter_stats;
+	struct mac_stats *mac_stats;
+
+	counter_stats =
+		&rrm_report->report.statistics_report.group_stats.counter_stats;
+	mac_stats =
+		&rrm_report->report.statistics_report.group_stats.mac_stats;
+
+	stats = qdf_mem_malloc(sizeof(*stats));
+	if (!stats)
+		return QDF_STATUS_E_NOMEM;
+
+	status =
+		cdp_host_get_vdev_stats(cds_get_context(QDF_MODULE_ID_SOC),
+					vdev_id, stats, true);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to get stats %d", status);
+		qdf_mem_free(stats);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pe_nofl_debug("counter stats count: fragment (tx: %d rx: %d) mac stats count: retry : %d multiple retry: %d frame duplicate %d",
+		      stats->tx.fragment_count, stats->rx.fragment_count,
+		      stats->tx.retry_count, stats->tx.multiple_retry_count,
+		      stats->rx.duplicate_count);
+
+	switch (rrm_report->report.statistics_report.group_id) {
+	case STA_STAT_GROUP_ID_COUNTER_STATS:
+		counter_stats->transmitted_fragment_count =
+			stats->tx.fragment_count -
+				counter_stats->transmitted_fragment_count;
+		counter_stats->received_fragment_count =
+			stats->rx.fragment_count -
+				counter_stats->received_fragment_count;
+		break;
+	case STA_STAT_GROUP_ID_MAC_STATS:
+		mac_stats->retry_count =
+			stats->tx.retry_count - mac_stats->retry_count;
+		mac_stats->multiple_retry_count =
+			stats->tx.multiple_retry_count -
+				mac_stats->multiple_retry_count;
+		mac_stats->frame_duplicate_count =
+			stats->rx.duplicate_count -
+				mac_stats->frame_duplicate_count;
+		break;
+	}
+	qdf_mem_free(stats);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+rrm_send_sta_stats_req(struct mac_context *mac,
+		       struct pe_session *session,
+		       tSirMacAddr peer_mac)
+{
+	struct infra_cp_stats_cmd_info info = {0};
+	get_infra_cp_stats_cb resp_cb = NULL;
+	void *context;
+	QDF_STATUS status;
+	tpSirMacRadioMeasureReport report;
+
+	status = wlan_cp_stats_infra_cp_get_context(mac->psoc, &resp_cb,
+						    &context);
+	if (resp_cb) {
+		pe_err("another request already in progress");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	info.request_cookie = NULL;
+	info.stats_id = TYPE_REQ_CTRL_PATH_RRM_STA_STAT;
+	info.action = ACTION_REQ_CTRL_PATH_STAT_GET;
+	info.infra_cp_stats_resp_cb = rmm_sta_stats_response_cb;
+	info.num_pdev_ids = 0;
+	info.num_vdev_ids = MAX_CTRL_STAT_VDEV_ENTRIES;
+	info.vdev_id[0] = wlan_vdev_get_id(session->vdev);
+	info.num_mac_addr_list = MAX_CTRL_STAT_MAC_ADDR_ENTRIES;
+	info.num_pdev_ids = 0;
+	/*
+	 * FW doesn't send vdev id in response path.
+	 * So, vdev id will be used to get session
+	 * in callback.
+	 */
+	mac->rrm.rrmPEContext.rrm_sta_stats.vdev_id =
+					wlan_vdev_get_id(session->vdev);
+	qdf_mem_copy(&info.peer_mac_addr[0], peer_mac, QDF_MAC_ADDR_SIZE);
+	report = &mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report;
+
+	status = rrm_update_vdev_stats(report, wlan_vdev_get_id(session->vdev));
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to register resp callback: %d", status);
+		return status;
+	}
+
+	status =  wlan_cp_stats_infra_cp_register_resp_cb(mac->psoc, &info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to register resp callback: %d", status);
+		return status;
+	}
+
+	status = wlan_cp_stats_send_infra_cp_req(mac->psoc, &info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to send stats request status: %d", status);
+		goto get_stats_fail;
+	}
+
+	return QDF_STATUS_SUCCESS;
+
+get_stats_fail:
+	status = wlan_cp_stats_infra_cp_deregister_resp_cb(mac->psoc);
+	if (QDF_IS_STATUS_ERROR(status))
+		pe_err("failed to deregister callback %d", status);
+	return status;
+}
+#endif
+
+/**
+ * rrm_process_sta_stats_report_req: Process RRM sta stats request
+ * @mac: mac context
+ * @pCurrentReq: Current RRM request
+ * @pStaStatsReq: RRM Measurement Request
+ * @pe_session: pe session
+ *
+ * Return: rrm status
+ */
+static tRrmRetStatus
+rrm_process_sta_stats_report_req(struct mac_context *mac,
+				 tpRRMReq pCurrentReq,
+				 tDot11fIEMeasurementRequest *sta_stats_req,
+				 struct pe_session *pe_session)
+{
+	QDF_STATUS status;
+	uint8_t meas_duration = 1;
+	struct rrm_sta_stats *rrm_sta_statistics;
+
+	if (sta_stats_req->measurement_request.sta_stats.meas_duration >
+	    MAX_MEAS_DURATION_FOR_STA_STATS) {
+		pe_err("Dropping req measurement duration > threshold %d",
+		       sta_stats_req->measurement_request.sta_stats.meas_duration);
+		return eRRM_INCAPABLE;
+	}
+
+	if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)
+	    sta_stats_req->measurement_request.sta_stats.peer_mac_addr)) {
+		pe_err("Dropping req: broadcast address not supported");
+		return eRRM_INCAPABLE;
+	}
+
+	rrm_sta_statistics = &mac->rrm.rrmPEContext.rrm_sta_stats;
+	if (sta_stats_req->measurement_request.sta_stats.meas_duration)
+		meas_duration =
+		sta_stats_req->measurement_request.sta_stats.meas_duration;
+
+	rrm_sta_statistics->rrm_report.token = pCurrentReq->token;
+	rrm_sta_statistics->rrm_report.type = pCurrentReq->type;
+	rrm_sta_statistics->rrm_report.refused = 0;
+	rrm_sta_statistics->rrm_report.incapable = 0;
+	rrm_sta_statistics->rrm_report.report.statistics_report.group_id =
+	sta_stats_req->measurement_request.sta_stats.group_identity;
+	rrm_sta_statistics->rrm_report.report.statistics_report.meas_duration
+		= sta_stats_req->measurement_request.sta_stats.meas_duration;
+
+	switch  (sta_stats_req->measurement_request.sta_stats.group_identity) {
+	case STA_STAT_GROUP_ID_COUNTER_STATS:
+	case STA_STAT_GROUP_ID_MAC_STATS:
+		status =
+		rrm_send_sta_stats_req(
+		mac, pe_session,
+		sta_stats_req->measurement_request.sta_stats.peer_mac_addr);
+		if (!QDF_IS_STATUS_SUCCESS(status))
+			return eRRM_REFUSED;
+		mac->lim.lim_timers.rrm_sta_stats_resp_timer.sessionId =
+							pe_session->peSessionId;
+		/*
+		 * Start timer of 1 sec even if meas duration is 0.
+		 * To get stats from FW.
+		 */
+		tx_timer_change(&mac->lim.lim_timers.rrm_sta_stats_resp_timer,
+				SYS_MS_TO_TICKS(meas_duration * 1000), 0);
+		/* Activate sta stats resp timer */
+		if (tx_timer_activate(
+		    &mac->lim.lim_timers.rrm_sta_stats_resp_timer) !=
+		    TX_SUCCESS) {
+			pe_err("failed to start sta stats timer");
+			return eRRM_REFUSED;
+		}
+		break;
+	case STA_STAT_GROUP_ID_DELAY_STATS:
+		/* TODO: update access delay from scan IE */
+	default:
+		pe_nofl_err("group id %d not supported",
+		sta_stats_req->measurement_request.sta_stats.group_identity);
+		return eRRM_INCAPABLE;
+	}
+	return eRRM_SUCCESS;
+}
+
+void
+rrm_process_rrm_sta_stats_request_failure(struct mac_context *mac,
+					  struct pe_session *pe_session,
+					  tSirMacAddr peer,
+					  tRrmRetStatus status, uint8_t index)
+{
+	tpSirMacRadioMeasureReport p_report = NULL;
+	tpRRMReq p_current_req = mac->rrm.rrmPEContext.pCurrentReq[index];
+
+	if (!p_current_req) {
+		pe_err("Current request is NULL");
+		return;
+	}
+
+	p_report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport));
+	if (!p_report)
+		return;
+	p_report->token = p_current_req->token;
+	p_report->type = SIR_MAC_RRM_STA_STATISTICS_TYPE;
+
+	pe_debug("Measurement index:%d status %d token %d", index, status,
+		 p_report->token);
+
+	switch (status) {
+	case eRRM_FAILURE: /* fallthrough */
+	case eRRM_REFUSED:
+		p_report->refused = 1;
+		break;
+	case eRRM_INCAPABLE:
+		p_report->incapable = 1;
+		break;
+	default:
+		pe_err("Invalid RRM status, failed to send report");
+		qdf_mem_free(p_report);
+		return;
+	}
+
+	lim_send_radio_measure_report_action_frame(mac,
+						   p_current_req->dialog_token,
+						   1, true,
+						   p_report, peer,
+						   pe_session);
+
+	qdf_mem_free(p_report);
+}
+
+/**
+ * rrm_check_other_sta_sats_req_in_progress: To check if any other sta stats req
+ * in progress
+ * @rrm_req: measurement request
+ *
+ * To avoid any conflict between multiple sta stats request at time of callback
+ * response from FW handle one sta stats request at a time.
+ *
+ * Return: true/false
+ */
+static bool
+rrm_check_other_sta_sats_req_in_progress(
+		tDot11fRadioMeasurementRequest *rrm_req)
+{
+	uint8_t count = 0, i = 0;
+
+	for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) {
+		if (rrm_req->MeasurementRequest[i].measurement_type ==
+		    SIR_MAC_RRM_STA_STATISTICS_TYPE)
+			count++;
+		if (count > 1)
+			return true;
+	}
+	return false;
+}
+
+/**
+ * rrm_process_sta_stats_req: Process RRM sta stats request
+ * @mac: mac context
+ * @session_entry: pe session
+ * @radiomes_report: measurement report
+ * @rrm_req: measurement request
+ * @num_report: no of reports
+ * @index: index of request
+ *
+ * Return: QDF_STATUS
+ */
+static
+QDF_STATUS rrm_process_sta_stats_req(
+			struct mac_context *mac, tSirMacAddr peer,
+			struct pe_session *session_entry,
+			tpSirMacRadioMeasureReport *radiomes_report,
+			tDot11fRadioMeasurementRequest *rrm_req,
+			uint8_t *num_report, int index)
+{
+	tRrmRetStatus rrm_status = eRRM_SUCCESS;
+	tpRRMReq curr_req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (index  >= MAX_MEASUREMENT_REQUEST) {
+		status = rrm_reject_req(radiomes_report,
+					rrm_req, num_report, index,
+					rrm_req->MeasurementRequest[0].
+					measurement_type);
+		return status;
+	}
+
+	if (rrm_check_other_sta_sats_req_in_progress(rrm_req)) {
+		pe_debug("another sta stats request already in progress");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	curr_req = qdf_mem_malloc(sizeof(*curr_req));
+	if (!curr_req) {
+		mac->rrm.rrmPEContext.pCurrentReq[index] = NULL;
+		qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats,
+			     sizeof(mac->rrm.rrmPEContext.rrm_sta_stats));
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	curr_req->dialog_token = rrm_req->DialogToken.token;
+	curr_req->token =
+		rrm_req->MeasurementRequest[index].measurement_token;
+	curr_req->measurement_idx = index;
+	curr_req->type = rrm_req->MeasurementRequest[index].measurement_type;
+
+
+	qdf_mem_set(&mac->rrm.rrmPEContext.rrm_sta_stats,
+		    sizeof(mac->rrm.rrmPEContext.rrm_sta_stats), 0);
+
+	mac->rrm.rrmPEContext.rrm_sta_stats.index = index;
+	mac->rrm.rrmPEContext.pCurrentReq[index] = curr_req;
+	mac->rrm.rrmPEContext.num_active_request++;
+	qdf_mem_copy(mac->rrm.rrmPEContext.rrm_sta_stats.peer,
+		     peer,
+		     QDF_MAC_ADDR_SIZE);
+
+	pe_debug("Processing sta stats Report req %d num_active_req:%d",
+		 index, mac->rrm.rrmPEContext.num_active_request);
+
+	rrm_status = rrm_process_sta_stats_report_req(mac, curr_req,
+		&rrm_req->MeasurementRequest[index], session_entry);
+	if (eRRM_SUCCESS != rrm_status)
+		goto failure;
+
+	return QDF_STATUS_SUCCESS;
+failure:
+	rrm_process_rrm_sta_stats_request_failure(
+			mac, session_entry, peer, rrm_status, index);
+
+	rrm_cleanup(mac, index);
+	return QDF_STATUS_E_FAILURE;
+}
+
 /* -------------------------------------------------------------------- */
+/**
+ * rrm_get_max_meas_duration() - calculate max measurement duration for a
+ * rrm req
+ * @mac: global mac context
+ * @pe_session: per vdev pe context
+ *
+ * Return: max measurement duration
+ */
+static uint16_t rrm_get_max_meas_duration(struct mac_context *mac,
+					  struct pe_session *pe_session)
+{
+	int8_t max_dur;
+	uint16_t max_meas_dur, sign;
+
+	/*
+	 * The logic here is to check the measurement duration passed in the
+	 * beacon request. Following are the cases handled.
+	 * Case 1: If measurement duration received in the beacon request is
+	 * greater than the max measurement duration advertised in the RRM
+	 * capabilities(Assoc Req), and Duration Mandatory bit is set to 1,
+	 * REFUSE the beacon request.
+	 * Case 2: If measurement duration received in the beacon request is
+	 * greater than the max measurement duration advertised in the RRM
+	 * capabilities(Assoc Req), and Duration Mandatory bit is set to 0,
+	 * perform measurement for the duration advertised in the
+	 * RRM capabilities
+	 * maxMeasurementDuration = 2^(nonOperatingChanMax - 4) * BeaconInterval
+	 */
+	max_dur = mac->rrm.rrmPEContext.rrmEnabledCaps.nonOperatingChanMax - 4;
+	sign = (max_dur < 0) ? 1 : 0;
+	max_dur = (1L << ABS(max_dur));
+	if (!sign)
+		max_meas_dur =
+			max_dur * pe_session->beaconParams.beaconInterval;
+	else
+		max_meas_dur =
+			pe_session->beaconParams.beaconInterval / max_dur;
+
+	return max_meas_dur;
+}
+
 /**
  * rrm_process_beacon_report_req
  *
@@ -635,8 +1188,6 @@ rrm_process_beacon_report_req(struct mac_context *mac,
 	tpSirBeaconReportReqInd psbrr;
 	uint8_t num_rpt, idx_rpt;
 	uint16_t measDuration, maxMeasduration;
-	int8_t maxDuration;
-	uint8_t sign;
 	tDot11fIEAPChannelReport *ie_ap_chan_rpt;
 	uint8_t tmp_idx, buf_left, buf_cons;
 	uint16_t ch_ctr = 0;
@@ -650,9 +1201,8 @@ rrm_process_beacon_report_req(struct mac_context *mac,
 		return eRRM_INCAPABLE;
 	}
 
-	if (pBeaconReq->measurement_request.Beacon.BeaconReporting.present &&
-	    (pBeaconReq->measurement_request.Beacon.BeaconReporting.
-	     reportingCondition != 0)) {
+	if (pBeaconReq->measurement_request.Beacon.rrm_reporting.present &&
+	    (pBeaconReq->measurement_request.Beacon.rrm_reporting.reporting_condition != 0)) {
 		/* Repeated measurement is not supported. This means number of repetitions should be zero.(Already checked) */
 		/* All test case in VoWifi(as of version 0.36)  use zero for number of repetitions. */
 		/* Beacon reporting should not be included in request if number of repetitons is zero. */
@@ -662,33 +1212,14 @@ rrm_process_beacon_report_req(struct mac_context *mac,
 		return eRRM_INCAPABLE;
 	}
 
-	/* The logic here is to check the measurement duration passed in the beacon request. Following are the cases handled.
-	   Case 1: If measurement duration received in the beacon request is greater than the max measurement duration advertised
-	   in the RRM capabilities(Assoc Req), and Duration Mandatory bit is set to 1, REFUSE the beacon request
-	   Case 2: If measurement duration received in the beacon request is greater than the max measurement duration advertised
-	   in the RRM capabilities(Assoc Req), and Duration Mandatory bit is set to 0, perform measurement for
-	   the duration advertised in the RRM capabilities
-
-	   maxMeasurementDuration = 2^(nonOperatingChanMax - 4) * BeaconInterval
-	 */
-	maxDuration =
-		mac->rrm.rrmPEContext.rrmEnabledCaps.nonOperatingChanMax - 4;
-	sign = (maxDuration < 0) ? 1 : 0;
-	maxDuration = (1L << ABS(maxDuration));
-	if (!sign)
-		maxMeasduration =
-			maxDuration * pe_session->beaconParams.beaconInterval;
-	else
-		maxMeasduration =
-			pe_session->beaconParams.beaconInterval / maxDuration;
-
+	maxMeasduration = rrm_get_max_meas_duration(mac, pe_session);
 	if( pBeaconReq->measurement_request.Beacon.meas_mode ==
 	   eSIR_PASSIVE_SCAN)
 		maxMeasduration += 10;
 
 	measDuration = pBeaconReq->measurement_request.Beacon.meas_duration;
 
-	pe_nofl_info("RX: [802.11 BCN_RPT] seq:%d SSID:" QDF_SSID_FMT " BSSID:" QDF_MAC_ADDR_FMT " Token:%d op_class:%d ch:%d meas_mode:%d meas_duration:%d max_dur: %d sign: %d max_meas_dur: %d",
+	pe_nofl_info("RX: [802.11 BCN_RPT] seq:%d SSID:" QDF_SSID_FMT " BSSID:" QDF_MAC_ADDR_FMT " Token:%d op_class:%d ch:%d meas_mode:%d meas_duration:%d max_meas_dur: %d",
 		     mac->rrm.rrmPEContext.prev_rrm_report_seq_num,
 		     QDF_SSID_REF(
 			pBeaconReq->measurement_request.Beacon.SSID.num_ssid,
@@ -699,7 +1230,7 @@ rrm_process_beacon_report_req(struct mac_context *mac,
 		     pBeaconReq->measurement_request.Beacon.regClass,
 		     pBeaconReq->measurement_request.Beacon.channel,
 		     pBeaconReq->measurement_request.Beacon.meas_mode,
-		     measDuration, maxDuration, sign, maxMeasduration);
+		     measDuration, maxMeasduration);
 
 	req_mode = (pBeaconReq->parallel << 0) | (pBeaconReq->enable << 1) |
 		   (pBeaconReq->request << 2) | (pBeaconReq->report << 3) |
@@ -1371,6 +1902,282 @@ QDF_STATUS rrm_process_beacon_req(struct mac_context *mac_ctx, tSirMacAddr peer,
 	return QDF_STATUS_SUCCESS;
 }
 
+
+/**
+ * rrm_process_channel_load_req() - process channel load request from AP
+ * @mac: global mac context
+ * @pe_session: per-vdev PE context
+ * @curr_req: current measurement req in progress
+ * @peer: Macaddress of the peer requesting the radio measurement
+ * @chan_load_req: channel load request received from AP
+ *
+ * return tRrmRetStatus
+ */
+static tRrmRetStatus
+rrm_process_channel_load_req(struct mac_context *mac,
+			     struct pe_session *pe_session,
+			     tpRRMReq curr_req, tSirMacAddr peer,
+			     tDot11fIEMeasurementRequest *chan_load_req)
+{
+	struct scheduler_msg msg = {0};
+	struct ch_load_ind *load_ind;
+	uint8_t op_class, channel, reporting_condition;
+	uint16_t randomization_intv, meas_duration, max_meas_duration;
+	bool present;
+
+	present = chan_load_req->measurement_request.channel_load.rrm_reporting.present;
+	reporting_condition = chan_load_req->measurement_request.channel_load.rrm_reporting.reporting_condition;
+	if (present && reporting_condition != 0) {
+		pe_err("Dropping req: Reporting condition is not zero");
+		return eRRM_INCAPABLE;
+	}
+
+	op_class = chan_load_req->measurement_request.channel_load.op_class;
+	channel = chan_load_req->measurement_request.channel_load.channel;
+	meas_duration =
+		chan_load_req->measurement_request.channel_load.meas_duration;
+	randomization_intv =
+	     chan_load_req->measurement_request.channel_load.randomization_intv;
+	max_meas_duration = rrm_get_max_meas_duration(mac, pe_session);
+	if (max_meas_duration < meas_duration) {
+		if (chan_load_req->durationMandatory) {
+			pe_nofl_err("RX:[802.11 CH_LOAD] Dropping the req: duration mandatory & max duration > meas duration");
+			return eRRM_REFUSED;
+		} else {
+			meas_duration = max_meas_duration;
+		}
+	}
+	pe_debug("RX:[802.11 CH_LOAD] seq:%d Token:%d op_c:%d ch:%d meas_dur:%d, rand intv: %d, max_dur:%d",
+		 mac->rrm.rrmPEContext.prev_rrm_report_seq_num,
+		 chan_load_req->measurement_token, op_class,
+		 channel, meas_duration, randomization_intv,
+		 max_meas_duration);
+	if (!meas_duration || meas_duration > RRM_SCAN_MAX_DWELL_TIME)
+		return eRRM_REFUSED;
+
+	/* Prepare the request to send to SME. */
+	load_ind = qdf_mem_malloc(sizeof(struct ch_load_ind));
+	if (!load_ind)
+		return eRRM_FAILURE;
+
+	qdf_mem_copy(load_ind->peer_addr.bytes, peer,
+		     sizeof(struct qdf_mac_addr));
+	load_ind->message_type = eWNI_SME_CHAN_LOAD_REQ_IND;
+	load_ind->length = sizeof(struct ch_load_ind);
+	load_ind->dialog_token = chan_load_req->measurement_token;
+	load_ind->msg_source = eRRM_MSG_SOURCE_11K;
+	load_ind->randomization_intv = SYS_TU_TO_MS(randomization_intv);
+	load_ind->measurement_idx = curr_req->measurement_idx;
+	load_ind->channel = channel;
+	load_ind->op_class = op_class;
+	load_ind->meas_duration = meas_duration;
+	curr_req->token = chan_load_req->measurement_token;
+	/* Send request to SME. */
+	msg.type = eWNI_SME_CHAN_LOAD_REQ_IND;
+	msg.bodyptr = load_ind;
+	MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG,
+			 pe_session->vdev_id, msg.type));
+	lim_sys_process_mmh_msg_api(mac, &msg);
+	return eRRM_SUCCESS;
+}
+
+/**
+ * rrm_process_chan_load_request_failure() - process channel load request
+ * in case of failure
+ * @mac: global mac context
+ * @pe_session: per-vdev PE context
+ * @peer: peer mac address
+ * @status:failure status of channel load request
+ * @index: request index
+ *
+ * return none
+ */
+static void
+rrm_process_chan_load_request_failure(struct mac_context *mac,
+				      struct pe_session *pe_session,
+				      tSirMacAddr peer,
+				      tRrmRetStatus status, uint8_t index)
+{
+	tpSirMacRadioMeasureReport report = NULL;
+	tpRRMReq curr_req = mac->rrm.rrmPEContext.pCurrentReq[index];
+
+	if (!curr_req) {
+		pe_debug("Current request is NULL");
+		goto cleanup;
+	}
+	report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport));
+	if (!report)
+		goto cleanup;
+	report->token = curr_req->token;
+	report->type = SIR_MAC_RRM_CHANNEL_LOAD_TYPE;
+	pe_debug("vdev:%d measurement index:%d status %d token %d",
+		 pe_session->vdev_id, index, status, report->token);
+	switch (status) {
+	case eRRM_REFUSED:
+	case eRRM_FAILURE:
+		report->refused = 1;
+		break;
+	case eRRM_INCAPABLE:
+		report->incapable = 1;
+		break;
+	default:
+		goto free;
+	}
+
+	lim_send_radio_measure_report_action_frame(mac, curr_req->dialog_token,
+						   1, true, report, peer,
+						   pe_session);
+free:
+	qdf_mem_free(report);
+cleanup:
+	rrm_cleanup(mac, index);
+}
+
+void
+rrm_process_chan_load_report_xmit(struct mac_context *mac_ctx,
+				  struct chan_load_xmit_ind *chan_load_ind)
+{
+	tSirMacRadioMeasureReport *report = NULL;
+	struct chan_load_report *channel_load_report;
+	tpRRMReq curr_req;
+	struct pe_session *session_entry;
+	uint8_t session_id, idx;
+	struct qdf_mac_addr sessionBssId;
+
+	if (!chan_load_ind) {
+		pe_err("Received chan_load_xmit_ind is NULL in PE");
+		return;
+	}
+
+	idx = chan_load_ind->measurement_idx;
+
+	if (idx >= QDF_ARRAY_SIZE(mac_ctx->rrm.rrmPEContext.pCurrentReq)) {
+		pe_err("Received measurement_idx is out of range: %u - %zu",
+		       idx,
+		       QDF_ARRAY_SIZE(mac_ctx->rrm.rrmPEContext.pCurrentReq));
+		return;
+	}
+
+	curr_req = mac_ctx->rrm.rrmPEContext.pCurrentReq[idx];
+	if (!curr_req) {
+		pe_err("no request pending in PE");
+		goto end;
+	}
+
+	pe_debug("Received chan load report xmit indication on idx:%d", idx);
+
+	sessionBssId = mac_ctx->rrm.rrmSmeContext[idx].sessionBssId;
+
+	session_entry = pe_find_session_by_bssid(mac_ctx, sessionBssId.bytes,
+						 &session_id);
+	if (!session_entry) {
+		pe_err("NULL session for bssId "QDF_MAC_ADDR_FMT"",
+		       QDF_MAC_ADDR_REF(sessionBssId.bytes));
+		goto end;
+	}
+
+	if (!chan_load_ind->is_report_success) {
+		rrm_process_chan_load_request_failure(mac_ctx, session_entry,
+						      sessionBssId.bytes,
+						      eRRM_REFUSED, idx);
+		return;
+	}
+
+	report = qdf_mem_malloc(sizeof(*report));
+	if (!report)
+		goto end;
+
+	/* Prepare the channel load report and send it to the peer.*/
+	report->token = chan_load_ind->dialog_token;
+	report->refused = 0;
+	report->incapable = 0;
+	report->type = SIR_MAC_RRM_CHANNEL_LOAD_TYPE;
+
+	channel_load_report = &report[0].report.channel_load_report;
+	channel_load_report->op_class = chan_load_ind->op_class;
+	channel_load_report->channel = chan_load_ind->channel;
+	channel_load_report->rrm_scan_tsf = chan_load_ind->rrm_scan_tsf;
+	channel_load_report->meas_duration = chan_load_ind->duration;
+	channel_load_report->chan_load = chan_load_ind->chan_load;
+
+	pe_err("send chan load report for bssId:"QDF_MAC_ADDR_FMT" reg_class:%d, channel:%d, measStartTime:%llu, measDuration:%d, chan_load:%d",
+	       QDF_MAC_ADDR_REF(sessionBssId.bytes),
+	       channel_load_report->op_class,
+	       channel_load_report->channel,
+	       channel_load_report->rrm_scan_tsf,
+	       channel_load_report->meas_duration,
+	       channel_load_report->chan_load);
+
+	lim_send_radio_measure_report_action_frame(mac_ctx,
+						   curr_req->dialog_token, 1,
+						   true, &report[0],
+						   sessionBssId.bytes,
+						   session_entry);
+
+end:
+	pe_debug("Measurement done idx:%d", idx);
+	rrm_cleanup(mac_ctx, idx);
+	qdf_mem_free(report);
+
+	return;
+}
+
+/**
+ * rrm_process_chan_load_req() - process channel load request
+ * @mac_ctx: Global pointer to MAC context
+ * @session_entry: session entry
+ * @report: Pointer to radio measurement report
+ * @rrm_req: Array of Measurement request IEs
+ * @peer: mac address of the peer requesting the radio measurement
+ * @num_report: No.of reports
+ * @index: Index for Measurement request
+ *
+ * Update structure sRRMReq and struct chan_load_req_ind and pass it to
+ * rrm_process_channel_load_req().
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+rrm_process_chan_load_req(struct mac_context *mac_ctx,
+			  struct pe_session *session_entry,
+			  tpSirMacRadioMeasureReport *report,
+			  tDot11fRadioMeasurementRequest *rrm_req,
+			  tSirMacAddr peer, uint8_t *num_report, int index)
+{
+	tRrmRetStatus rrm_status = eRRM_SUCCESS;
+	tpRRMReq curr_req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (index  >= MAX_MEASUREMENT_REQUEST) {
+		status = rrm_reject_req(report, rrm_req, num_report, index,
+			       rrm_req->MeasurementRequest[0].measurement_type);
+		return status;
+	}
+
+	curr_req = qdf_mem_malloc(sizeof(*curr_req));
+	if (!curr_req) {
+		mac_ctx->rrm.rrmPEContext.pCurrentReq[index] = NULL;
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	curr_req->dialog_token = rrm_req->DialogToken.token;
+	curr_req->token =
+		rrm_req->MeasurementRequest[index].measurement_token;
+	curr_req->measurement_idx = index;
+	mac_ctx->rrm.rrmPEContext.pCurrentReq[index] = curr_req;
+	mac_ctx->rrm.rrmPEContext.num_active_request++;
+	pe_debug("Processing channel load req index: %d num_active_req:%d",
+		 index, mac_ctx->rrm.rrmPEContext.num_active_request);
+	rrm_status = rrm_process_channel_load_req(mac_ctx, session_entry,
+				curr_req, peer,
+				&rrm_req->MeasurementRequest[index]);
+	if (eRRM_SUCCESS != rrm_status)
+		rrm_process_chan_load_request_failure(mac_ctx, session_entry,
+						      peer, rrm_status, index);
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * update_rrm_report() - Set incapable bit
  * @mac_ctx: Global pointer to MAC context
@@ -1532,6 +2339,16 @@ rrm_process_radio_measurement_request(struct mac_context *mac_ctx,
 
 	for (i = 0; i < rrm_req->num_MeasurementRequest; i++) {
 		switch (rrm_req->MeasurementRequest[i].measurement_type) {
+		case SIR_MAC_RRM_CHANNEL_LOAD_TYPE:
+			/* Process channel load request */
+			status = rrm_process_chan_load_req(mac_ctx,
+							   session_entry,
+							   &report,
+							   rrm_req, peer,
+							   &num_report, i);
+			if (QDF_IS_STATUS_ERROR(status))
+				return status;
+			break;
 		case SIR_MAC_RRM_BEACON_TYPE:
 			/* Process beacon request. */
 			status = rrm_process_beacon_req(mac_ctx, peer,
@@ -1541,6 +2358,12 @@ rrm_process_radio_measurement_request(struct mac_context *mac_ctx,
 			if (QDF_IS_STATUS_ERROR(status))
 				return status;
 			break;
+		case SIR_MAC_RRM_STA_STATISTICS_TYPE:
+		     status = rrm_process_sta_stats_req(mac_ctx, peer,
+							session_entry, &report,
+							rrm_req, &num_report,
+							i);
+			break;
 		case SIR_MAC_RRM_LCI_TYPE:
 		case SIR_MAC_RRM_LOCATION_CIVIC_TYPE:
 		case SIR_MAC_RRM_FINE_TIME_MEAS_TYPE:
@@ -1650,19 +2473,30 @@ void rrm_cleanup(struct mac_context *mac, uint8_t idx)
 {
 	tpRRMReq cur_rrm_req = NULL;
 
-	mac->rrm.rrmPEContext.num_active_request--;
-	pe_debug("Beacon report cleanup idx:%d, num_active_request:%d",
-		 idx, mac->rrm.rrmPEContext.num_active_request);
+	if (mac->rrm.rrmPEContext.num_active_request)
+		mac->rrm.rrmPEContext.num_active_request--;
+
 	cur_rrm_req = mac->rrm.rrmPEContext.pCurrentReq[idx];
 	if (!cur_rrm_req)
 		return;
+	if (cur_rrm_req->request.Beacon.reqIes.num) {
+		qdf_mem_free(cur_rrm_req->request.Beacon.reqIes.pElementIds);
+		cur_rrm_req->request.Beacon.reqIes.pElementIds = NULL;
+		cur_rrm_req->request.Beacon.reqIes.num = 0;
+	}
 
-	qdf_mem_free(cur_rrm_req->request.Beacon.reqIes.pElementIds);
-	cur_rrm_req->request.Beacon.reqIes.pElementIds = NULL;
-	cur_rrm_req->request.Beacon.reqIes.num = 0;
-
+	if (cur_rrm_req->type == SIR_MAC_RRM_STA_STATISTICS_TYPE) {
+		pe_debug("deactivate rrm sta stats timer");
+		lim_deactivate_and_change_timer(mac,
+						eLIM_RRM_STA_STATS_RSP_TIMER);
+		qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats,
+			     sizeof(mac->rrm.rrmPEContext.rrm_sta_stats));
+	}
 	qdf_mem_free(cur_rrm_req);
 	mac->rrm.rrmPEContext.pCurrentReq[idx] = NULL;
+
+	pe_debug("cleanup rrm req idx:%d, num_active_request:%d",
+		 idx, mac->rrm.rrmPEContext.num_active_request);
 }
 
 /**

Разлика између датотеке није приказан због своје велике величине
+ 250 - 217
core/mac/src/sys/legacy/src/utils/src/dot11f.c


+ 3 - 0
core/mac/src/sys/legacy/src/utils/src/mac_trace.c

@@ -215,6 +215,8 @@ uint8_t *mac_trace_get_sme_msg_string(uint16_t sme_msg)
 		CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_REPORT_IND);
 		CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_REQ_IND);
 		CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_RESP_XMIT_IND);
+		CASE_RETURN_STRING(eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND);
+		CASE_RETURN_STRING(eWNI_SME_CHAN_LOAD_REQ_IND);
 		CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_REQ);
 		CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_RSP);
 #if defined FEATURE_WLAN_ESE
@@ -586,6 +588,7 @@ uint8_t *mac_trace_get_lim_msg_string(uint16_t lim_msg)
 		CASE_RETURN_STRING(SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT);
 		CASE_RETURN_STRING(SIR_LIM_AUTH_RETRY_TIMEOUT);
 		CASE_RETURN_STRING(SIR_LIM_AUTH_SAE_TIMEOUT);
+		CASE_RETURN_STRING(SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT);
 		CASE_RETURN_STRING(SIR_LIM_MSG_TYPES_END);
 		CASE_RETURN_STRING(LIM_MLM_SCAN_REQ);
 		CASE_RETURN_STRING(LIM_MLM_SCAN_CNF);

+ 186 - 3
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -5289,9 +5289,12 @@ sir_convert_beacon_frame2_mlo_struct(uint8_t *pframe, uint32_t nframe,
 					nframe - WLAN_BEACON_IES_OFFSET,
 					&ml_ie, &ml_ie_total_len);
 		if (QDF_IS_STATUS_SUCCESS(status)) {
-			util_get_bvmlie_persta_partner_info(ml_ie,
-							    ml_ie_total_len,
-							    &partner_info);
+			status = util_get_bvmlie_persta_partner_info(
+								ml_ie,
+								ml_ie_total_len,
+								&partner_info);
+			if (QDF_IS_STATUS_ERROR(status))
+				return status;
 			bcn_struct->mlo_ie.mlo_ie.num_sta_profile =
 						partner_info.num_partner_links;
 			util_get_mlie_common_info_len(ml_ie, ml_ie_total_len,
@@ -7061,6 +7064,186 @@ QDF_STATUS populate_dot11f_wfatpc(struct mac_context *mac,
 	return QDF_STATUS_SUCCESS;
 }
 
+void
+populate_dot11f_chan_load_report(struct mac_context *mac,
+				 tDot11fIEMeasurementReport *dot11f,
+				 struct chan_load_report *channel_load_report)
+{
+	dot11f->report.channel_load_report.op_class =
+					channel_load_report->op_class;
+	dot11f->report.channel_load_report.channel =
+					channel_load_report->channel;
+	qdf_mem_copy(dot11f->report.channel_load_report.meas_start_time,
+		&channel_load_report->rrm_scan_tsf,
+		sizeof(dot11f->report.channel_load_report.meas_start_time));
+	dot11f->report.channel_load_report.meas_duration =
+				channel_load_report->meas_duration;
+	dot11f->report.channel_load_report.chan_load =
+				channel_load_report->chan_load;
+
+	pe_debug("regClass %d chan %d meas_time %d meas_dur %d, chan_load %d",
+		 dot11f->report.channel_load_report.op_class,
+		 dot11f->report.channel_load_report.channel,
+		 channel_load_report->rrm_scan_tsf,
+		 dot11f->report.channel_load_report.meas_duration,
+		 dot11f->report.channel_load_report.chan_load);
+}
+
+static void
+populate_dot11f_rrm_counter_stats(tDot11fIEMeasurementReport *pdot11f,
+				  struct counter_stats *counter_stats,
+				  bool *reporting_reason_present)
+{
+	tDot11fIEreporting_reason *reporting_reason;
+
+	reporting_reason = &pdot11f->report.sta_stats.reporting_reason;
+	pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_fragment_count =
+		counter_stats->transmitted_fragment_count;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.group_transmitted_frame_count =
+		counter_stats->group_transmitted_frame_count;
+
+	if (counter_stats->failed_count) {
+		reporting_reason->failed_count = 1;
+		*reporting_reason_present = true;
+	}
+	pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.failed_count =
+			counter_stats->failed_count;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.received_fragment_count =
+		counter_stats->received_fragment_count;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.group_received_frame_count =
+		counter_stats->group_received_frame_count;
+
+	if (counter_stats->fcs_error_count) {
+		reporting_reason->fcs_error = 1;
+		*reporting_reason_present = true;
+	}
+	pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.fcs_error_count =
+			counter_stats->fcs_error_count;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_frame_count =
+			counter_stats->transmitted_frame_count;
+}
+
+static void
+populate_dot11f_rrm_mac_stats(tDot11fIEMeasurementReport *pdot11f,
+			      struct mac_stats *mac_stats,
+			      bool *reporting_reason_present)
+{
+	tDot11fIEreporting_reason *reporting_reason;
+
+	reporting_reason = &pdot11f->report.sta_stats.reporting_reason;
+	if (mac_stats->retry_count) {
+		reporting_reason->retry = 1;
+		*reporting_reason_present = true;
+	}
+	pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.retry_count =
+			mac_stats->retry_count;
+
+	if (mac_stats->multiple_retry_count) {
+		reporting_reason->multiple_retry = 1;
+		*reporting_reason_present = true;
+	}
+	pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.multiple_retry_count =
+			mac_stats->multiple_retry_count;
+
+	if (mac_stats->frame_duplicate_count) {
+		reporting_reason->frame_duplicate = 1;
+		*reporting_reason_present = true;
+	}
+	pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.frame_duplicate_count =
+			mac_stats->frame_duplicate_count;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_success_count =
+			mac_stats->rts_success_count;
+
+	if (mac_stats->rts_failure_count) {
+		reporting_reason->rts_failure = 1;
+		*reporting_reason_present = true;
+	}
+	pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_failure_count =
+			mac_stats->rts_failure_count;
+
+	if (mac_stats->ack_failure_count) {
+		reporting_reason->ack_failure = 1;
+		*reporting_reason_present = true;
+	}
+	pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.ack_failure_count =
+			mac_stats->ack_failure_count;
+}
+
+static void
+populate_dot11f_rrm_access_delay_stats(
+				tDot11fIEMeasurementReport *pdot11f,
+				struct access_delay_stats *access_delay_stats)
+{
+	pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.ap_average_access_delay =
+		access_delay_stats->ap_average_access_delay;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_besteffort =
+		access_delay_stats->average_access_delay_besteffort;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_background =
+		access_delay_stats->average_access_delay_background;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_video =
+		access_delay_stats->average_access_delay_video;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_voice =
+		access_delay_stats->average_access_delay_voice;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.station_count =
+		access_delay_stats->station_count;
+
+	pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.channel_utilization =
+		access_delay_stats->channel_utilization;
+}
+
+QDF_STATUS
+populate_dot11f_rrm_sta_stats_report(
+		struct mac_context *mac, tDot11fIEMeasurementReport *pdot11f,
+		struct statistics_report *statistics_report)
+{
+	struct counter_stats counter_stats;
+	struct mac_stats mac_stats;
+	struct access_delay_stats access_delay_stats;
+	bool reporting_reason_present = false;
+
+	counter_stats = statistics_report->group_stats.counter_stats;
+	mac_stats = statistics_report->group_stats.mac_stats;
+	access_delay_stats = statistics_report->group_stats.access_delay_stats;
+
+	pdot11f->report.sta_stats.meas_duration =
+					statistics_report->meas_duration;
+	pdot11f->report.sta_stats.group_id = statistics_report->group_id;
+	pdot11f->report.sta_stats.reporting_reason.present = 0;
+
+	switch (statistics_report->group_id) {
+	case STA_STAT_GROUP_ID_COUNTER_STATS:
+		populate_dot11f_rrm_counter_stats(pdot11f, &counter_stats,
+						  &reporting_reason_present);
+		break;
+	case STA_STAT_GROUP_ID_MAC_STATS:
+		populate_dot11f_rrm_mac_stats(pdot11f, &mac_stats,
+					      &reporting_reason_present);
+		break;
+	case STA_STAT_GROUP_ID_DELAY_STATS:
+		populate_dot11f_rrm_access_delay_stats(pdot11f,
+						       &access_delay_stats);
+		break;
+	default:
+		pe_err("group id not supported %d",
+		       statistics_report->group_id);
+		return QDF_STATUS_SUCCESS;
+	}
+	if (reporting_reason_present)
+		pdot11f->report.sta_stats.reporting_reason.present = 1;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS
 populate_dot11f_beacon_report(struct mac_context *mac,
 			      tDot11fIEMeasurementReport *pDot11f,

+ 12 - 3
core/pld/src/pld_pcie.c

@@ -99,12 +99,19 @@ static void pld_pcie_remove(struct pci_dev *pdev)
 	struct osif_psoc_sync *psoc_sync;
 
 	errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync);
+
+#ifdef ENFORCE_PLD_REMOVE
+	if (errno && errno != -EINVAL)
+		return;
+#else
 	if (errno)
 		return;
+#endif
 
 	osif_psoc_sync_unregister(&pdev->dev);
 
-	osif_psoc_sync_wait_for_ops(psoc_sync);
+	if (psoc_sync)
+		osif_psoc_sync_wait_for_ops(psoc_sync);
 
 	pld_context = pld_get_global_context();
 
@@ -116,8 +123,10 @@ static void pld_pcie_remove(struct pci_dev *pdev)
 	pld_del_dev(pld_context, &pdev->dev);
 
 out:
-	osif_psoc_sync_trans_stop(psoc_sync);
-	osif_psoc_sync_destroy(psoc_sync);
+	if (psoc_sync) {
+		osif_psoc_sync_trans_stop(psoc_sync);
+		osif_psoc_sync_destroy(psoc_sync);
+	}
 }
 
 /**

Разлика између датотеке није приказан због своје велике величине
+ 263 - 262
core/sap/src/sap_ch_select.c


+ 0 - 20
core/sap/src/sap_ch_select.h

@@ -94,24 +94,4 @@ typedef enum {
 	CHANNEL_13,
 	CHANNEL_14
 } tSapChannel;
-
-typedef struct {
-	uint32_t chan_freq;
-	uint16_t bssCount;      /* bss found in scanresult for this channel */
-	int32_t rssiAgr;        /* Max value of rssi among all BSS(es) from scanresult for this channel */
-	uint32_t weight;        /* Weightage of this channel */
-	uint32_t weight_copy;   /* copy of the original weight */
-	bool valid;             /* Is this a valid center frequency for regulatory domain */
-	bool weight_calc_done;
-} tSapSpectChInfo;              /* tDfsSpectChInfo; */
-
-/**
- * Structure holding all the information required to make a
- * decision for the best operating channel based on dfs formula
- */
-
-typedef struct {
-	tSapSpectChInfo *pSpectCh;      /* tDfsSpectChInfo *pSpectCh;  // Ptr to the channels in the entire spectrum band */
-	uint8_t numSpectChans;  /* Total num of channels in the spectrum */
-} tSapChSelSpectInfo;           /* tDfsChSelParams; */
 #endif /* if !defined __SAP_CH_SELECT_H */

+ 1 - 1
core/sap/src/sap_fsm.c

@@ -1697,7 +1697,7 @@ QDF_STATUS sap_set_session_param(mac_handle_t mac_handle,
 
 	mac_ctx->sap.sapCtxList[sapctx->sessionId].sap_context = sapctx;
 	mac_ctx->sap.sapCtxList[sapctx->sessionId].sapPersona =
-			wlan_get_opmode_vdev_id(mac_ctx->pdev, session_id);
+			wlan_get_opmode_from_vdev_id(mac_ctx->pdev, session_id);
 	sap_debug("Initializing sap_ctx = %pK with session = %d",
 		   sapctx, session_id);
 

Неке датотеке нису приказане због велике количине промена