Преглед на файлове

Merge 8157664c66de403c986b6ee0ead0da57bec04c89 on remote branch

Change-Id: I19a0ff63925ca895d39ab3d24a231c5b64dfc891
Linux Build Service Account преди 1 година
родител
ревизия
454d3cfc99
променени са 100 файла, в които са добавени 4999 реда и са изтрити 1253 реда
  1. 9 0
      Kconfig
  2. 5 0
      components/action_oui/core/src/wlan_action_oui_main.c
  3. 45 2
      components/action_oui/core/src/wlan_action_oui_parse.c
  4. 53 0
      components/action_oui/dispatcher/inc/wlan_action_oui_cfg.h
  5. 2 0
      components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h
  6. 9 0
      components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c
  7. 6 0
      components/cmn_services/interface_mgr/src/wlan_if_mgr_sap.c
  8. 100 8
      components/cmn_services/logging/inc/wlan_connectivity_logging.h
  9. 241 51
      components/cmn_services/logging/src/wlan_connectivity_logging.c
  10. 71 8
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
  11. 34 7
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ll_sap.h
  12. 122 2
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h
  13. 89 26
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c
  14. 354 8
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c
  15. 316 40
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  16. 2 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h
  17. 53 1
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_ll_sap.c
  18. 317 9
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c
  19. 129 196
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h
  20. 129 197
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_sbs_i.h
  21. 6 9
      components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h
  22. 15 13
      components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
  23. 1 1
      components/dp/core/src/wlan_dp_softap_txrx.c
  24. 25 7
      components/dp/core/src/wlan_dp_txrx.c
  25. 13 1
      components/dsc/inc/wlan_dsc_vdev.h
  26. 32 1
      components/dsc/src/wlan_dsc_vdev.c
  27. 27 12
      components/mlme/core/inc/wlan_mlme_main.h
  28. 19 0
      components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h
  29. 86 24
      components/mlme/core/src/wlan_mlme_main.c
  30. 35 0
      components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c
  31. 28 1
      components/mlme/dispatcher/inc/cfg_mlme_sta.h
  32. 74 0
      components/mlme/dispatcher/inc/wlan_mlme_api.h
  33. 8 1
      components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
  34. 4 4
      components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
  35. 138 7
      components/mlme/dispatcher/src/wlan_mlme_api.c
  36. 2 42
      components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
  37. 3 8
      components/nan/dispatcher/src/nan_ucfg_api.c
  38. 20 6
      components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c
  39. 0 1
      components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c
  40. 49 0
      components/pmo/core/inc/wlan_pmo_static_config.h
  41. 20 0
      components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h
  42. 12 0
      components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c
  43. 61 0
      components/target_if/connection_mgr/src/target_if_cm_roam_offload.c
  44. 5 0
      components/tdls/core/src/wlan_tdls_main.c
  45. 47 23
      components/tdls/core/src/wlan_tdls_mgmt.c
  46. 2 3
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c
  47. 161 16
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c
  48. 15 0
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h
  49. 3 0
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c
  50. 29 0
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h
  51. 28 4
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h
  52. 25 0
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h
  53. 14 0
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_tgt_if_tx_api.h
  54. 79 50
      components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c
  55. 29 1
      components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c
  56. 22 0
      components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h
  57. 79 1
      components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c
  58. 50 40
      components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c
  59. 156 109
      components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c
  60. 301 23
      components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c
  61. 16 27
      components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.h
  62. 103 2
      components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_api.h
  63. 44 6
      components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_public_structs.h
  64. 74 5
      components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c
  65. 3 3
      components/umac/twt/core/src/wlan_twt_cfg.c
  66. 7 0
      components/umac/twt/dispatcher/inc/wlan_twt_cfg_ext_api.h
  67. 1 0
      components/umac/twt/dispatcher/src/wlan_twt_cfg_ext_api.c
  68. 5 10
      components/wmi/src/wmi_unified_roam_tlv.c
  69. 7 2
      configs/default_defconfig
  70. 4 0
      configs/kiwi_v2_defconfig
  71. 3 0
      configs/pineapple_gki_kiwi-v2_defconfig
  72. 2 0
      configs/pineapple_gki_peach_defconfig
  73. 2 0
      configs/qca6390_defconfig
  74. 2 0
      configs/sun_gki_kiwi-v2_defconfig
  75. 2 0
      configs/sun_gki_peach_defconfig
  76. 1 0
      core/bmi/src/ol_fw.c
  77. 6 0
      core/dp/htt/htt_rx_ll.c
  78. 62 8
      core/hdd/src/wlan_hdd_cfg.c
  79. 159 10
      core/hdd/src/wlan_hdd_cfg80211.c
  80. 10 0
      core/hdd/src/wlan_hdd_cfr.c
  81. 0 5
      core/hdd/src/wlan_hdd_cm_connect.c
  82. 49 1
      core/hdd/src/wlan_hdd_connectivity_logging.c
  83. 100 97
      core/hdd/src/wlan_hdd_driver_ops.c
  84. 35 10
      core/hdd/src/wlan_hdd_hostapd.c
  85. 28 1
      core/hdd/src/wlan_hdd_ioctl.c
  86. 27 4
      core/hdd/src/wlan_hdd_main.c
  87. 27 1
      core/hdd/src/wlan_hdd_mlo.c
  88. 5 3
      core/hdd/src/wlan_hdd_station_info.c
  89. 99 17
      core/hdd/src/wlan_hdd_stats.c
  90. 1 1
      core/hdd/src/wlan_hdd_stats.h
  91. 0 1
      core/hdd/src/wlan_hdd_wmm.c
  92. 3 3
      core/mac/inc/qwlan_version.h
  93. 34 0
      core/mac/inc/sir_mac_prot_def.h
  94. 18 0
      core/mac/src/pe/include/lim_api.h
  95. 16 12
      core/mac/src/pe/include/lim_ft.h
  96. 54 1
      core/mac/src/pe/include/rrm_global.h
  97. 62 16
      core/mac/src/pe/lim/lim_api.c
  98. 108 41
      core/mac/src/pe/lim/lim_ft.c
  99. 8 3
      core/mac/src/pe/lim/lim_ft_preauth.c
  100. 3 0
      core/mac/src/pe/lim/lim_process_action_frame.c

+ 9 - 0
Kconfig

@@ -1126,6 +1126,11 @@ config WLAN_DISABLE_EXPORT_SYMBOL
 	bool "Enable WLAN_DISABLE_EXPORT_SYMBOL"
 	default n
 
+config WLAN_MULTI_CHIP_SUPPORT
+	bool "Enable WLAN_MULTI_CHIP_SUPPORT"
+	select WLAN_DISABLE_EXPORT_SYMBOL
+	default n
+
 config WLAN_DL_MODES
 	bool "Enable WLAN_DL_MODES"
 	default n
@@ -1932,4 +1937,8 @@ config BCN_RATECODE_ENABLE
 config WLAN_SYSFS_RF_TEST_MODE
 	bool "enable CONFIG_WLAN_SYSFS_RF_TEST_MODE"
 	default n
+
+config WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET
+	bool "enable WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET"
+	default n
 endif # QCA_CLD_WLAN

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

@@ -188,6 +188,11 @@ static void action_oui_load_config(struct action_oui_psoc_priv *psoc_priv)
 		      cfg_get(psoc,
 			      CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL),
 		      ACTION_OUI_MAX_STR_LEN);
+
+	qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_ENABLE_CTS2SELF],
+		      cfg_get(psoc, CFG_ACTION_OUI_ENABLE_CTS2SELF),
+		      ACTION_OUI_MAX_STR_LEN);
+
 	qdf_str_lcopy(psoc_priv->action_oui_str
 			[ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN],
 		      cfg_get(psoc,

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

@@ -966,6 +966,50 @@ action_oui_is_empty(struct action_oui_psoc_priv *psoc_priv,
 	return false;
 }
 
+static bool validate_vendor_oui_data(struct action_oui_extension *extension,
+				     struct action_oui_search_attr *attr)
+{
+	uint8_t elem_id, elem_len;
+	int32_t left;
+	uint8_t eid = WLAN_MAC_EID_VENDOR;
+	const uint8_t *ptr = NULL;
+	const uint8_t *oui = extension->oui;
+
+	if (!attr->ie_data || !attr->ie_length || !oui)
+		return false;
+
+	ptr = attr->ie_data;
+	left = attr->ie_length;
+
+	while (left >= 2) {
+		elem_id  = ptr[0];
+		elem_len = ptr[1];
+		left -= 2;
+
+		if (elem_len > left)
+			return false;
+
+		if (eid == elem_id) {
+			/*
+			 * if oui is provided and oui_size is more than left
+			 * bytes, then we cannot have match
+			 */
+			if (extension->oui_length > left)
+				return false;
+
+			if (qdf_mem_cmp(&ptr[2], extension->oui,
+					extension->oui_length) == 0 &&
+			    check_for_vendor_oui_data(extension, ptr))
+				return true;
+		}
+
+		left -= elem_len;
+		ptr += (elem_len + 2);
+	}
+
+	return false;
+}
+
 bool
 action_oui_search(struct action_oui_psoc_priv *psoc_priv,
 		  struct action_oui_search_attr *attr,
@@ -1016,10 +1060,9 @@ action_oui_search(struct action_oui_psoc_priv *psoc_priv,
 			goto next;
 
 		if (extension->data_length && !wildcard_oui &&
-		    !check_for_vendor_oui_data(extension, oui_ptr))
+		    !validate_vendor_oui_data(extension, attr))
 			goto next;
 
-
 		if ((extension->info_mask & ACTION_OUI_INFO_MAC_ADDRESS) &&
 		    !check_for_vendor_ap_mac(extension, attr))
 			goto next;

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

@@ -761,6 +761,58 @@
 	"", \
 	"Used to enable CTS2SELF with QoS null frame for specified APs")
 
+/*
+ * <ini>
+ * g_action_oui_enable_cts_2_self - Used to enable CTS2SELF for specified APs
+ *
+ * Default OUIs: (All values in Hex)
+ * OUI 1: 000C43
+ * OUI data Len: 04
+ * OUI Data : 07000000
+ * OUI data Mask: F0 - 11110000
+ * Info Mask : 21 - 0010 0001 Check for OUI and Band
+ * Capabilities: C0 - 1100 0000 Band == 2 GHz || Band == 5 GHz
+ *
+ * OUI 2 : 000C43
+ * OUI data Len : 04
+ * OUI Data : 03000000
+ * OUI data Mask: F0 - 11110000
+ * Info Mask : 21 - 0010 0001 Check for OUI and Band
+ * Capabilities: C0 - 1100 0000 Band == 2 GHz || Band == 5 GHz
+ *
+ * OUI 3 : 8CFDF0
+ * OUI data Len : 05
+ * OUI Data : 0101020100
+ * OUI data Mask: F8 - 11111000
+ * Info Mask : 21 - 0010 0001 Check for OUI and Band
+ * Capabilities: C0 - 1100 0000 Band == 2 GHz || Band == 5 GHz
+ *
+ * OUI 4 : 8CFDF0
+ * OUI data Len : 05
+ * OUI Data : 0109020300
+ * OUI data Mask: F8 - 11111000
+ * Info Mask : 21 - 0010 0001 Check for OUI and Band
+ * Capabilities: C0 - 1100 0000 Band == 2 GHz || Band == 5 GHz
+ *
+ * g_action_oui_enable_cts_2_self=000C43 04 07000000 F0 21 C0 000C43 04 03000000 F0 21 C0 8CFDF0 05 0101020100 F8 21 C0 8CFDF0 05 0109020300 F8 21 C0
+ *
+ * Refer to gEnableActionOUI for more detail about the format.
+ *
+ * Related: gEnableActionOUI
+ *
+ * Supported Feature: Action OUIs
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_ACTION_OUI_ENABLE_CTS2SELF CFG_INI_STRING( \
+	"g_action_oui_enable_cts_2_self", \
+	0, \
+	ACTION_OUI_MAX_STR_LEN, \
+	"000C43 04 07000000 F0 21 C0 000C43 04 03000000 F0 21 C0 8CFDF0 05 0101020100 F8 21 C0 8CFDF0 05 0109020300 F8 21 C0", \
+	"Used to enable CTS2SELF frame for specified APs")
+
 /*
  * <ini>
  * gActionOUISendSMPSFrameWithOMN - Used to send SMPS frame along with OMN
@@ -807,6 +859,7 @@
 	CFG(CFG_ACTION_OUI_TAKE_ALL_BAND_INFO) \
 	CFG(CFG_ACTION_OUI_11BE_ALLOW_LIST) \
 	CFG(CFG_ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE) \
+	CFG(CFG_ACTION_OUI_ENABLE_CTS2SELF) \
 	CFG(CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL) \
 	CFG(CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN) \
 	CFG(CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ) \

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

@@ -124,6 +124,7 @@
  * on 2.4 GHz
  * @ACTION_OUI_DISABLE_BFORMEE: disable SU/MU beam formee capability for
  * specified AP
+ * @ACTION_OUI_ENABLE_CTS2SELF: enable cts to self for specified AP's
  * @ACTION_OUI_MAXIMUM_ID: maximum number of action oui types
  */
 enum action_oui_id {
@@ -148,6 +149,7 @@ enum action_oui_id {
 	ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ,
 	ACTION_OUI_DISABLE_BFORMEE,
 	ACTION_OUI_DISABLE_AGGRESSIVE_EDCA,
+	ACTION_OUI_ENABLE_CTS2SELF,
 	ACTION_OUI_MAXIMUM_ID
 };
 

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

@@ -869,6 +869,15 @@ QDF_STATUS if_mgr_validate_candidate(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_INVAL;
 	}
 
+	/*
+	 * This is a temporary check and will be removed once ll_lt_sap CSA
+	 * support is added.
+	 */
+	if (policy_mgr_get_ll_lt_sap_freq(psoc) == chan_freq) {
+		ifmgr_debug("STA connection not allowed on LL_LT_SAP freq %d",
+			    chan_freq);
+		return QDF_STATUS_E_INVAL;
+	}
 	/*
 	 * Ignore the BSS if any other vdev is already connected to it.
 	 */

+ 6 - 0
components/cmn_services/interface_mgr/src/wlan_if_mgr_sap.c

@@ -135,6 +135,7 @@ if_mgr_ap_stop_bss_complete(struct wlan_objmgr_vdev *vdev,
 {
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_objmgr_pdev *pdev;
+	uint8_t mcc_scc_switch;
 
 	pdev = wlan_vdev_get_pdev(vdev);
 	if (!pdev)
@@ -160,6 +161,11 @@ if_mgr_ap_stop_bss_complete(struct wlan_objmgr_vdev *vdev,
 		if_mgr_enable_roaming(pdev, vdev, RSO_START_BSS);
 	}
 
+	policy_mgr_get_mcc_scc_switch(psoc, &mcc_scc_switch);
+	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE &&
+	    mcc_scc_switch == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL)
+		policy_mgr_check_concurrent_intf_and_restart_sap(psoc, false);
+
 	return QDF_STATUS_SUCCESS;
 }
 

+ 100 - 8
components/cmn_services/logging/inc/wlan_connectivity_logging.h

@@ -283,6 +283,46 @@ enum wlan_bcn_rpt_measurement_mode {
 	MEASURE_MODE_RESERVED = 0xFF
 };
 
+/**
+ * enum wlan_diag_connect_fail_reason - WLAN diag connect fail reason code
+ * @WLAN_DIAG_UNSPECIFIC_REASON: Unspecific reason
+ * @WLAN_DIAG_NO_CANDIDATE_FOUND: No candidate found
+ * @WLAN_DIAG_ABORT_DUE_TO_NEW_REQ_RECVD: Aborted as new command is
+ * received.
+ * @WLAN_DIAG_BSS_SELECT_IND_FAILED: Failed BSS select indication
+ * @WLAN_DIAG_PEER_CREATE_FAILED: peer create failed
+ * @WLAN_DIAG_JOIN_FAILED: Failed in joining state
+ * @WLAN_DIAG_JOIN_TIMEOUT: Did not receive beacon or probe response after
+ * unicast probe request
+ * @WLAN_DIAG_AUTH_FAILED: Auth rejected by AP
+ * @WLAN_DIAG_AUTH_TIMEOUT: No Auth resp from AP
+ * @WLAN_DIAG_ASSOC_FAILED: Assoc rejected by AP
+ * @WLAN_DIAG_ASSOC_TIMEOUT: No Assoc resp from AP
+ * @WLAN_DIAG_HW_MODE_FAILURE: failed to change HW mode
+ * @WLAN_DIAG_SER_FAILURE: Failed to serialize command
+ * @WLAN_DIAG_SER_TIMEOUT: Serialization cmd timeout
+ * @WLAN_DIAG_GENERIC_FAILURE: Generic failure apart from above
+ * @WLAN_DIAG_VALID_CANDIDATE_CHECK_FAIL: Valid Candidate Check fail
+ */
+enum wlan_diag_connect_fail_reason {
+	WLAN_DIAG_UNSPECIFIC_REASON = 0,
+	WLAN_DIAG_NO_CANDIDATE_FOUND = 1,
+	WLAN_DIAG_ABORT_DUE_TO_NEW_REQ_RECVD,
+	WLAN_DIAG_BSS_SELECT_IND_FAILED,
+	WLAN_DIAG_PEER_CREATE_FAILED,
+	WLAN_DIAG_JOIN_FAILED,
+	WLAN_DIAG_JOIN_TIMEOUT,
+	WLAN_DIAG_AUTH_FAILED,
+	WLAN_DIAG_AUTH_TIMEOUT,
+	WLAN_DIAG_ASSOC_FAILED,
+	WLAN_DIAG_ASSOC_TIMEOUT,
+	WLAN_DIAG_HW_MODE_FAILURE,
+	WLAN_DIAG_SER_FAILURE,
+	WLAN_DIAG_SER_TIMEOUT,
+	WLAN_DIAG_GENERIC_FAILURE,
+	WLAN_DIAG_VALID_CANDIDATE_CHECK_FAIL,
+};
+
 /**
  * struct wlan_connectivity_log_diag_cmn - Structure for diag event
  * @bssid: bssid
@@ -340,21 +380,24 @@ struct wlan_diag_mlo_cmn_info {
 };
 
 #define DIAG_MLO_SETUP_VERSION 1
+#define DIAG_MLO_SETUP_VERSION_V2 2
 
-#define MAX_BANDS 3
+#define MAX_NUM_LINKS_PER_EVENT 3
 /**
  * struct wlan_diag_mlo_setup - MLO setup structure
  * @diag_cmn: Common diag info
  * @version: structure version
+ * @num_links: Number of links associated for MLO setup
  * @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];
+	uint8_t version;
+	uint8_t num_links;
+	uint16_t reserved;
+	struct wlan_diag_mlo_cmn_info mlo_cmn_info[MAX_NUM_LINKS_PER_EVENT];
 } qdf_packed;
 
 #define DIAG_MLO_RECONFIG_VERSION 1
@@ -374,19 +417,22 @@ struct wlan_diag_mlo_reconfig {
 } qdf_packed;
 
 #define DIAG_MLO_T2LM_STATUS_VERSION 1
+#define DIAG_MLO_T2LM_STATUS_VERSION_V2 2
 
 /**
  * struct wlan_diag_mlo_t2lm_status - MLO T2LM status diag event structure
  * @diag_cmn: Common diag info
  * @version: structure version
+ * @num_links: Number of links associated for T2LM status
  * @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];
+	uint8_t version;
+	uint8_t num_links;
+	uint16_t reserved;
+	struct wlan_diag_mlo_cmn_info mlo_cmn_info[MAX_NUM_LINKS_PER_EVENT];
 } qdf_packed;
 
 #define DIAG_MLO_T2LM_REQ_RESP_VERSION 1
@@ -593,6 +639,7 @@ struct wlan_diag_roam_scan_done {
  * @diag_cmn: Common diag info
  * @version: Structure Version
  * @is_roam_successful: True if roamed successfully or false if roaming failed
+ * @is_mlo: Indicates whether the current connection is a MLO connection
  * @reserved: Reserved
  * @roam_fail_reason: Roam failure reason code defined in enum
  * wlan_roam_failure_reason_code
@@ -601,7 +648,8 @@ struct wlan_diag_roam_result {
 	struct wlan_connectivity_log_diag_cmn diag_cmn;
 	uint8_t version;
 	uint8_t is_roam_successful:1;
-	uint8_t reserved:7;
+	uint8_t is_mlo:1;
+	uint8_t reserved:6;
 	uint16_t roam_fail_reason;
 } qdf_packed;
 
@@ -1121,6 +1169,22 @@ bool wlan_is_log_record_present_for_bssid(struct wlan_objmgr_psoc *psoc,
 					  struct qdf_mac_addr *bssid,
 					  uint8_t vdev_id);
 
+/**
+ * wlan_is_sae_auth_log_present_for_bssid() - Is cached SAE auth log record
+ * present for the given bssid. This API checks on all the link vdev if the
+ * given vdev_id is an MLO vdev and updates the vdev_id to caller in which
+ * the auth frame was cached.
+ * @psoc: Global psoc pointer
+ * @bssid: BSSID
+ * @vdev_id: vdev id
+ *
+ * Return: True if an entry is found
+ */
+bool
+wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc,
+				       struct qdf_mac_addr *bssid,
+				       uint8_t *vdev_id);
+
 /**
  * wlan_clear_sae_auth_logs_cache() - Clear the cached auth related logs
  * @psoc: Pointer to global psoc object
@@ -1147,6 +1211,14 @@ bool wlan_is_log_record_present_for_bssid(struct wlan_objmgr_psoc *psoc,
 	return false;
 }
 
+static inline bool
+wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc,
+				       struct qdf_mac_addr *bssid,
+				       uint8_t *vdev_id)
+{
+	return false;
+}
+
 static inline
 void wlan_clear_sae_auth_logs_cache(struct wlan_objmgr_psoc *psoc,
 				    uint8_t vdev_id)
@@ -1273,6 +1345,18 @@ wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev,
 				   struct wlan_diag_packet_info *data,
 				   enum wlan_main_tag tag);
 
+/**
+ * wlan_populate_roam_mld_log_param() - Populate roam MLO log parameters
+ * @vdev: Pointer to vdev object
+ * @data: Diag event packet info
+ * @tag: Main Tag
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_populate_roam_mld_log_param(struct wlan_objmgr_vdev *vdev,
+				 struct wlan_diag_packet_info *data,
+				 enum wlan_main_tag tag);
 #else
 static inline void
 wlan_connectivity_mlo_reconfig_event(struct wlan_objmgr_vdev *vdev)
@@ -1305,6 +1389,14 @@ wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline QDF_STATUS
+wlan_populate_roam_mld_log_param(struct wlan_objmgr_vdev *vdev,
+				 struct wlan_diag_packet_info *data,
+				 enum wlan_main_tag tag)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 /**

+ 241 - 51
components/cmn_services/logging/src/wlan_connectivity_logging.c

@@ -27,6 +27,7 @@
 #include "wlan_mlme_api.h"
 #include "cdp_txrx_ctrl.h"
 #include "wlan_mlo_mgr_peer.h"
+#include "wlan_scan_api.h"
 
 #ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
 static struct wlan_connectivity_log_buf_data global_cl;
@@ -92,6 +93,51 @@ void wlan_connectivity_logging_stop(void)
 }
 #endif
 
+#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && \
+	defined(WLAN_FEATURE_11BE_MLO)
+static void
+wlan_clear_ml_vdev_sae_auth_logs(struct wlan_objmgr_psoc *psoc,
+				 struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *mlo_dev_ctx;
+	struct wlan_objmgr_vdev *link_vdev;
+	struct mlme_legacy_priv *mlme_priv;
+	uint8_t i, link_vdev_id;
+
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	if (!mlo_dev_ctx) {
+		logging_err_rl("mlo_dev ctx is NULL for vdev:%d",
+			       wlan_vdev_get_id(vdev));
+		return;
+	}
+
+	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		if (!mlo_dev_ctx->wlan_vdev_list[i])
+			continue;
+
+		link_vdev_id =
+			wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
+		link_vdev = mlo_dev_ctx->wlan_vdev_list[i];
+
+		mlme_priv = wlan_vdev_mlme_get_ext_hdl(link_vdev);
+		if (!mlme_priv) {
+			logging_err_rl("vdev:%d legacy private object is NULL",
+				       link_vdev_id);
+			return;
+		}
+
+		logging_debug("vdev:%d clear sae auth logs cache",
+			      link_vdev_id);
+		qdf_mem_zero(mlme_priv->auth_log, sizeof(mlme_priv->auth_log));
+	}
+}
+#else
+static inline void
+wlan_clear_ml_vdev_sae_auth_logs(struct wlan_objmgr_psoc *psoc,
+				 struct wlan_objmgr_vdev *vdev)
+{}
+#endif
+
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 void wlan_clear_sae_auth_logs_cache(struct wlan_objmgr_psoc *psoc,
 				    uint8_t vdev_id)
@@ -106,6 +152,12 @@ void wlan_clear_sae_auth_logs_cache(struct wlan_objmgr_psoc *psoc,
 		return;
 	}
 
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		wlan_clear_ml_vdev_sae_auth_logs(psoc, vdev);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+		return;
+	}
+
 	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
 	if (!mlme_priv) {
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
@@ -113,7 +165,9 @@ void wlan_clear_sae_auth_logs_cache(struct wlan_objmgr_psoc *psoc,
 		return;
 	}
 
+	logging_debug("vdev:%d clear sae auth logs cache", vdev_id);
 	qdf_mem_zero(mlme_priv->auth_log, sizeof(mlme_priv->auth_log));
+
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
 }
 #endif
@@ -223,6 +277,62 @@ bool wlan_is_log_record_present_for_bssid(struct wlan_objmgr_psoc *psoc,
 	return false;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+bool
+wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc,
+				       struct qdf_mac_addr *bssid,
+				       uint8_t *vdev_id)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_mlo_dev_context *mlo_dev_ctx;
+	uint8_t i, link_vdev_id;
+
+	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 false;
+	}
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+		return wlan_is_log_record_present_for_bssid(psoc, bssid,
+							    *vdev_id);
+	}
+
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+
+	if (!mlo_dev_ctx) {
+		logging_err_rl("mlo_dev ctx is NULL for vdev:%d", *vdev_id);
+		return wlan_is_log_record_present_for_bssid(psoc, bssid,
+							    *vdev_id);
+	}
+
+	for (i =  0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
+		if (!mlo_dev_ctx->wlan_vdev_list[i])
+			continue;
+
+		link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
+		if (wlan_is_log_record_present_for_bssid(psoc, bssid,
+							 link_vdev_id)) {
+			*vdev_id = link_vdev_id;
+			return true;
+		}
+	}
+
+	return false;
+}
+#else
+bool
+wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc,
+				       struct qdf_mac_addr *bssid,
+				       uint8_t *vdev_id)
+{
+	return wlan_is_log_record_present_for_bssid(psoc, bssid, *vdev_id);
+}
+#endif
+
 /**
  * wlan_add_sae_log_record_to_available_slot() - Add a new log record into the
  * cache for the queue.
@@ -247,7 +357,8 @@ wlan_add_sae_log_record_to_available_slot(struct wlan_objmgr_psoc *psoc,
 
 	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
 	if (!mlme_priv) {
-		logging_err_rl("vdev legacy private object is NULL");
+		logging_err_rl("vdev:%d legacy private object is NULL",
+			       vdev_id);
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -264,6 +375,8 @@ wlan_add_sae_log_record_to_available_slot(struct wlan_objmgr_psoc *psoc,
 				if (mlme_priv->auth_log[i][j].diag_cmn.ktime_us)
 					continue;
 
+				logging_debug("vdev:%d added at [i][j]:[%d][%d]",
+					      vdev_id, i, j);
 				mlme_priv->auth_log[i][j] = *pkt_info;
 				break;
 			}
@@ -274,6 +387,8 @@ wlan_add_sae_log_record_to_available_slot(struct wlan_objmgr_psoc *psoc,
 			 * For given record, there is no existing bssid
 			 * so add the entry at first available slot
 			 */
+			logging_debug("vdev:%d added entry at [i][j]:[%d][%d]",
+				      vdev_id, i, 0);
 			mlme_priv->auth_log[i][0] = *pkt_info;
 			break;
 		}
@@ -416,8 +531,8 @@ wlan_populate_band_bitmap(struct mlo_link_switch_context *link_ctx)
 	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
 		link_chan_info = link_ctx->links_info[i].link_chan_info;
 
-		band =  wlan_reg_freq_to_band((qdf_freq_t)
-					      link_chan_info->ch_freq);
+		band = wlan_reg_freq_to_band((qdf_freq_t)
+					     link_chan_info->ch_freq);
 
 		band_bitmap |= BIT(band);
 	}
@@ -431,7 +546,7 @@ wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev,
 				   enum wlan_main_tag tag)
 {
 	struct mlo_link_switch_context *link_ctx;
-	struct qdf_mac_addr peer_mac;
+	struct qdf_mac_addr peer_mac, peer_mld_mac;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	if (!mlo_is_mld_sta(vdev))
@@ -447,27 +562,55 @@ wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev,
 		return status;
 	}
 
-	qdf_mem_copy(data->diag_cmn.bssid,
-		     peer_mac.bytes,
-		     QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(data->diag_cmn.bssid, peer_mac.bytes, QDF_MAC_ADDR_SIZE);
 
-	qdf_mem_copy(data->mld_addr,
-		     wlan_vdev_mlme_get_mldaddr(vdev),
-		     QDF_MAC_ADDR_SIZE);
+	status = wlan_vdev_get_bss_peer_mld_mac(vdev, &peer_mld_mac);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		logging_err("vdev: %d failed to get mld mac address of peer",
+			    wlan_vdev_get_id(vdev));
+		return status;
+	}
 
-	if (tag == WLAN_ASSOC_REQ ||
-	    tag == WLAN_REASSOC_REQ) {
-		link_ctx = vdev->mlo_dev_ctx->link_ctx;
-		if (!link_ctx) {
-			logging_debug("vdev: %d link_ctx not found",
-				      wlan_vdev_get_id(vdev));
-			return QDF_STATUS_E_INVAL;
-		}
+	qdf_mem_copy(data->mld_addr, peer_mld_mac.bytes, QDF_MAC_ADDR_SIZE);
 
-		data->supported_links =
-			wlan_populate_band_bitmap(link_ctx);
+	if (tag != WLAN_ASSOC_REQ && tag != WLAN_REASSOC_REQ)
+		return status;
+
+	link_ctx = vdev->mlo_dev_ctx->link_ctx;
+	if (!link_ctx) {
+		logging_debug("vdev: %d link_ctx not found",
+			      wlan_vdev_get_id(vdev));
+		return QDF_STATUS_E_INVAL;
 	}
 
+	data->supported_links = wlan_populate_band_bitmap(link_ctx);
+
+	return status;
+}
+
+QDF_STATUS
+wlan_populate_roam_mld_log_param(struct wlan_objmgr_vdev *vdev,
+				 struct wlan_diag_packet_info *data,
+				 enum wlan_main_tag tag)
+{
+	struct wlan_objmgr_pdev *pdev;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!mlo_is_mld_sta(vdev))
+		return status;
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev)
+		return QDF_STATUS_E_INVAL;
+
+	status = wlan_scan_get_mld_addr_by_link_addr(
+			pdev, (struct qdf_mac_addr *)data->diag_cmn.bssid,
+			(struct qdf_mac_addr *)data->mld_addr);
+	if (QDF_IS_STATUS_ERROR(status))
+		logging_err_rl("vdev:%d Not able to fetch MLD addr for link addr: " QDF_MAC_ADDR_FMT,
+			       wlan_vdev_get_id(vdev),
+			       QDF_MAC_ADDR_REF(data->diag_cmn.bssid));
+
 	return status;
 }
 
@@ -498,6 +641,7 @@ wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev)
 	uint i = 0;
 	struct mlo_link_switch_context *link_ctx = NULL;
 	struct wlan_channel *chan_info;
+	uint8_t num_links = 0;
 
 	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
 				 struct wlan_diag_mlo_setup);
@@ -509,7 +653,7 @@ wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev)
 
 	wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get());
 	wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us();
-	wlan_diag_event.version = DIAG_MLO_SETUP_VERSION;
+	wlan_diag_event.version = DIAG_MLO_SETUP_VERSION_V2;
 
 	if (!vdev->mlo_dev_ctx) {
 		logging_err("vdev: %d MLO dev ctx not found",
@@ -525,29 +669,43 @@ wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev)
 	}
 
 	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
-		wlan_diag_event.mlo_cmn_info[i].link_id =
+		if (link_ctx->links_info[i].link_id == WLAN_INVALID_LINK_ID)
+			continue;
+
+		chan_info = link_ctx->links_info[i].link_chan_info;
+		if (!chan_info) {
+			logging_debug("link %d: chan_info not found",
+				      link_ctx->links_info[i].link_id);
+			continue;
+		}
+
+		wlan_diag_event.mlo_cmn_info[num_links].link_id =
 				link_ctx->links_info[i].link_id;
-		wlan_diag_event.mlo_cmn_info[i].vdev_id =
+		wlan_diag_event.mlo_cmn_info[num_links].vdev_id =
 				link_ctx->links_info[i].vdev_id;
 
-		qdf_mem_copy(wlan_diag_event.mlo_cmn_info[i].link_addr,
+		qdf_mem_copy(wlan_diag_event.mlo_cmn_info[num_links].link_addr,
 			     link_ctx->links_info[i].ap_link_addr.bytes,
 			     QDF_MAC_ADDR_SIZE);
 
-		chan_info = link_ctx->links_info[i].link_chan_info;
-
-		wlan_diag_event.mlo_cmn_info[i].band =
+		wlan_diag_event.mlo_cmn_info[num_links].band =
 			wlan_convert_freq_to_diag_band(chan_info->ch_freq);
 
-		if (wlan_diag_event.mlo_cmn_info[i].band == WLAN_INVALID_BAND)
+		if (wlan_diag_event.mlo_cmn_info[num_links].band ==
+							 WLAN_INVALID_BAND)
 			wlan_diag_event.mlo_cmn_info[i].status =
 							REJECTED_LINK_STATUS;
+
+		num_links++;
 	}
 
+	wlan_diag_event.num_links = num_links;
+
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MLO_SETUP);
 }
 
 #define IS_LINK_SET(link_bitmap, link_id) ((link_bitmap) & (BIT(link_id)))
+#define DEFAULT_TID_MAP 0xFF
 
 static void
 wlan_populate_tid_link_id_bitmap(struct wlan_t2lm_info *t2lm,
@@ -566,6 +724,12 @@ wlan_populate_tid_link_id_bitmap(struct wlan_t2lm_info *t2lm,
 	buf->mlo_cmn_info[bss_link].vdev_id = link_info->vdev_id;
 
 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
+		if (t2lm[dir].default_link_mapping) {
+			buf->mlo_cmn_info[bss_link].tid_ul = DEFAULT_TID_MAP;
+			buf->mlo_cmn_info[bss_link].tid_dl = DEFAULT_TID_MAP;
+			continue;
+		}
+
 		for (i = 0; i < T2LM_MAX_NUM_TIDS; i++) {
 			switch (t2lm[dir].direction) {
 			case WLAN_T2LM_DL_DIRECTION:
@@ -604,7 +768,7 @@ wlan_populate_tid_link_id_bitmap(struct wlan_t2lm_info *t2lm,
 void
 wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev)
 {
-	uint8_t i = 0, dir;
+	uint8_t i = 0, dir, num_links = 0;
 	QDF_STATUS status;
 	struct mlo_link_info *link_info;
 	struct wlan_t2lm_info t2lm[WLAN_T2LM_MAX_DIRECTION] = {0};
@@ -630,7 +794,7 @@ wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev)
 
 	wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us();
 	wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get());
-	wlan_diag_event.version = DIAG_MLO_T2LM_STATUS_VERSION;
+	wlan_diag_event.version = DIAG_MLO_T2LM_STATUS_VERSION_V2;
 
 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++)
 		t2lm[dir].direction = WLAN_T2LM_INVALID_DIRECTION;
@@ -641,16 +805,20 @@ wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev)
 		return;
 	}
 
-	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS && i < MAX_BANDS; i++) {
+	for (i = 0;
+	     i < WLAN_MAX_ML_BSS_LINKS && i < MAX_NUM_LINKS_PER_EVENT; i++) {
 		if (qdf_is_macaddr_zero(&link_info->ap_link_addr) &&
-		    link_info->vdev_id == WLAN_INVALID_VDEV_ID)
+		    link_info->link_id == WLAN_INVALID_LINK_ID)
 			continue;
 
 		wlan_populate_tid_link_id_bitmap(t2lm, link_info,
-						 &wlan_diag_event, i);
+						 &wlan_diag_event, num_links);
 		link_info++;
+		num_links++;
 	}
 
+	wlan_diag_event.num_links = num_links;
+
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event,
 				    EVENT_WLAN_MLO_T2LM_STATUS);
 }
@@ -693,7 +861,10 @@ wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
 		return;
 	}
 
-	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
+	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE ||
+	    (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	     (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) ||
+	      wlan_vdev_mlme_is_mlo_link_vdev(vdev))))
 		goto out;
 
 	if (!wlan_cm_is_first_candidate_connect_attempt(vdev))
@@ -702,7 +873,7 @@ wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
 	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);
+	wlan_diag_event.is_mlo = wlan_vdev_mlme_is_mlo_vdev(vdev);
 
 	if (wlan_diag_event.is_mlo) {
 		qdf_mem_copy(wlan_diag_event.diag_cmn.bssid,
@@ -758,7 +929,7 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     enum wlan_main_tag tag)
 {
 	enum QDF_OPMODE opmode;
-	bool is_auth_frame_caching_required, is_initial_connection;
+	bool cache_sae_frame_cap, is_initial_connection;
 	struct wlan_objmgr_vdev *vdev;
 	QDF_STATUS status;
 
@@ -775,11 +946,17 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 	if (opmode != QDF_STA_MODE)
 		goto out;
 
-	if (mlo_is_mld_sta(vdev) &&
-	    wlan_vdev_mlme_is_mlo_link_vdev(vdev))
-		goto out;
-
 	is_initial_connection = wlan_cm_is_vdev_connecting(vdev);
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	    (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) ||
+	     (is_initial_connection &&
+	      wlan_vdev_mlme_is_mlo_link_vdev(vdev)))) {
+		logging_debug("vdev:%d is_connection:%d | %s skip mgmt event",
+			      vdev_id, is_initial_connection,
+			      wlan_vdev_mlme_is_mlo_link_vdev(vdev) ?
+			      "link_vdev" : wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) ? "link switch in prog" : "");
+		goto out;
+	}
 
 	qdf_mem_zero(&wlan_diag_event, sizeof(struct wlan_diag_packet_info));
 
@@ -791,10 +968,13 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 	qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, &mac_hdr->i_addr3[0],
 		     QDF_MAC_ADDR_SIZE);
 
-	status = wlan_populate_mlo_mgmt_event_param(vdev, &wlan_diag_event,
-						    tag);
-	if (QDF_IS_STATUS_ERROR(status))
-		goto out;
+	if (is_initial_connection) {
+		status = wlan_populate_mlo_mgmt_event_param(vdev,
+							    &wlan_diag_event,
+							    tag);
+		if (QDF_IS_STATUS_ERROR(status))
+			goto out;
+	}
 
 	wlan_diag_event.version = DIAG_MGMT_VERSION_V2;
 	wlan_diag_event.tx_fail_reason = tx_status;
@@ -817,22 +997,28 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 
 	wlan_diag_event.is_retry_frame =
 			(mac_hdr->i_fc[1] & IEEE80211_FC1_RETRY);
-	is_auth_frame_caching_required =
+
+	/*
+	 * Cache the SAE auth frames info in vdev mlme private and return in
+	 * case of roam preauth
+	 */
+	cache_sae_frame_cap =
 		wlan_psoc_nif_fw_ext2_cap_get(psoc,
 					      WLAN_ROAM_STATS_FRAME_INFO_PER_CANDIDATE);
 	if (!is_initial_connection &&
 	    (tag == WLAN_AUTH_REQ || tag == WLAN_AUTH_RESP) &&
-	    auth_algo == WLAN_SAE_AUTH_ALGO_NUMBER &&
-	    is_auth_frame_caching_required)
+	    auth_algo == WLAN_SAE_AUTH_ALGO_NUMBER && cache_sae_frame_cap) {
 		wlan_cache_connectivity_log(psoc, vdev_id, &wlan_diag_event);
-	else
-		WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MGMT);
+		goto out;
+	}
+
+	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MGMT);
 
 	if (tag == WLAN_ASSOC_RSP || tag == WLAN_REASSOC_RSP)
 		wlan_connectivity_mlo_setup_event(vdev);
+
 out:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
-
 }
 
 void
@@ -948,7 +1134,11 @@ void wlan_connectivity_mld_link_status_event(struct wlan_objmgr_psoc *psoc,
 		wlan_convert_link_id_to_diag_band(&src->mld_addr,
 						  src->prev_link_bitmap);
 	wlan_diag_event.reason = src->reason_code;
-	wlan_diag_event.diag_cmn.fw_timestamp = src->fw_timestamp;
+	/*
+	 * FW timestamp received from FW in milliseconds and to be sent to
+	 * userspace in microseconds
+	 */
+	wlan_diag_event.diag_cmn.fw_timestamp = src->fw_timestamp * 1000;
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event,
 				    EVENT_WLAN_MLO_LINK_STATUS);

+ 71 - 8
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -1565,6 +1565,25 @@ void policy_mgr_check_scc_channel(struct wlan_objmgr_psoc *psoc,
 				  qdf_freq_t sap_ch_freq,
 				  uint8_t vdev_id, uint8_t cc_mode);
 
+/**
+ * policy_mgr_handle_go_sap_fav_channel() - Get preferred force SCC
+ * channel frequency using favorite mandatory channel list for GO+SAP
+ * concurrency
+ * @psoc: Pointer to Psoc
+ * @vdev_id: vdev id
+ * @sap_ch_freq: sap/go channel starting channel frequency
+ * @intf_ch_freq: prefer force scc frequency
+ *
+ * SAP should move to 2.4 GHz if P2P GO is on 5G/6G. SAP should move to user
+ * configured channel after P2P GO is stopped
+ *
+ * Return: QDF_STATUS_SUCCESS if a valid favorite SAP channel is found
+ */
+QDF_STATUS
+policy_mgr_handle_go_sap_fav_channel(struct wlan_objmgr_psoc *psoc,
+				     uint8_t vdev_id, qdf_freq_t sap_ch_freq,
+				     qdf_freq_t *intf_ch_freq);
+
 /**
  * policy_mgr_nan_sap_pre_enable_conc_check() - Check if NAN+SAP SCC is
  *                                              allowed in given ch
@@ -1887,7 +1906,7 @@ policy_mgr_is_vdev_ll_sap(struct wlan_objmgr_psoc *psoc,
  * @vdev_id: vdev id
  *
  * Based on vdev id ap profile set via vendor command is get and compared with
- * ht_ll_type AP type and is return true if profile set is throghput sensitive.
+ * ll_ht_type AP type and is return true if profile set is throghput sensitive.
  *
  * Return: true if it's present otherwise false
  */
@@ -4934,6 +4953,21 @@ policy_mgr_get_ml_sta_info_psoc(struct wlan_objmgr_psoc *psoc,
  */
 void policy_mgr_handle_link_removal_on_vdev(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * policy_mgr_handle_link_removal_on_standby() - Handle AP link removal for
+ * MLO STA standby links
+ * @vdev: objmgr vdev
+ * @reconfig_info: link reconfig info
+ *
+ * Handle link removal for ML STA standby links:
+ * Send force link command to target with link removal reason code
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+policy_mgr_handle_link_removal_on_standby(struct wlan_objmgr_vdev *vdev,
+					  struct ml_rv_info *reconfig_info);
+
 /**
  * policy_mgr_is_mlo_sap_concurrency_allowed() - Check for mlo sap allowed
  *                                               concurrency combination
@@ -5349,7 +5383,7 @@ QDF_STATUS policy_mgr_get_sbs_cfg(struct wlan_objmgr_psoc *psoc, bool *sbs);
 qdf_freq_t policy_mgr_get_ll_sap_freq(struct wlan_objmgr_psoc *psoc);
 
 /**
- * policy_mgr_get_lt_ll_sap_freq()- Function to get LT LL sap freq if it's
+ * policy_mgr_get_ll_lt_sap_freq()- Function to get LT LL sap freq if it's
  * present
  * @psoc: PSOC object
  *
@@ -5360,22 +5394,23 @@ qdf_freq_t policy_mgr_get_ll_sap_freq(struct wlan_objmgr_psoc *psoc);
  * Return: freq if it's LT LL SAP otherwise 0
  *
  */
-qdf_freq_t policy_mgr_get_lt_ll_sap_freq(struct wlan_objmgr_psoc *psoc);
+qdf_freq_t policy_mgr_get_ll_lt_sap_freq(struct wlan_objmgr_psoc *psoc);
 
 /**
- * policy_mgr_get_ht_ll_sap_freq()- Function to get HT LL sap freq if it's
+ * policy_mgr_get_ll_ht_sap_freq()- Function to get LL HT sap freq if it's
  * present
  * @psoc: PSOC object
  *
  * Based on vdev id ap profile set via vendor command is get and compared with
- * ht_ll_type AP type and return freq for that SAP if profile set is throghput
+ * ll_ht_type AP type and return freq for that SAP if profile set is throghput
  * sensitive.
  *
  * Return: freq if it's HT LL SAP otherwise 0
  *
  */
-qdf_freq_t policy_mgr_get_ht_ll_sap_freq(struct wlan_objmgr_psoc *psoc);
+qdf_freq_t policy_mgr_get_ll_ht_sap_freq(struct wlan_objmgr_psoc *psoc);
 
+#ifndef WLAN_FEATURE_LL_LT_SAP
 /**
  * policy_mgr_is_ll_sap_concurrency_valid() - Function to check whether
  * low latency SAP + STA/SAP/GC/GO concurrency allowed or not
@@ -5389,7 +5424,15 @@ qdf_freq_t policy_mgr_get_ht_ll_sap_freq(struct wlan_objmgr_psoc *psoc);
 bool policy_mgr_is_ll_sap_concurrency_valid(struct wlan_objmgr_psoc *psoc,
 					    qdf_freq_t freq,
 					    enum policy_mgr_con_mode mode);
-
+#else
+static inline
+bool policy_mgr_is_ll_sap_concurrency_valid(struct wlan_objmgr_psoc *psoc,
+					    qdf_freq_t freq,
+					    enum policy_mgr_con_mode mode)
+{
+	return true;
+}
+#endif
 /**
  * policy_mgr_update_indoor_concurrency() - Function to update the indoor
  * concurrency related regulatory changes
@@ -5566,6 +5609,7 @@ bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range,
 /**
  * policy_mgr_is_conn_lead_to_dbs_sbs() - New freq leads to DBS/SBS
  * @psoc: PSOC object information
+ * @vdev_id: vdev id of the caller
  * @freq: New connection frequency
  *
  * This API loops through existing connections from policy_mgr connection table
@@ -5574,7 +5618,7 @@ bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range,
  */
 bool
 policy_mgr_is_conn_lead_to_dbs_sbs(struct wlan_objmgr_psoc *psoc,
-				   uint32_t freq);
+				   uint8_t vdev_id, qdf_freq_t freq);
 
 /**
  * policy_mgr_sap_ch_width_update() - Update SAP ch_width
@@ -5649,4 +5693,23 @@ void
 policy_mgr_sap_on_non_psc_channel(struct wlan_objmgr_psoc *psoc,
 				  qdf_freq_t *intf_ch_freq,
 				  uint8_t sap_vdev_id);
+
+#ifdef WLAN_FEATURE_LL_LT_SAP
+/**
+ * policy_mgr_get_pcl_ch_list_for_ll_sap() - Get PCL channel list for LL_LT_SAP
+ * @psoc: psoc object
+ * @pcl: pcl list
+ * @vdev_id: vdev id
+ * @info: pointer to connection_info structure
+ * @connection_count: total number of existing connection present
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_pcl_ch_list_for_ll_sap(
+					struct wlan_objmgr_psoc *psoc,
+					struct policy_mgr_pcl_list *pcl,
+					uint8_t vdev_id,
+					struct connection_info *info,
+					uint8_t *connection_count);
+#endif
 #endif /* __WLAN_POLICY_MGR_API_H */

+ 34 - 7
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ll_sap.h

@@ -20,16 +20,43 @@
 
 #include "wlan_objmgr_psoc_obj.h"
 
+#ifdef WLAN_FEATURE_LL_LT_SAP
 /**
- * wlan_policy_mgr_get_ll_lt_sap_vdev() - Get ll_lt_sap vdev
+ * wlan_policy_mgr_get_ll_lt_sap_vdev_id() - Get ll_lt_sap vdev id
  * @psoc: PSOC object
  *
- * API to find ll_lt_sap vdev pointer
- *
- * This API increments the ref count of the vdev object internally, the
- * caller has to invoke the wlan_objmgr_vdev_release_ref() to decrement
- * ref count
+ * API to find ll_lt_sap vdev id
  *
  * Return: vdev id
  */
-uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev(struct wlan_objmgr_psoc *psoc);
+uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev_id(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * __policy_mgr_is_ll_lt_sap_restart_required() - Check in ll_lt_sap restart is
+ * required
+ * @psoc: PSOC object
+ * @func: Function pointer of the caller function.
+ *
+ * This API checks if ll_lt_sap restart is required or not
+ *
+ * Return: true/false
+ */
+bool __policy_mgr_is_ll_lt_sap_restart_required(struct wlan_objmgr_psoc *psoc,
+						const char *func);
+
+#define policy_mgr_is_ll_lt_sap_restart_required(psoc) \
+	__policy_mgr_is_ll_lt_sap_restart_required(psoc, __func__)
+#else
+
+static inline bool
+policy_mgr_is_ll_lt_sap_restart_required(struct wlan_objmgr_psoc *psoc)
+{
+	return false;
+}
+
+static inline
+uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev_id(struct wlan_objmgr_psoc *psoc)
+{
+	return WLAN_INVALID_VDEV_ID;
+}
+#endif

+ 122 - 2
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h

@@ -261,6 +261,12 @@ enum policy_mgr_pcl_group_id {
  * @POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH_SCC_5G_LOW: 5 GHz High SCC
  * frequency followed by 5G High band i.e 5G freq > sbs cutoff freq, add 5 GHz
  * Low SCC frequency
+ * @POLICY_MGR_PCL_ORDER_SCC_5G_LOW: SCC channel on 5G low
+ * @POLICY_MGR_PCL_ORDER_SCC_5G_HIGH: SCC channel on 5G high
+ * @POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH: SCC channels on 5G low
+ * followed by MCC channels on 5G high
+ * @POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_MCC_5G_LOW: SCC channels on 5G high
+ * followed by MCC channels on 5G low
  *
  * Order in which the PCL is requested
  */
@@ -273,6 +279,10 @@ enum policy_mgr_pcl_channel_order {
 	POLICY_MGR_PCL_ORDER_SCC_5G_LOW_5G_LOW,
 	POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH,
 	POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH_SCC_5G_LOW,
+	POLICY_MGR_PCL_ORDER_SCC_5G_LOW,
+	POLICY_MGR_PCL_ORDER_SCC_5G_HIGH,
+	POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH,
+	POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_MCC_5G_LOW,
 };
 
 /**
@@ -431,11 +441,22 @@ enum policy_mgr_mac_use {
  * 5 GHz low frequencies, add 2.4 GHz if its shared with 5 GHz low
  * @PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G: 5GHZ high SCC channel followed by
  * 5 GHz high frequencies, add 2.4 GHZ if its shared with 5GHz high
- * @PM_SBS_CH_MCC_CH: SBS channels followed by MCC channels
- * @PM_SBS_5G_MCC_24G: SBS channels, 5G MCC channels and 2.4GHz channels
  * @PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G: 5GHZ high SCC
  * channel followed by 5 GHz high frequencies and 5 GHz low SCC channel,
  * add 2.4 GHZ if its shared with 5GHz high
+ * @PM_SBS_CH_MCC_CH: SBS channels followed by MCC channels
+ * @PM_SBS_5G_MCC_24G: SBS channels, 5G MCC channels and 2.4GHz channels
+ * @PM_SCC_ON_24G: SCC channels on 2.4 Ghz
+ * @PM_SCC_ON_5G_LOW: SCC channels on 5G low frequencies
+ * @PM_SCC_ON_5G_HIGH: SCC channels on 5G high frequencies
+ * @PM_SBS_CH_MCC_CH_SCC_ON_24_24G: SBS channels followed by MCC channels
+ * followed by SCC channels on 2.4 GHz followed by 2.4 GHz channels
+ * @PM_5G_24G: 5 GHz channels, followed by 2.4 GHz channels
+ * @PM_MCC_CH_SCC_ON_24G: MCC chanenls followed by SCC channels on 2.4 Ghz
+ * @PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH: SCC channels on 5G low frequencies
+ * followed by MCC channels on 5G high frequencies
+ * @PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW: SCC channels on 5G high frequencies
+ * followed by MCC channels on 5G low frequencies
  *
  * @PM_MAX_PCL_TYPE: Max place holder
  *
@@ -484,6 +505,14 @@ enum policy_mgr_pcl_type {
 
 	PM_SBS_CH_MCC_CH,
 	PM_SBS_5G_MCC_24G,
+	PM_SCC_ON_24G,
+	PM_SCC_ON_5G_LOW,
+	PM_SCC_ON_5G_HIGH,
+	PM_SBS_CH_MCC_CH_SCC_ON_24_24G,
+	PM_5G_24G,
+	PM_MCC_CH_SCC_ON_24G,
+	PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH,
+	PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW,
 
 	PM_MAX_PCL_TYPE
 };
@@ -812,6 +841,58 @@ enum policy_mgr_one_connection_mode {
  * @PM_NAN_DISC_NDI_MCC_24_2x2: NAN & NDI connection on MCC using 2x2 on 2.4 GHz
  * @PM_NAN_DISC_NDI_DBS_1x1: NAN & NDI connection on DBS using 1x1
  * @PM_NAN_DISC_NDI_DBS_2x2: NAN & NDI connection on DBS using 2x2
+ * @PM_STA_24_LL_LT_SAP_DBS_1x1: STA & LL_LT_SAP connection in DBS using 1x1
+ * @PM_STA_24_LL_LT_SAP_DBS_2x2: STA & LL_LT_SAP connection in DBS using 2x2
+ * @PM_STA_5_LL_LT_SAP_MCC_1x1: STA & LL_LT_SAP connection in MCC on 5 GHz
+ * using 1x1
+ * @PM_STA_5_LL_LT_SAP_MCC_2x2: STA & LL_LT_SAP connection in MCC on 5 GHz
+ * using 2x2
+ * @PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: STA on 5G low & LL_LT_SAP on 5G high
+ * connection in SBS using 1x1
+ * @PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: STA on 5G low & LL_LT_SAP on 5G high
+ * connection in SBS using 2x2
+ * @PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: STA on 5G high & LL_LT_SAP on 5G low
+ * connection in SBS using 1x1
+ * @PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: STA on 5G high & LL_LT_SAP on 5G low
+ * connection in SBS using 1x1
+ * @PM_SAP_24_LL_LT_SAP_DBS_1x1: SAP & LL_LT_SAP connection in DBS using 1x1
+ * @PM_SAP_24_LL_LT_SAP_DBS_2x2: SAP & LL_LT_SAP connection in DBS using 2x2
+ * @PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: SAP on 5G low & LL_LT_SAP on 5G high
+ * connection in SBS using 1x1
+ * @PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: SAP on 5G low & LL_LT_SAP on 5G high
+ * connection in SBS using 2x2
+ * @PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: SAP on 5G high & LL_LT_SAP on 5G low
+ * connection in SBS using 1x1
+ * @PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: SAP on 5G high & LL_LT_SAP on 5G low
+ * connection in SBS using 1x1
+ * @PM_P2P_GO_24_LL_LT_SAP_DBS_1x1: P2P GO & LL_LT_SAP connection in DBS
+ * using 1x1
+ * @PM_P2P_GO_24_LL_LT_SAP_DBS_2x2: P2P GO & LL_LT_SAP connection in DBS
+ * using 2x2
+ * @PM_P2P_GO_5_LL_LT_SAP_MCC_1x1: GO & LL_LT_SAP connection in MCC using 1x1
+ * @PM_P2P_GO_5_LL_LT_SAP_MCC_2x2: GO & LL_LT_SAP connection in MCC using 2x2
+ * @PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: GO on 5G low & LL_LT_SAP on 5G
+ * high connection in SBS using 1x1
+ * @PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: GO on 5G low & LL_LT_SAP on 5G
+ * high connection in SBS using 2x2
+ * @PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: GO on 5G high & LL_LT_SAP on 5G
+ * low connection in SBS using 1x1
+ * @PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: GO on 5G high & LL_LT_SAP on 5G
+ * low connection in SBS using 2x2
+ * @PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1: CLI & LL_LT_SAP connection in DBS using 1x1
+ * @PM_P2P_CLI_24_LL_LT_SAP_DBS_2x2: CLI & LL_LT_SAP connection in DBS using 2x2
+ * @PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1: CLI & LL_LT_SAP connection in MCC on 5 GHz
+ * using 1x1
+ * @PM_P2P_CLI_5_LL_LT_SAP_MCC_2x2: CLI & LL_LT_SAP connection in MCC on 5 GHz
+ * using 2x2
+ * @PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: CLI on 5G low & LL_LT_SAP on 5G
+ * high connection in SBS using 1x1
+ * @PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: CLI on 5G low & LL_LT_SAP on 5G
+ * high connection in SBS using 2x2
+ * @PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: CLI on 5G high & LL_LT_SAP on 5G
+ * low connection in SBS using 1x1
+ * @PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: CLI on 5G high & LL_LT_SAP on 5G
+ * low connection in SBS using 2x2
  * @PM_MAX_TWO_CONNECTION_MODE: Max enumeration
  *
  * These are generic IDs that identify the various roles in the
@@ -976,6 +1057,45 @@ enum policy_mgr_two_connection_mode {
 	PM_NAN_DISC_NDI_MCC_24_2x2,
 	PM_NAN_DISC_NDI_DBS_1x1,
 	PM_NAN_DISC_NDI_DBS_2x2,
+	PM_STA_24_LL_LT_SAP_DBS_1x1,
+	PM_STA_24_LL_LT_SAP_DBS_2x2 = PM_STA_24_LL_LT_SAP_DBS_1x1,
+	PM_STA_5_LL_LT_SAP_MCC_1x1,
+	PM_STA_5_LL_LT_SAP_MCC_2x2 = PM_STA_5_LL_LT_SAP_MCC_1x1,
+	PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 =
+					PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+	PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 =
+					PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+	PM_SAP_24_LL_LT_SAP_DBS_1x1,
+	PM_SAP_24_LL_LT_SAP_DBS_2x2 = PM_SAP_24_LL_LT_SAP_DBS_1x1,
+	PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 =
+					PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+	PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 =
+					PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+	PM_P2P_GO_24_LL_LT_SAP_DBS_1x1,
+	PM_P2P_GO_24_LL_LT_SAP_DBS_2x2 = PM_P2P_GO_24_LL_LT_SAP_DBS_1x1,
+	PM_P2P_GO_5_LL_LT_SAP_MCC_1x1,
+	PM_P2P_GO_5_LL_LT_SAP_MCC_2x2 = PM_P2P_GO_5_LL_LT_SAP_MCC_1x1,
+	PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 =
+				PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+	PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 =
+				PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+	PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1,
+	PM_P2P_CLI_24_LL_LT_SAP_DBS_2x2 = PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1,
+	PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1,
+	PM_P2P_CLI_5_LL_LT_SAP_MCC_2x2 = PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1,
+	PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 =
+				PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1,
+	PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+	PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 =
+				PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1,
+
 	PM_MAX_TWO_CONNECTION_MODE
 };
 

+ 89 - 26
components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c

@@ -44,6 +44,7 @@
 #include "wlan_mlo_mgr_sta.h"
 #include "wlan_mlo_mgr_link_switch.h"
 #include "wlan_psoc_mlme_api.h"
+#include "wlan_policy_mgr_ll_sap.h"
 
 enum policy_mgr_conc_next_action (*policy_mgr_get_current_pref_hw_mode_ptr)
 	(struct wlan_objmgr_psoc *psoc);
@@ -264,7 +265,8 @@ policy_mgr_get_sap_bw(struct wlan_objmgr_psoc *psoc, enum phy_ch_width *bw)
 
 	if (policy_mgr_get_mode_specific_conn_info(psoc, &freq_list[0],
 						   &vdev_id_list[0],
-						   PM_SAP_MODE) != 1)
+						   PM_SAP_MODE) != 1 ||
+	    !WLAN_REG_IS_6GHZ_CHAN_FREQ(freq_list[0]))
 		return QDF_STATUS_E_NOSUPPORT;
 
 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id_list[0],
@@ -283,6 +285,7 @@ policy_mgr_get_sap_bw(struct wlan_objmgr_psoc *psoc, enum phy_ch_width *bw)
 /**
  * policy_mgr_get_sap_ch_width_update_action() - get SAP ch_width update action
  * @psoc: Pointer to psoc
+ * @vdev_id: Vdev id of the caller
  * @ch_freq: channel frequency of new connection
  * @next_action: next action to happen in order to update bandwidth
  * @reason: Bandwidth upgrade/downgrade reason
@@ -294,15 +297,20 @@ policy_mgr_get_sap_bw(struct wlan_objmgr_psoc *psoc, enum phy_ch_width *bw)
  */
 static void
 policy_mgr_get_sap_ch_width_update_action(struct wlan_objmgr_psoc *psoc,
-				uint32_t ch_freq,
+				uint8_t vdev_id, qdf_freq_t ch_freq,
 				enum policy_mgr_conc_next_action *next_action,
 				enum policy_mgr_conn_update_reason *reason)
 {
 	enum phy_ch_width cur_bw;
-	uint32_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1];
+	qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1];
 	uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1];
 	bool eht_capab = false;
 
+	/*
+	 * Stop any running opportunistic timer as it will be started after
+	 * decision if required.
+	 */
+	policy_mgr_stop_opportunistic_timer(psoc);
 	if (QDF_IS_STATUS_ERROR(wlan_psoc_mlme_get_11be_capab(psoc,
 							      &eht_capab)) ||
 	    !eht_capab ||
@@ -312,12 +320,13 @@ policy_mgr_get_sap_ch_width_update_action(struct wlan_objmgr_psoc *psoc,
 
 	policy_mgr_get_mode_specific_conn_info(psoc, &freq_list[0],
 					       &vdev_id_list[0], PM_SAP_MODE);
-	if (cur_bw == CH_WIDTH_320MHZ &&
-	    ch_freq && policy_mgr_is_conn_lead_to_dbs_sbs(psoc, ch_freq))
+	if (cur_bw == CH_WIDTH_320MHZ && ch_freq &&
+	    policy_mgr_is_conn_lead_to_dbs_sbs(psoc, vdev_id, ch_freq))
 		*next_action = PM_DOWNGRADE_BW;
 	else if (cur_bw == CH_WIDTH_160MHZ &&
 		 !ch_freq &&
-		 !policy_mgr_is_conn_lead_to_dbs_sbs(psoc, freq_list[0]) &&
+		 !policy_mgr_is_conn_lead_to_dbs_sbs(psoc,
+					vdev_id_list[0], freq_list[0]) &&
 		 (reason &&
 		  (*reason == POLICY_MGR_UPDATE_REASON_TIMER_START ||
 		   *reason == POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC)))
@@ -337,7 +346,9 @@ enum policy_mgr_conc_next_action policy_mgr_need_opportunistic_upgrade(
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
 
 	if (policy_mgr_is_hwmode_offload_enabled(psoc)) {
-		policy_mgr_get_sap_ch_width_update_action(psoc, 0, &upgrade,
+		policy_mgr_get_sap_ch_width_update_action(psoc,
+							  WLAN_INVALID_VDEV_ID,
+							  0, &upgrade,
 							  reason);
 		return upgrade;
 	}
@@ -531,7 +542,8 @@ QDF_STATUS policy_mgr_update_connection_info(struct wlan_objmgr_psoc *psoc,
 	else if (policy_mgr_update_indoor_concurrency(psoc, vdev_id, cur_freq,
 						SWITCH_WITHOUT_CONCURRENCY))
 		wlan_reg_recompute_current_chan_list(psoc, pm_ctx->pdev);
-	else if (wlan_reg_get_keep_6ghz_sta_cli_connection(pm_ctx->pdev))
+	else if (wlan_reg_get_keep_6ghz_sta_cli_connection(pm_ctx->pdev) &&
+		 (mode == PM_STA_MODE || mode == PM_P2P_CLIENT_MODE))
 		wlan_reg_recompute_current_chan_list(psoc, pm_ctx->pdev);
 
 	ml_nlink_conn_change_notify(
@@ -948,18 +960,20 @@ policy_mgr_get_third_conn_action_table(
 
 bool
 policy_mgr_is_conn_lead_to_dbs_sbs(struct wlan_objmgr_psoc *psoc,
-				   uint32_t freq)
+				   uint8_t vdev_id, qdf_freq_t freq)
 {
 	struct connection_info info[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
 	uint32_t connection_count, i;
 
 	connection_count = policy_mgr_get_connection_info(psoc, info);
-
-	for (i = 0; i < connection_count; i++)
+	for (i = 0; i < connection_count; i++) {
+		/* Ignore the vdev id for which freq is passed */
+		if (vdev_id == info[i].vdev_id)
+			continue;
 		if (!policy_mgr_2_freq_always_on_same_mac(psoc, freq,
 							  info[i].ch_freq))
 			return true;
-
+	}
 	return false;
 }
 
@@ -986,7 +1000,8 @@ policy_mgr_get_next_action(struct wlan_objmgr_psoc *psoc,
 
 	if (policy_mgr_is_hwmode_offload_enabled(psoc)) {
 		*next_action = PM_NOP;
-		policy_mgr_get_sap_ch_width_update_action(psoc, ch_freq,
+		policy_mgr_get_sap_ch_width_update_action(psoc, session_id,
+							  ch_freq,
 							  next_action, &reason);
 		return QDF_STATUS_SUCCESS;
 	}
@@ -1105,11 +1120,12 @@ policy_mgr_is_hw_mode_change_required(struct wlan_objmgr_psoc *psoc,
 
 static bool
 policy_mgr_is_ch_width_downgrade_required(struct wlan_objmgr_psoc *psoc,
+					  uint8_t vdev_id,
 					  struct scan_cache_entry *entry,
 					  qdf_list_t *scan_list)
 
 {
-	if (policy_mgr_is_conn_lead_to_dbs_sbs(psoc,
+	if (policy_mgr_is_conn_lead_to_dbs_sbs(psoc, vdev_id,
 					       entry->channel.chan_freq) ||
 	    wlan_cm_bss_mlo_type(psoc, entry, scan_list))
 		return true;
@@ -1130,6 +1146,11 @@ policy_mgr_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 	enum phy_ch_width cur_bw = CH_WIDTH_INVALID;
 
 	if (policy_mgr_is_hwmode_offload_enabled(psoc)) {
+		/*
+		 * Stop any running opportunistic timer as it will be started
+		 * after decision if required.
+		 */
+		policy_mgr_stop_opportunistic_timer(psoc);
 		wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab);
 		if (eht_capab &&
 		    QDF_IS_STATUS_SUCCESS(policy_mgr_get_sap_bw(psoc,
@@ -1179,7 +1200,8 @@ ch_width_update:
 
 		if (policy_mgr_is_hw_mode_change_required(psoc, ch_freq,
 							  vdev_id) ||
-		    policy_mgr_is_ch_width_downgrade_required(psoc, entry,
+		    policy_mgr_is_ch_width_downgrade_required(psoc, vdev_id,
+							      entry,
 							      scan_list)) {
 			policy_mgr_debug("Scan list has BSS of freq %d hw mode/SAP ch_width:%d update required",
 					 ch_freq, cur_bw);
@@ -1937,18 +1959,19 @@ bool policy_mgr_is_sap_restart_required_after_sta_disconnect(
 		 * due to concurrency, then move SAP back to user configured
 		 * frequency.
 		 * if SCC to MCC switch mode is
-		 * QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL, then move SAP to
-		 * user configured frequency whenever standalone SAP is
+		 * QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL, then don't move
+		 * SAP to user configured frequency whenever standalone SAP is
 		 * currently not on the user configured frequency.
-		 * else move the SAP only when SAP is on 2.4 GHz band and user
+		 * Else move the SAP only when SAP is on 2.4 GHz band and user
 		 * configured frequency is on any other bands.
+		 * And for QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL, if GO
+		 * is on 5/6 GHz, SAP is not allowed to move back to 5/6 GHz.
+		 * If GO is not present on 5/6 GHz, SAP need to moved to
+		 * user configured frequency.
 		 */
 		if (!sta_gc_present && user_config_freq &&
-		    cc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL &&
-		    !wlan_reg_is_same_band_freqs(user_config_freq,
-						 op_ch_freq_list[i])) {
-			curr_sap_freq = op_ch_freq_list[i];
-			policy_mgr_debug("Move sap to user configured freq: %d",
+		    cc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) {
+			policy_mgr_debug("Don't move sap to user configured freq: %d",
 					 user_config_freq);
 			break;
 		} else if (!sta_gc_present && user_config_freq &&
@@ -2023,7 +2046,7 @@ bool policy_mgr_is_sap_restart_required_after_sta_disconnect(
 		return true;
 
 	*intf_ch_freq = new_sap_freq;
-	policy_mgr_debug("Standalone SAP(vdev_id %d) is not allowed on DFS/Unsafe channel, Move it to channel %u",
+	policy_mgr_debug("Standalone SAP(vdev_id %d) will be moved to channel %u",
 			 sap_vdev_id, *intf_ch_freq);
 
 	return true;
@@ -2588,6 +2611,10 @@ policy_mgr_check_sap_go_force_scc(struct wlan_objmgr_psoc *psoc,
 		policy_mgr_err("Invalid Context");
 		return QDF_STATUS_E_INVAL;
 	}
+	if (pm_ctx->cfg.mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL)
+		return QDF_STATUS_SUCCESS;
+
 	if (!vdev) {
 		policy_mgr_err("vdev is null");
 		return QDF_STATUS_E_INVAL;
@@ -2814,7 +2841,7 @@ static void __policy_mgr_check_sta_ap_concurrent_ch_intf(
 				wlan_hdd_get_channel_for_sap_restart
 					(pm_ctx->psoc, vdev_id[i], &ch_freq);
 			if (status == QDF_STATUS_SUCCESS) {
-				policy_mgr_debug("SAP vdev id %d restarts due to MCC->SCC switch, old ch freq :%d new ch freq: %d",
+				policy_mgr_debug("SAP vdev id %d restarts, old ch freq :%d new ch freq: %d",
 						 vdev_id[i],
 						 op_ch_freq_list[i], ch_freq);
 				break;
@@ -2828,10 +2855,40 @@ end:
 void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data)
 {
 	struct qdf_op_sync *op_sync;
+	struct policy_mgr_psoc_priv_obj *pm_ctx = data;
+	int ret;
 
-	if (qdf_op_protect(&op_sync))
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
 		return;
+	}
+
+	ret = qdf_op_protect(&op_sync);
+	if (ret) {
+		if (ret == -EAGAIN) {
+			if (qdf_is_driver_unloading() ||
+			    qdf_is_recovering() ||
+			    qdf_is_driver_state_module_stop()) {
+				policy_mgr_debug("driver not ready");
+				return;
+			}
 
+			if (!pm_ctx->sta_ap_intf_check_work_info)
+				return;
+
+			pm_ctx->work_fail_count++;
+			policy_mgr_debug("qdf_op start fail, ret %d, work_fail_count %d",
+					 ret, pm_ctx->work_fail_count);
+			if (pm_ctx->work_fail_count > 1) {
+				pm_ctx->work_fail_count = 0;
+				return;
+			}
+			qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work,
+					       SAP_CONC_CHECK_DEFER_TIMEOUT_MS);
+		}
+		return;
+	}
+	pm_ctx->work_fail_count = 0;
 	__policy_mgr_check_sta_ap_concurrent_ch_intf(data);
 
 	qdf_op_unprotect(op_sync);
@@ -3100,6 +3157,12 @@ void policy_mgr_check_concurrent_intf_and_restart_sap(
 			"No action taken at check_concurrent_intf_and_restart_sap");
 		return;
 	}
+
+	if (policy_mgr_is_ll_lt_sap_restart_required(psoc)) {
+		restart_sap = true;
+		goto sap_restart;
+	}
+
 	/*
 	 * If STA+SAP sessions are on DFS channel and STA+SAP SCC is
 	 * enabled on DFS channel then move the SAP out of DFS channel

+ 354 - 8
components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c

@@ -2514,8 +2514,142 @@ add_sbs_chlist_to_pcl(struct wlan_objmgr_psoc *psoc,
 			}
 			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 		}
-	} else {
-		policy_mgr_debug("invalid order");
+	} else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_LOW) {
+		/* Add 5 GHz low SCC channel*/
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		cl = pm_conc_connection_list;
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) &&
+			    cl[conn_index].freq < sbs_cut_off_freq) {
+				pcl_freqs[*index] = cl[conn_index].freq;
+				pcl_weights[*index] =
+						WEIGHT_OF_GROUP1_PCL_CHANNELS;
+				(*index)++;
+				*low_5_band_scc_present = true;
+				break;
+			}
+
+			conn_index++;
+		}
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	} else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_HIGH) {
+		/* Add 5 GHz high SCC channel*/
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		cl = pm_conc_connection_list;
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) &&
+			    cl[conn_index].freq > sbs_cut_off_freq) {
+				pcl_freqs[*index] = cl[conn_index].freq;
+				pcl_weights[*index] =
+					WEIGHT_OF_GROUP1_PCL_CHANNELS;
+				(*index)++;
+				*high_5_band_scc_present = true;
+				break;
+			}
+			conn_index++;
+		}
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	} else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH) {
+		/* Add 5 GHz low SCC channel*/
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		cl = pm_conc_connection_list;
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) &&
+			    cl[conn_index].freq < sbs_cut_off_freq) {
+				pcl_freqs[*index] = cl[conn_index].freq;
+				pcl_weights[*index] =
+						WEIGHT_OF_GROUP1_PCL_CHANNELS;
+				(*index)++;
+				*low_5_band_scc_present = true;
+				break;
+			}
+
+			conn_index++;
+		}
+
+		/* Add 5 GHz high MCC channels*/
+		for (i = 0; i < chlist_len_5 && *index < pcl_sz; i++) {
+			/* Skip 5 GHz low frequencies */
+			if (chlist_5[i] < sbs_cut_off_freq)
+				continue;
+
+			conn_index = 0;
+			/* Skip SCC channels */
+			while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+				if (cl[conn_index].freq == chlist_5[i])
+					break;
+				conn_index++;
+			}
+
+			if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index))
+				continue;
+			pcl_freqs[*index] = chlist_5[i];
+			pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+			(*index)++;
+		}
+		for (i = 0; i < chlist_len_6 && *index < pcl_sz &&
+		     !skip_6gh_channel; i++) {
+			if (chlist_6[i] < sbs_cut_off_freq)
+				return;
+
+			conn_index = 0;
+			/* Skip SCC channels */
+			while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+				if (cl[conn_index].freq == chlist_6[i])
+					break;
+				conn_index++;
+			}
+
+			if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index))
+				continue;
+
+			pcl_freqs[*index] = chlist_6[i];
+			pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+			(*index)++;
+		}
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	} else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_MCC_5G_LOW) {
+		/* Add 5 GHz high SCC channel*/
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		cl = pm_conc_connection_list;
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) &&
+			    cl[conn_index].freq > sbs_cut_off_freq) {
+				pcl_freqs[*index] = cl[conn_index].freq;
+				pcl_weights[*index] =
+						WEIGHT_OF_GROUP1_PCL_CHANNELS;
+				(*index)++;
+				*high_5_band_scc_present = true;
+				break;
+			}
+
+			conn_index++;
+		}
+
+		/* Add 5 GHz low MCC channels */
+		for (i = 0; i < chlist_len_5 && *index < pcl_sz; i++) {
+			/* Skip 5 GHz high frequencies */
+			if (chlist_5[i] > sbs_cut_off_freq)
+				continue;
+
+			conn_index = 0;
+			/* Skip SCC channels */
+			while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+				if (cl[conn_index].freq == chlist_5[i])
+					break;
+				conn_index++;
+			}
+
+			if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index))
+				continue;
+			pcl_freqs[*index] = chlist_5[i];
+			pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+			(*index)++;
+		}
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	}   else {
+		policy_mgr_debug("invalid order %d", order);
 		return;
 	}
 
@@ -3717,6 +3851,122 @@ QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc,
 				  false);
 		status = QDF_STATUS_SUCCESS;
 		break;
+	case PM_SCC_ON_24G:
+		policy_mgr_get_connection_channels(psoc, mode,
+						   POLICY_MGR_PCL_ORDER_2G,
+						   true,
+						   POLICY_MGR_PCL_GROUP_ID1_ID2,
+						   pcl_channels, pcl_weights,
+						   pcl_sz, len);
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_5G_LOW:
+		add_sbs_chlist_to_pcl(psoc,  pcl_channels,
+				      pcl_weights, pcl_sz,
+				      len,
+				      skip_6ghz_channel,
+				      channel_list_5, chan_index_5,
+				      channel_list_6, chan_index_6,
+				      POLICY_MGR_PCL_ORDER_SCC_5G_LOW,
+				      &high_5_band_scc_present,
+				      &low_5_band_scc_present);
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_5G_HIGH:
+		add_sbs_chlist_to_pcl(psoc,  pcl_channels,
+				      pcl_weights, pcl_sz,
+				      len,
+				      skip_6ghz_channel,
+				      channel_list_5, chan_index_5,
+				      channel_list_6, chan_index_6,
+				      POLICY_MGR_PCL_ORDER_SCC_5G_HIGH,
+				      &high_5_band_scc_present,
+				      &low_5_band_scc_present);
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SBS_CH_MCC_CH_SCC_ON_24_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);
+		policy_mgr_get_connection_channels(psoc, mode,
+						   POLICY_MGR_PCL_ORDER_2G,
+						   true,
+						   POLICY_MGR_PCL_GROUP_ID1_ID2,
+						   pcl_channels, pcl_weights,
+						   pcl_sz, len);
+		policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz,
+					  len, WEIGHT_OF_GROUP1_PCL_CHANNELS,
+					  channel_list_24, chan_index_24);
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_5G_24G:
+		policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights,
+					 pcl_sz, len,
+					 POLICY_MGR_PCL_GROUP_ID1_ID2,
+					 channel_list_5, chan_index_5,
+					 channel_list_6, chan_index_6);
+		policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz,
+					  len, WEIGHT_OF_GROUP1_PCL_CHANNELS,
+					  channel_list_24, chan_index_24);
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_MCC_CH_SCC_ON_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_GROUP2_PCL_CHANNELS,
+				  rest_freqs, rest_num,
+				  skip_6ghz_channel);
+		policy_mgr_get_connection_channels(psoc, mode,
+						   POLICY_MGR_PCL_ORDER_2G,
+						   true,
+						   POLICY_MGR_PCL_GROUP_ID1_ID2,
+						   pcl_channels, pcl_weights,
+						   pcl_sz, len);
+		status = QDF_STATUS_SUCCESS;
+		break;
+
+	case PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH:
+		add_sbs_chlist_to_pcl(
+				psoc,  pcl_channels, pcl_weights, pcl_sz, len,
+				skip_6ghz_channel, channel_list_5, chan_index_5,
+				channel_list_6, chan_index_6,
+				POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH,
+				&high_5_band_scc_present,
+				&low_5_band_scc_present);
+		status = QDF_STATUS_SUCCESS;
+		break;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW:
+		add_sbs_chlist_to_pcl(
+				psoc,  pcl_channels, pcl_weights, pcl_sz, len,
+				skip_6ghz_channel, channel_list_5, chan_index_5,
+				channel_list_6, chan_index_6,
+				POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH,
+				&high_5_band_scc_present,
+				&low_5_band_scc_present);
+
+		status = QDF_STATUS_SUCCESS;
+		break;
 	default:
 		policy_mgr_err("unknown pcl value %d", pcl);
 		break;
@@ -4124,7 +4374,8 @@ policy_mgr_get_pref_force_scc_freq(struct wlan_objmgr_psoc *psoc,
 
 /**
  * policy_mgr_handle_sta_sap_fav_channel() - Get preferred force SCC
- * channel frequency using favorite mandatory channel list
+ * channel frequency using favorite mandatory channel list for STA+SAP
+ * concurrency
  * @psoc: Pointer to Psoc
  * @pm_ctx: pm ctx
  * @vdev_id: vdev id
@@ -4201,6 +4452,101 @@ policy_mgr_handle_sta_sap_fav_channel(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
+QDF_STATUS
+policy_mgr_handle_go_sap_fav_channel(struct wlan_objmgr_psoc *psoc,
+				     uint8_t vdev_id, qdf_freq_t sap_ch_freq,
+				     qdf_freq_t *intf_ch_freq)
+{
+	QDF_STATUS status;
+	uint8_t go_count;
+	uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	struct policy_mgr_pcl_list pcl;
+	uint32_t i;
+
+	go_count = policy_mgr_get_mode_specific_conn_info(psoc,
+							  op_ch_freq_list,
+							  vdev_id_list,
+							  PM_P2P_GO_MODE);
+	if (!go_count)
+		return QDF_STATUS_E_FAILURE;
+
+	/* According to requirement, SAP should move to 2.4 GHz if P2P GO is
+	 * on 5G/6G.
+	 */
+	if (WLAN_REG_IS_24GHZ_CH_FREQ(op_ch_freq_list[0]) ||
+	    WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq))
+		return QDF_STATUS_E_FAILURE;
+
+	qdf_mem_zero(&pcl, sizeof(pcl));
+	status = policy_mgr_get_pcl_for_existing_conn(
+			psoc, PM_SAP_MODE, pcl.pcl_list, &pcl.pcl_len,
+			pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list),
+			false, vdev_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Unable to get PCL for SAP");
+		return status;
+	}
+
+	for (i = 0; i < pcl.pcl_len; i++) {
+		if (WLAN_REG_IS_24GHZ_CH_FREQ(pcl.pcl_list[i])) {
+			*intf_ch_freq = pcl.pcl_list[i];
+			policy_mgr_debug("sap move to %d because GO on %d",
+					 *intf_ch_freq, op_ch_freq_list[0]);
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+/**
+ * policy_mgr_handle_sap_fav_channel() - Get preferred force SCC
+ * channel frequency using favorite mandatory channel list
+ * @psoc: Pointer to Psoc
+ * @pm_ctx: pm ctx
+ * @vdev_id: vdev id
+ * @intf_ch_freq: prefer force scc frequency
+ * @sap_ch_freq: sap/go channel starting channel frequency
+ * @acs_band: acs band
+ *
+ * Return: QDF_STATUS_SUCCESS if a valid favorite mandatory force scc channel
+ * is found.
+ */
+static QDF_STATUS
+policy_mgr_handle_sap_fav_channel(struct wlan_objmgr_psoc *psoc,
+				  struct policy_mgr_psoc_priv_obj *pm_ctx,
+				  uint8_t vdev_id, qdf_freq_t sap_ch_freq,
+				  qdf_freq_t *intf_ch_freq,
+				  uint32_t acs_band)
+{
+	QDF_STATUS status;
+	uint8_t sta_count, go_count;
+
+	go_count = policy_mgr_mode_specific_connection_count(psoc,
+							     PM_P2P_GO_MODE,
+							     NULL);
+	if (go_count) {
+		status = policy_mgr_handle_go_sap_fav_channel(
+					psoc, vdev_id,
+					sap_ch_freq, intf_ch_freq);
+		if (QDF_IS_STATUS_SUCCESS(status) &&
+		    *intf_ch_freq && *intf_ch_freq != sap_ch_freq)
+			return QDF_STATUS_SUCCESS;
+	}
+
+	sta_count = policy_mgr_mode_specific_connection_count(psoc,
+							      PM_STA_MODE,
+							      NULL);
+	if (sta_count && sta_count < 2)
+		return policy_mgr_handle_sta_sap_fav_channel(
+					psoc, pm_ctx, vdev_id,
+					sap_ch_freq, intf_ch_freq,
+					acs_band);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
 void policy_mgr_check_scc_channel(struct wlan_objmgr_psoc *psoc,
 				  qdf_freq_t *intf_ch_freq,
 				  qdf_freq_t sap_ch_freq,
@@ -4236,11 +4582,11 @@ void policy_mgr_check_scc_channel(struct wlan_objmgr_psoc *psoc,
 			policy_mgr_debug("acs_band: %d", acs_band);
 	}
 
-	/* Handle STA + SAP mandaory freq cases */
-	if (sta_count && sta_count < 2 &&
-	    cc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) {
-		status = policy_mgr_handle_sta_sap_fav_channel(psoc, pm_ctx,
-				vdev_id, sap_ch_freq, intf_ch_freq, acs_band);
+	/* Handle STA/P2P + SAP mandaory freq cases */
+	if (cc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) {
+		status = policy_mgr_handle_sap_fav_channel(
+				psoc, pm_ctx, vdev_id, sap_ch_freq,
+				intf_ch_freq, acs_band);
 		if (QDF_IS_STATUS_SUCCESS(status))
 			return;
 		policy_mgr_debug("no mandatory channels (%d, %d)", sap_ch_freq,

+ 316 - 40
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -47,6 +47,7 @@
 #include "wlan_p2p_ucfg_api.h"
 #include "wlan_mlo_link_force.h"
 #include "wlan_connectivity_logging.h"
+#include "wlan_policy_mgr_ll_sap.h"
 
 /* invalid channel id. */
 #define INVALID_CHANNEL_ID 0
@@ -1673,6 +1674,9 @@ qdf_freq_t policy_mgr_get_sbs_cut_off_freq(struct wlan_objmgr_psoc *psoc)
 		return 0;
 	}
 
+	if (!policy_mgr_is_hw_sbs_capable(psoc))
+		return 0;
+
 	if (pm_ctx->hw_mode.sbs_lower_band_end_freq)
 		return pm_ctx->hw_mode.sbs_lower_band_end_freq;
 	/*
@@ -4380,6 +4384,20 @@ policy_mgr_trigger_roam_on_link_removal(struct wlan_objmgr_vdev *vdev)
 		policy_mgr_err("roam invoke failed");
 }
 
+/*
+ * policy_mgr_update_dynamic_inactive_bitmap() - Update dynamic inactive links
+ * @psoc: psoc object
+ * @vdev: vdev object
+ * @req: req of set link command
+ * @resp: resp of set link command
+ *
+ * If MLO_LINK_FORCE_MODE_INACTIVE_NUM force mode with control flag -
+ * "dynamic_force_link_num" enabled was sent to firmware,
+ * host will need to select same num of links to be dyamic inactive
+ * links. And move corresponding vdevs to disabled policy mgr connection table.
+ *
+ * Return: void
+ */
 static void
 policy_mgr_update_dynamic_inactive_bitmap(
 			struct wlan_objmgr_psoc *psoc,
@@ -4387,63 +4405,121 @@ policy_mgr_update_dynamic_inactive_bitmap(
 			struct mlo_link_set_active_req *req,
 			struct mlo_link_set_active_resp *resp)
 {
-	uint32_t candidate_inactive_links;
+	uint32_t candidate_inactive_links, inactive_links;
+	uint32_t standby_links;
 	uint32_t dyn_inactive_links = 0;
 	uint8_t dyn_num = 0, num = 0, i;
 	uint8_t link_ids[MAX_MLO_LINK_ID * 2];
+	struct ml_link_force_state curr_state = {0};
+	uint8_t force_inactive_num = 0;
+	uint32_t force_inactive_num_bitmap = 0;
+	uint32_t force_inactive_bitmap;
+
+	ml_nlink_get_curr_force_state(psoc, vdev, &curr_state);
 
-	if (req->param.force_mode != MLO_LINK_FORCE_MODE_INACTIVE_NUM ||
-	    !req->param.control_flags.dynamic_force_link_num)
+	switch (req->param.force_mode) {
+	case MLO_LINK_FORCE_MODE_ACTIVE:
+	case MLO_LINK_FORCE_MODE_INACTIVE:
+	case MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE:
+	case MLO_LINK_FORCE_MODE_ACTIVE_NUM:
+	case MLO_LINK_FORCE_MODE_NO_FORCE:
+		if (!curr_state.curr_dynamic_inactive_bitmap)
+			return;
+
+		force_inactive_num = curr_state.force_inactive_num;
+		force_inactive_num_bitmap =
+			curr_state.force_inactive_num_bitmap;
+		force_inactive_bitmap = curr_state.force_inactive_bitmap;
+		break;
+	case MLO_LINK_FORCE_MODE_INACTIVE_NUM:
+		if (!req->param.control_flags.dynamic_force_link_num) {
+			if (!curr_state.curr_dynamic_inactive_bitmap)
+				return;
+			dyn_inactive_links = 0;
+			dyn_num = 0;
+			goto update;
+		}
+
+		force_inactive_num = curr_state.force_inactive_num;
+		force_inactive_num_bitmap =
+			curr_state.force_inactive_num_bitmap;
+		force_inactive_bitmap = curr_state.force_inactive_bitmap;
+		break;
+	default:
 		return;
+	}
 
 	/* force inactive num "clear" case, return 0 - no
 	 * dynamic inactive links.
 	 */
-	if (!req->param.force_cmd.link_num) {
+	if (!force_inactive_num) {
 		dyn_inactive_links = 0;
 		dyn_num = 0;
 		goto update;
 	}
-	/* 1. If force inactive overlap with force num bitmap,
-	 * select the inactive link from overlapped links firstly.
-	 * 2. If selected inactive link num <
-	 * req->param.force_cmd.link_num, then select the inactive
-	 * links from current inactive links reported from FW.
+
+	/* 1. If standby link is force inactive,
+	 * select the standby link as dynamic inactive link firstly.
 	 */
+	standby_links = ml_nlink_get_standby_link_bitmap(psoc, vdev);
 	candidate_inactive_links =
-		req->param.force_cmd.ieee_link_id_bitmap &
-		resp->inactive_linkid_bitmap;
-
+		force_inactive_num_bitmap &
+		force_inactive_bitmap &
+		standby_links;
+	inactive_links = candidate_inactive_links;
 	num = ml_nlink_convert_link_bitmap_to_ids(candidate_inactive_links,
 						  QDF_ARRAY_SIZE(link_ids),
 						  link_ids);
-	if (num < req->param.force_cmd.link_num &&
+
+	/* 2. If non standby link is force inactive,
+	 *  select the non standby link as second option.
+	 */
+	if (num < force_inactive_num &&
+	    num < QDF_ARRAY_SIZE(link_ids)) {
+		candidate_inactive_links =
+			force_inactive_num_bitmap &
+			force_inactive_bitmap &
+			~inactive_links;
+		num += ml_nlink_convert_link_bitmap_to_ids(
+				candidate_inactive_links,
+				QDF_ARRAY_SIZE(link_ids) - num,
+				&link_ids[num]);
+		inactive_links |= candidate_inactive_links;
+	}
+
+	/* 3. If there are links inactive from fw event's
+	 * curr_inactive_linkid_bitmap, select the current inactive
+	 * links as third option. note: those link may not be force
+	 * inactive.
+	 */
+	if (num < force_inactive_num &&
 	    num < QDF_ARRAY_SIZE(link_ids)) {
 		candidate_inactive_links =
-			req->param.force_cmd.ieee_link_id_bitmap &
+			force_inactive_num_bitmap &
 			resp->curr_inactive_linkid_bitmap &
-			~candidate_inactive_links;
+			~inactive_links;
 		num += ml_nlink_convert_link_bitmap_to_ids(
 				candidate_inactive_links,
 				QDF_ARRAY_SIZE(link_ids) - num,
 				&link_ids[num]);
+		inactive_links |= candidate_inactive_links;
 	}
+
 	for (i = 0; i < num; i++) {
-		if (dyn_num >= req->param.force_cmd.link_num)
+		if (dyn_num >= force_inactive_num)
 			break;
 		dyn_inactive_links |= 1 << link_ids[i];
 		dyn_num++;
 	}
 
 update:
-	policy_mgr_debug("inactive link num %d bitmap 0x%x force inactive 0x%x dyn links 0x%x num %d",
-			 req->param.force_cmd.link_num,
-			 req->param.force_cmd.ieee_link_id_bitmap,
+	policy_mgr_debug("inactive link num %d bitmap 0x%x force inactive 0x%x curr 0x%x dyn links 0x%x num %d",
+			 force_inactive_num,
+			 force_inactive_num_bitmap,
 			 resp->inactive_linkid_bitmap,
+			 resp->curr_inactive_linkid_bitmap,
 			 dyn_inactive_links, dyn_num);
-	if (dyn_num < req->param.force_cmd.link_num)
-		policy_mgr_debug("unexpected selected dynamic inactive link num %d",
-				 dyn_num);
+
 	ml_nlink_set_dynamic_inactive_links(psoc, vdev, dyn_inactive_links);
 }
 
@@ -4509,6 +4585,9 @@ policy_mgr_handle_force_active_resp(struct wlan_objmgr_psoc *psoc,
 			req->param.control_flags.overwrite_force_active_bitmap ?
 			LINK_OVERWRITE : LINK_ADD);
 
+		policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req,
+							  resp);
+
 		/* update vdev active inactive status */
 		policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req,
 							    resp);
@@ -4542,6 +4621,9 @@ policy_mgr_handle_force_inactive_resp(struct wlan_objmgr_psoc *psoc,
 			req->param.control_flags.overwrite_force_inactive_bitmap ?
 			LINK_OVERWRITE : LINK_ADD);
 
+		policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req,
+							  resp);
+
 		/* update vdev active inactive status */
 		policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req,
 							    resp);
@@ -4575,6 +4657,9 @@ policy_mgr_handle_force_active_num_resp(struct wlan_objmgr_psoc *psoc,
 			psoc, vdev, req->param.force_cmd.link_num,
 			req->param.force_cmd.ieee_link_id_bitmap);
 
+		policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req,
+							  resp);
+
 		/* update vdev active inactive status */
 		policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req,
 							    resp);
@@ -4685,6 +4770,9 @@ policy_mgr_handle_force_active_inactive_resp(
 			req->param.control_flags.overwrite_force_inactive_bitmap ?
 			LINK_OVERWRITE : LINK_ADD);
 
+		policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req,
+							  resp);
+
 		/* update vdev active inactive status */
 		policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req,
 							    resp);
@@ -4739,6 +4827,8 @@ policy_mgr_handle_no_force_resp(struct wlan_objmgr_psoc *psoc,
 			ml_nlink_clr_force_state(psoc, vdev);
 		}
 
+		policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req,
+							  resp);
 		/* update vdev active inactive status */
 		policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req,
 							    resp);
@@ -6031,16 +6121,14 @@ policy_mgr_handle_ml_sta_link_state_allowed(struct wlan_objmgr_psoc *psoc,
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
 	}
 
-	if (ml_sta_is_not_connected)
+	if (ml_sta_is_not_connected) {
 		status = QDF_STATUS_E_FAILURE;
-	else if (reason == MLO_LINK_FORCE_REASON_LINK_REMOVAL) {
-		if (!ml_sta_is_link_removal)
-			status = QDF_STATUS_E_FAILURE;
-	} else {
+	} else if (reason != MLO_LINK_FORCE_REASON_LINK_REMOVAL) {
 		if (ml_sta_is_link_removal)
 			status = QDF_STATUS_E_FAILURE;
 	}
-	policy_mgr_debug("set link reason %d status %d", reason, status);
+	policy_mgr_debug("set link reason %d status %d rm %d", reason, status,
+			 ml_sta_is_link_removal);
 
 	return status;
 }
@@ -6269,8 +6357,7 @@ 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) &&
-	    reason != MLO_LINK_FORCE_REASON_TDLS) {
+	if (ml_is_nlink_service_supported(psoc)) {
 		status =
 		policy_mgr_mlo_sta_set_link_by_linkid(psoc, vdev, reason,
 						      mode,
@@ -7028,6 +7115,27 @@ policy_mgr_is_emlsr_sta_concurrency_present(struct wlan_objmgr_psoc *psoc)
 	return false;
 }
 
+static bool
+policy_mgr_is_ml_sta_concurrency_present(struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0;
+	uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
+	qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
+	uint8_t num_enabled_ml_sta, conn_count;
+
+	conn_count = policy_mgr_get_connection_count(psoc);
+	policy_mgr_get_ml_sta_info_psoc(psoc, &num_ml_sta,
+					&num_disabled_ml_sta,
+					ml_sta_vdev_lst, ml_freq_lst,
+					&num_non_ml,
+					NULL, NULL);
+	num_enabled_ml_sta = num_ml_sta;
+	if (num_ml_sta >= num_disabled_ml_sta)
+		num_enabled_ml_sta = num_ml_sta - num_disabled_ml_sta;
+
+	return conn_count > num_enabled_ml_sta;
+}
+
 static uint8_t
 policy_mgr_get_affected_links_for_sta_sta(struct wlan_objmgr_psoc *psoc,
 					  uint8_t num_ml, qdf_freq_t *freq_list,
@@ -8140,6 +8248,77 @@ policy_mgr_pick_link_vdev_from_inactive_list(
 	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 }
 
+QDF_STATUS
+policy_mgr_handle_link_removal_on_standby(struct wlan_objmgr_vdev *vdev,
+					  struct ml_rv_info *reconfig_info)
+{
+	struct mlo_link_info *link_info;
+	uint8_t i, link_id;
+	uint32_t removal_link_bitmap = 0;
+	QDF_STATUS status;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev || !vdev->mlo_dev_ctx) {
+		policy_mgr_err("invalid vdev or mlo_dev_ctx");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		policy_mgr_err("psoc is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	for (i = 0; i < reconfig_info->num_links; i++) {
+		if (!(reconfig_info->link_info[i].is_ap_removal_timer_p &&
+		      reconfig_info->link_info[i].ap_removal_timer))
+			continue;
+
+		link_id = reconfig_info->link_info[i].link_id;
+		link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
+							   link_id);
+		if (!link_info) {
+			policy_mgr_err("link info null, id %d", link_id);
+			return QDF_STATUS_E_NULL_VALUE;
+		}
+		policy_mgr_debug("AP removal tbtt %d vdev %d link %d flag 0x%x STA MAC " QDF_MAC_ADDR_FMT " BSSID " QDF_MAC_ADDR_FMT,
+				 reconfig_info->link_info[i].ap_removal_timer,
+				 link_info->vdev_id, link_id,
+				 (uint32_t)link_info->link_status_flags,
+				 QDF_MAC_ADDR_REF(link_info->link_addr.bytes),
+				 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes));
+
+		if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
+			continue;
+
+		if (link_info->vdev_id != WLAN_INVALID_VDEV_ID)
+			continue;
+
+		if (qdf_atomic_test_and_set_bit(LS_F_AP_REMOVAL_BIT,
+						&link_info->link_status_flags))
+			continue;
+
+		removal_link_bitmap |= 1 << link_id;
+	}
+	if (!removal_link_bitmap)
+		return QDF_STATUS_SUCCESS;
+
+	status = policy_mgr_mlo_sta_set_nlink(
+			psoc, wlan_vdev_get_id(vdev),
+			MLO_LINK_FORCE_REASON_LINK_REMOVAL,
+			MLO_LINK_FORCE_MODE_INACTIVE,
+			0,
+			removal_link_bitmap,
+			0,
+			0);
+	if (status == QDF_STATUS_E_PENDING)
+		status = QDF_STATUS_SUCCESS;
+	else
+		policy_mgr_err("status %d", status);
+
+	return status;
+}
+
 void policy_mgr_handle_link_removal_on_vdev(struct wlan_objmgr_vdev *vdev)
 {
 	struct wlan_objmgr_psoc *psoc;
@@ -8350,6 +8529,8 @@ void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc,
 	uint8_t iter, link, active_link_cnt = 0, inactive_link_cnt = 0;
 	uint32_t active_link_bitmap = 0;
 	uint32_t inactive_link_bitmap = 0;
+	struct ml_link_force_state curr = {0};
+	bool update_inactive_link = false;
 
 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, session_id,
 						    WLAN_POLICY_MGR_ID);
@@ -8409,6 +8590,29 @@ void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc,
 	} else if (policy_mgr_is_emlsr_sta_concurrency_present(psoc)) {
 		policy_mgr_debug("Concurrency exists, cannot enter EMLSR mode");
 		goto done;
+	} else {
+		if (policy_mgr_is_ml_sta_concurrency_present(psoc)) {
+			policy_mgr_debug("Concurrency exists, don't enter EMLSR mode");
+				goto done;
+		}
+		ml_nlink_get_curr_force_state(psoc, vdev, &curr);
+		if (curr.force_inactive_num || curr.force_active_num) {
+			policy_mgr_debug("force num exists with act %d %d don't enter EMLSR mode",
+					 curr.force_active_num,
+					 curr.force_inactive_num);
+			goto done;
+		}
+		/* If current force inactive bitmap exists, we have to remove
+		 * the new active bitmap from the existing inactive bitmap,
+		 * e.g. a link id can't be present in active bitmap and
+		 * inactive bitmap at same time, so update inactive bitmap
+		 * as well.
+		 */
+		if (curr.force_inactive_bitmap && !inactive_link_cnt) {
+			inactive_link_bitmap = curr.force_inactive_bitmap &
+						~active_link_bitmap;
+			update_inactive_link = true;
+		}
 	}
 
 	/*
@@ -8417,7 +8621,7 @@ void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc,
 	 * else if there is only active vdev count, send single WMI for
 	 * all active vdevs with force mode MLO_LINK_FORCE_MODE_ACTIVE.
 	 */
-	if (inactive_link_cnt) {
+	if (inactive_link_cnt || update_inactive_link) {
 		reason = MLO_LINK_FORCE_REASON_CONNECT;
 		mode = MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE;
 		link_ctrl_flags = link_ctrl_f_overwrite_active_bitmap |
@@ -8823,6 +9027,7 @@ QDF_STATUS policy_mgr_update_active_mlo_num_links(struct wlan_objmgr_psoc *psoc,
 {
 	struct wlan_objmgr_vdev *vdev;
 	uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0;
+	uint8_t num_enabled_ml_sta = 0, conn_count;
 	uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
 	qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
@@ -8859,11 +9064,13 @@ QDF_STATUS policy_mgr_update_active_mlo_num_links(struct wlan_objmgr_psoc *psoc,
 		goto release_vdev_ref;
 	}
 
+	conn_count = policy_mgr_get_connection_count(psoc);
 	policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta,
 				   ml_sta_vdev_lst, ml_freq_lst, &num_non_ml,
 				   NULL, NULL);
-	policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_non_ml: %d",
-			 vdev_id, num_ml_sta, num_disabled_ml_sta, num_non_ml);
+	policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_non_ml: %d conn cout %d",
+			 vdev_id, num_ml_sta, num_disabled_ml_sta, num_non_ml,
+			 conn_count);
 
 	/*
 	 * No ML STA is present or more no.of links are active than supported
@@ -8886,7 +9093,38 @@ QDF_STATUS policy_mgr_update_active_mlo_num_links(struct wlan_objmgr_psoc *psoc,
 	 * In this case send set link command with num link 2 and mode
 	 * MLO_LINK_FORCE_MODE_ACTIVE_NUM, so that FW should restrict to only
 	 * in MLMR mode (2 link should be active).
+	 * If current enabled links are < 2, and there are concurrent
+	 * connection present, force active 2 links, which may be
+	 * conflict with concurrent rules, reject it.
+	 * If the two enabled links are MCC, don't not force active 2 links.
 	 */
+	num_enabled_ml_sta = num_ml_sta;
+	if (num_ml_sta >= num_disabled_ml_sta)
+		num_enabled_ml_sta = num_ml_sta - num_disabled_ml_sta;
+
+	if (force_active_cnt >= 2) {
+		if (num_ml_sta < 2) {
+			policy_mgr_debug("num_ml_sta %d < 2, can't force active cnt %d",
+					 num_ml_sta,
+					 force_active_cnt);
+			goto release_vdev_ref;
+		}
+		if (num_enabled_ml_sta < 2 &&
+		    conn_count > num_enabled_ml_sta) {
+			policy_mgr_debug("enabled link num %d < 2, concurrent conn present %d",
+					 num_enabled_ml_sta,
+					 conn_count);
+			goto release_vdev_ref;
+		}
+		if (policy_mgr_is_ml_sta_links_in_mcc(
+					psoc, ml_freq_lst,
+					ml_sta_vdev_lst,
+					NULL, num_ml_sta,
+					NULL)) {
+			policy_mgr_debug("enabled links are mcc, concurrency disallow");
+			goto release_vdev_ref;
+		}
+	}
 	if (force_active_cnt == 2 && num_disabled_ml_sta == 0)
 		goto set_link;
 
@@ -11539,12 +11777,20 @@ bool policy_mgr_is_restart_sap_required(struct wlan_objmgr_psoc *psoc,
 	bool sap_found = false;
 	uint8_t num_mcc_conn = 0;
 	uint8_t num_scc_conn = 0;
+	uint8_t num_5_or_6_conn = 0;
 
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {
 		policy_mgr_err("Invalid psoc");
 		return false;
 	}
+
+	if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) {
+		if (policy_mgr_is_ll_lt_sap_restart_required(psoc))
+			return true;
+		return false;
+	}
+
 	if (scc_mode == QDF_MCC_TO_SCC_SWITCH_DISABLE) {
 		policy_mgr_debug("No scc required");
 		return false;
@@ -11561,10 +11807,14 @@ bool policy_mgr_is_restart_sap_required(struct wlan_objmgr_psoc *psoc,
 					      IEEE80211_CHAN_DFS_CFREQ2)))
 				sap_on_dfs = true;
 			sap_found = true;
-		} else if (connection[i].freq == freq) {
-			num_scc_conn++;
 		} else {
-			num_mcc_conn++;
+			if (connection[i].freq == freq)
+				num_scc_conn++;
+			else
+				num_mcc_conn++;
+
+			if (!WLAN_REG_IS_24GHZ_CH_FREQ(connection[i].freq))
+				num_5_or_6_conn++;
 		}
 	}
 	if (!sap_found) {
@@ -11594,10 +11844,23 @@ bool policy_mgr_is_restart_sap_required(struct wlan_objmgr_psoc *psoc,
 		policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc);
 
 	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
+		if (!connection[i].in_use)
+			continue;
+
+		if (scc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL &&
+		    connection[i].mode == PM_P2P_GO_MODE &&
+		    connection[i].vdev_id != vdev_id &&
+		    policy_mgr_2_freq_always_on_same_mac(psoc, freq,
+							 connection[i].freq)) {
+			policy_mgr_debug("SAP:%d and GO:%d on same mac. Restart SAP ",
+					 freq, connection[i].freq);
+			restart_required = true;
+			break;
+		}
+
 		is_sta_p2p_cli =
-			connection[i].in_use &&
 			(connection[i].mode == PM_STA_MODE ||
-			connection[i].mode == PM_P2P_CLIENT_MODE);
+			 connection[i].mode == PM_P2P_CLIENT_MODE);
 		if (!is_sta_p2p_cli)
 			continue;
 
@@ -11673,6 +11936,17 @@ bool policy_mgr_is_restart_sap_required(struct wlan_objmgr_psoc *psoc,
 					 connection[i].freq, freq);
 			restart_required = true;
 		}
+
+		if (scc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL &&
+		    connection[i].freq == freq &&
+		    WLAN_REG_IS_24GHZ_CH_FREQ(freq) &&
+		    !num_5_or_6_conn &&
+		    user_config_freq &&
+		    !WLAN_REG_IS_24GHZ_CH_FREQ(user_config_freq)) {
+			policy_mgr_debug("SAP move to user configure %d from %d",
+					 user_config_freq, freq);
+			restart_required = true;
+		}
 	}
 
 	if (!restart_required &&
@@ -12089,16 +12363,17 @@ qdf_freq_t policy_mgr_get_ll_sap_freq(struct wlan_objmgr_psoc *psoc)
 	return _policy_mgr_get_ll_sap_freq(psoc, LL_AP_TYPE_ANY);
 }
 
-qdf_freq_t policy_mgr_get_ht_ll_sap_freq(struct wlan_objmgr_psoc *psoc)
+qdf_freq_t policy_mgr_get_ll_ht_sap_freq(struct wlan_objmgr_psoc *psoc)
 {
 	return _policy_mgr_get_ll_sap_freq(psoc, LL_AP_TYPE_HT);
 }
 
-qdf_freq_t policy_mgr_get_lt_ll_sap_freq(struct wlan_objmgr_psoc *psoc)
+qdf_freq_t policy_mgr_get_ll_lt_sap_freq(struct wlan_objmgr_psoc *psoc)
 {
 	return _policy_mgr_get_ll_sap_freq(psoc, LL_AP_TYPE_LT);
 }
 
+#ifndef WLAN_FEATURE_LL_LT_SAP
 bool policy_mgr_is_ll_sap_concurrency_valid(struct wlan_objmgr_psoc *psoc,
 					    qdf_freq_t freq,
 					    enum policy_mgr_con_mode mode)
@@ -12127,6 +12402,7 @@ bool policy_mgr_is_ll_sap_concurrency_valid(struct wlan_objmgr_psoc *psoc,
 
 	return true;
 }
+#endif
 
 bool
 policy_mgr_update_indoor_concurrency(struct wlan_objmgr_psoc *psoc,

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

@@ -350,6 +350,7 @@ struct policy_mgr_cfg {
  * @no_of_open_sessions: Number of active vdevs
  * @no_of_active_sessions: Number of active connections
  * @sta_ap_intf_check_work: delayed sap restart work
+ * @work_fail_count: sta_ap work schedule fail count
  * @nan_sap_conc_work: Info related to nan sap conc work
  * @num_dbs_hw_modes: Number of different HW modes supported
  * @hw_mode: List of HW modes supported
@@ -403,6 +404,7 @@ struct policy_mgr_psoc_priv_obj {
 	uint8_t no_of_open_sessions[QDF_MAX_NO_OF_MODE];
 	uint8_t no_of_active_sessions[QDF_MAX_NO_OF_MODE];
 	struct qdf_delayed_work sta_ap_intf_check_work;
+	uint8_t work_fail_count;
 	qdf_work_t nan_sap_conc_work;
 	uint32_t num_dbs_hw_modes;
 	struct dbs_hw_mode_info hw_mode;

+ 53 - 1
components/cmn_services/policy_mgr/src/wlan_policy_mgr_ll_sap.c

@@ -24,7 +24,7 @@
 #include "wlan_policy_mgr_i.h"
 #include "wlan_cmn.h"
 
-uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev(struct wlan_objmgr_psoc *psoc)
+uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev_id(struct wlan_objmgr_psoc *psoc)
 {
 	uint8_t ll_lt_sap_cnt;
 	uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS];
@@ -39,3 +39,55 @@ uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev(struct wlan_objmgr_psoc *psoc)
 
 	return vdev_id_list[0];
 }
+
+bool __policy_mgr_is_ll_lt_sap_restart_required(struct wlan_objmgr_psoc *psoc,
+						const char *func)
+{
+	qdf_freq_t ll_lt_sap_freq = 0;
+	uint8_t scc_vdev_id;
+	bool is_scc = false;
+	uint8_t conn_idx = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid pm ctx");
+		return false;
+	}
+
+	ll_lt_sap_freq = policy_mgr_get_ll_lt_sap_freq(psoc);
+
+	if (!ll_lt_sap_freq)
+		return false;
+
+	/*
+	 * Restart ll_lt_sap if any other interface is present in SCC
+	 * with LL_LT_SAP.
+	 */
+	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_LL_LT_SAP_MODE)
+			continue;
+
+		if (ll_lt_sap_freq == pm_conc_connection_list[conn_idx].freq) {
+			scc_vdev_id = pm_conc_connection_list[conn_idx].vdev_id;
+			is_scc = true;
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	if (is_scc) {
+		uint8_t ll_lt_sap_vdev_id =
+				wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc);
+
+		policymgr_nofl_debug("%s ll_lt_sap vdev %d with freq %d is in scc with vdev %d",
+				     func, ll_lt_sap_vdev_id, ll_lt_sap_freq,
+				     scc_vdev_id);
+		return true;
+	}
+
+	return false;
+}

+ 317 - 9
components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -37,6 +37,7 @@
 #ifdef WLAN_FEATURE_11BE_MLO
 #include "wlan_mlo_mgr_cmn.h"
 #endif
+#include "wlan_policy_mgr_ll_sap.h"
 #include "wlan_cm_ucfg_api.h"
 #include "wlan_cm_roam_api.h"
 #include "wlan_scan_api.h"
@@ -1339,6 +1340,10 @@ static QDF_STATUS policy_mgr_pcl_modification_for_sap(
 	bool srd_chan_enabled;
 
 	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
 
 	/* check the channel avoidance list for beaconing entities */
 	policy_mgr_update_with_safe_channel_list(psoc, pcl_channels,
@@ -1528,7 +1533,7 @@ static bool policy_mgr_is_dynamic_sbs_enabled(struct wlan_objmgr_psoc *psoc)
 
 /**
  * policy_mgr_is_sbs_mac0_freq() - Check if the given frequency is
- * sbs frequency on mac0.
+ * sbs frequency on mac0 for static sbs case.
  * @psoc: psoc pointer
  * @freq: Frequency which needs to be checked.
  *
@@ -1540,6 +1545,9 @@ static bool policy_mgr_is_sbs_mac0_freq(struct wlan_objmgr_psoc *psoc,
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
 	struct policy_mgr_freq_range *freq_range;
 
+	if (policy_mgr_is_dynamic_sbs_enabled(psoc))
+		return false;
+
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx)
 		return false;
@@ -1561,7 +1569,6 @@ 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);
@@ -1570,7 +1577,6 @@ 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,
 		PM_LL_LT_SAP_MODE);
@@ -1588,8 +1594,7 @@ static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap(
 			continue;
 
 		/* Remove mac0 frequencies for static SBS case */
-		if (!is_dynamic_sbs_enabled &&
-		    policy_mgr_is_sbs_mac0_freq(psoc, pcl_channels[i])) {
+		if (policy_mgr_is_sbs_mac0_freq(psoc, pcl_channels[i])) {
 			sbs_mac0_modified_pcl = true;
 			continue;
 		}
@@ -2633,6 +2638,206 @@ policy_mgr_get_third_connection_pcl_table_index_sap_nan(
 	return index;
 }
 
+static enum policy_mgr_two_connection_mode
+policy_mgr_get_third_connection_pcl_table_index_sta_ll_lt_sap(
+						struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_two_connection_mode index;
+	enum policy_mgr_two_connection_mode sbs_5g_1x1;
+	enum policy_mgr_two_connection_mode sbs_5g_2x2;
+	qdf_freq_t sta_freq, sbs_cut_off_freq;
+
+	/*
+	 * LL_LT_SAP can not be in SCC so there will not be any scc index.
+	 * With LL_LT_SAP, MCC is possible only on 5 GHz
+	 */
+	if (policy_mgr_are_2_freq_on_same_mac(
+					psoc,
+					pm_conc_connection_list[0].freq,
+					pm_conc_connection_list[1].freq)) {
+		if (!(WLAN_REG_IS_24GHZ_CH_FREQ(
+			   pm_conc_connection_list[0].freq)) &&
+			   !(WLAN_REG_IS_24GHZ_CH_FREQ(
+			   pm_conc_connection_list[1].freq))) {
+			if (POLICY_MGR_ONE_ONE ==
+					pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_5_LL_LT_SAP_MCC_1x1;
+			else
+				index = PM_STA_5_LL_LT_SAP_MCC_2x2;
+
+			return index;
+		}
+	}
+
+	if (pm_conc_connection_list[0].mode == PM_STA_MODE)
+		sta_freq = pm_conc_connection_list[0].freq;
+	else
+		sta_freq = pm_conc_connection_list[1].freq;
+
+	sbs_cut_off_freq =  policy_mgr_get_sbs_cut_off_freq(psoc);
+
+	if (sta_freq < sbs_cut_off_freq) {
+		sbs_5g_1x1 = PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1;
+		sbs_5g_2x2 = PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2;
+	} else {
+		sbs_5g_1x1 = PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1;
+		sbs_5g_2x2 = PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2;
+	}
+
+	index =
+	policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(
+						psoc, sbs_5g_1x1, sbs_5g_2x2,
+						PM_STA_24_LL_LT_SAP_DBS_1x1,
+						PM_STA_24_LL_LT_SAP_DBS_2x2);
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+policy_mgr_get_third_connection_pcl_table_index_sap_ll_lt_sap(
+						struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_two_connection_mode index;
+	enum policy_mgr_two_connection_mode sbs_5g_1x1;
+	enum policy_mgr_two_connection_mode sbs_5g_2x2;
+	qdf_freq_t sap_freq, sbs_cut_off_freq;
+
+	if (pm_conc_connection_list[0].mode == PM_SAP_MODE)
+		sap_freq = pm_conc_connection_list[0].freq;
+	else
+		sap_freq = pm_conc_connection_list[1].freq;
+
+	sbs_cut_off_freq =  policy_mgr_get_sbs_cut_off_freq(psoc);
+
+	if (sap_freq < sbs_cut_off_freq) {
+		sbs_5g_1x1 = PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1;
+		sbs_5g_2x2 = PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2;
+	} else {
+		sbs_5g_1x1 = PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1;
+		sbs_5g_2x2 = PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2;
+	}
+
+	/*
+	 * LL_LT_SAP can not be in SCC so there will not be any scc index.
+	 * For LL_LT_SAP + SAP, MCC is not possible, so there will be only
+	 * sbs or dbs index
+	 */
+
+	index =
+	policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(
+						psoc, sbs_5g_1x1, sbs_5g_2x2,
+						PM_SAP_24_LL_LT_SAP_DBS_1x1,
+						PM_SAP_24_LL_LT_SAP_DBS_2x2);
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+policy_mgr_get_third_connection_pcl_table_index_go_ll_lt_sap(
+						struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_two_connection_mode index;
+	enum policy_mgr_two_connection_mode sbs_5g_1x1;
+	enum policy_mgr_two_connection_mode sbs_5g_2x2;
+	qdf_freq_t go_freq, sbs_cut_off_freq;
+
+	/*
+	 * LL_LT_SAP can not be in SCC so there will not be any scc index.
+	 * With LL_LT_SAP, MCC is possible only on 5 GHz
+	 */
+	if (policy_mgr_are_2_freq_on_same_mac(
+					psoc,
+					pm_conc_connection_list[0].freq,
+					pm_conc_connection_list[1].freq)) {
+		if (!(WLAN_REG_IS_24GHZ_CH_FREQ(
+			   pm_conc_connection_list[0].freq)) &&
+			   !(WLAN_REG_IS_24GHZ_CH_FREQ(
+			   pm_conc_connection_list[1].freq))) {
+			if (POLICY_MGR_ONE_ONE ==
+					pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_5_LL_LT_SAP_MCC_1x1;
+			else
+				index = PM_P2P_GO_5_LL_LT_SAP_MCC_2x2;
+
+			return index;
+		}
+	}
+
+	if (pm_conc_connection_list[0].mode == PM_P2P_GO_MODE)
+		go_freq = pm_conc_connection_list[0].freq;
+	else
+		go_freq = pm_conc_connection_list[1].freq;
+
+	sbs_cut_off_freq =  policy_mgr_get_sbs_cut_off_freq(psoc);
+
+	if (go_freq < sbs_cut_off_freq) {
+		sbs_5g_1x1 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1;
+		sbs_5g_2x2 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2;
+	} else {
+		sbs_5g_1x1 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1;
+		sbs_5g_2x2 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2;
+	}
+
+	index =
+	policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(
+						psoc, sbs_5g_1x1, sbs_5g_2x2,
+						PM_P2P_GO_24_LL_LT_SAP_DBS_1x1,
+						PM_P2P_GO_24_LL_LT_SAP_DBS_2x2);
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+policy_mgr_get_third_connection_pcl_table_index_cli_ll_lt_sap(
+						struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_two_connection_mode index;
+	enum policy_mgr_two_connection_mode sbs_5g_1x1;
+	enum policy_mgr_two_connection_mode sbs_5g_2x2;
+	qdf_freq_t cli_freq, sbs_cut_off_freq;
+
+	/*
+	 * LL_LT_SAP can not be in SCC so there will not be any scc index.
+	 * With LL_LT_SAP, MCC is possible only on 5 GHz
+	 */
+	if (policy_mgr_are_2_freq_on_same_mac(
+					psoc,
+					pm_conc_connection_list[0].freq,
+					pm_conc_connection_list[1].freq)) {
+		if (!(WLAN_REG_IS_24GHZ_CH_FREQ(
+			   pm_conc_connection_list[0].freq)) &&
+			   !(WLAN_REG_IS_24GHZ_CH_FREQ(
+			   pm_conc_connection_list[1].freq))) {
+			if (POLICY_MGR_ONE_ONE ==
+					pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1;
+			else
+				index = PM_P2P_CLI_5_LL_LT_SAP_MCC_2x2;
+
+			return index;
+		}
+	}
+
+	if (pm_conc_connection_list[0].mode == PM_P2P_GO_MODE)
+		cli_freq = pm_conc_connection_list[0].freq;
+	else
+		cli_freq = pm_conc_connection_list[1].freq;
+
+	sbs_cut_off_freq =  policy_mgr_get_sbs_cut_off_freq(psoc);
+
+	if (cli_freq < sbs_cut_off_freq) {
+		sbs_5g_1x1 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1;
+		sbs_5g_2x2 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2;
+	} else {
+		sbs_5g_1x1 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1;
+		sbs_5g_2x2 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2;
+	}
+
+	index =
+	policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(
+					psoc, sbs_5g_1x1, sbs_5g_2x2,
+					PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1,
+					PM_P2P_CLI_24_LL_LT_SAP_DBS_2x2);
+	return index;
+}
+
 enum policy_mgr_two_connection_mode
 policy_mgr_get_third_connection_pcl_table_index(
 					struct wlan_objmgr_psoc *psoc)
@@ -2721,6 +2926,30 @@ policy_mgr_get_third_connection_pcl_table_index(
 		index =
 		policy_mgr_get_third_connection_pcl_table_index_cli_cli(psoc);
 
+	else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) &&
+		  (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		 (PM_STA_MODE == pm_conc_connection_list[1].mode)))
+		index = policy_mgr_get_third_connection_pcl_table_index_sta_ll_lt_sap(psoc);
+
+	else if (((PM_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		  (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		 (PM_SAP_MODE == pm_conc_connection_list[1].mode)))
+		index = policy_mgr_get_third_connection_pcl_table_index_sap_ll_lt_sap(psoc);
+
+	else if (((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) &&
+		  (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		 (PM_P2P_GO_MODE == pm_conc_connection_list[1].mode)))
+		index = policy_mgr_get_third_connection_pcl_table_index_go_ll_lt_sap(psoc);
+
+	else if (((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) &&
+		  (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		 (PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode)))
+		index = policy_mgr_get_third_connection_pcl_table_index_cli_ll_lt_sap(psoc);
+
 	policy_mgr_debug("mode0:%d mode1:%d freq0:%d freq1:%d chain:%d index:%d",
 			 pm_conc_connection_list[0].mode,
 			 pm_conc_connection_list[1].mode,
@@ -3822,6 +4051,10 @@ QDF_STATUS policy_mgr_modify_sap_pcl_based_on_mandatory_channel(
 	bool sta_sap_scc_on_5ghz_channel;
 	bool scc_on_indoor =
 		 policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc);
+	uint8_t go_count;
+	uint32_t go_op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint8_t go_vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint32_t go_op_ch_freq_5g = 0;
 
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {
@@ -3855,6 +4088,14 @@ QDF_STATUS policy_mgr_modify_sap_pcl_based_on_mandatory_channel(
 	sta_sap_scc_on_5ghz_channel =
 		policy_mgr_is_connected_sta_5g(psoc, &sta_5GHz_freq);
 
+	go_count = policy_mgr_get_mode_specific_conn_info(
+				psoc, go_op_ch_freq_list,
+				go_vdev_id_list, PM_P2P_GO_MODE);
+	if (go_count && !WLAN_REG_IS_24GHZ_CH_FREQ(go_op_ch_freq_list[0])) {
+		go_op_ch_freq_5g = go_op_ch_freq_list[0];
+		policy_mgr_debug("go 5/6G present, SAP exclude 5/6G channels");
+	}
+
 	for (i = 0; i < *pcl_len_org; i++) {
 		found = false;
 		if (i >= NUM_CHANNELS) {
@@ -3862,6 +4103,10 @@ QDF_STATUS policy_mgr_modify_sap_pcl_based_on_mandatory_channel(
 			break;
 		}
 
+		if (go_op_ch_freq_5g &&
+		    !WLAN_REG_IS_24GHZ_CH_FREQ(pcl_list_org[i]))
+			continue;
+
 		if (scc_on_indoor && policy_mgr_is_force_scc(psoc) &&
 		    pcl_list_org[i] == indoor_sta_freq) {
 			policy_mgr_debug("indoor chan:%d", pcl_list_org[i]);
@@ -3981,9 +4226,8 @@ policy_mgr_get_sap_mandatory_channel(struct wlan_objmgr_psoc *psoc,
 	mcc_to_scc_switch =
 		policy_mgr_get_mcc_to_scc_switch_mode(psoc);
 
-	sta_count =
-		policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE,
-							  NULL);
+	sta_count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE,
+							      NULL);
 
 	if (!sta_count || mcc_to_scc_switch !=
 			QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL)
@@ -4091,7 +4335,7 @@ policy_mgr_get_sap_mandatory_channel(struct wlan_objmgr_psoc *psoc,
 		if (user_config_freq && (pcl.pcl_list[i] == user_config_freq)) {
 			sap_new_freq = pcl.pcl_list[i];
 			policy_mgr_debug("Prefer starting SAP on user configured channel:%d",
-					 sap_ch_freq);
+					 sap_new_freq);
 			goto update_freq;
 		}
 	}
@@ -4174,6 +4418,16 @@ QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc,
 					psoc, PM_P2P_CLIENT_MODE, NULL)))
 			strict_follow_pcl = true;
 
+		/*
+		 * This is a temporary check and will be removed once ll_lt_sap
+		 * CSA support is added.
+		 */
+		if (wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc) !=
+							WLAN_INVALID_VDEV_ID) {
+			policy_mgr_debug("LL_LT_SAP present, strict follow PCL");
+			strict_follow_pcl = true;
+		}
+
 		/*
 		 * There is a small window between releasing the above lock
 		 * and acquiring the same in policy_mgr_allow_concurrency,
@@ -4803,3 +5057,57 @@ policy_mgr_get_pcl_channel_for_ll_sap_concurrency(
 	return QDF_STATUS_SUCCESS;
 }
 #endif
+
+#ifdef WLAN_FEATURE_LL_LT_SAP
+QDF_STATUS policy_mgr_get_pcl_ch_list_for_ll_sap(
+					struct wlan_objmgr_psoc *psoc,
+					struct policy_mgr_pcl_list *pcl,
+					uint8_t vdev_id,
+					struct connection_info *info,
+					uint8_t *connection_count)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint8_t num_cxn_del = 0;
+	struct policy_mgr_conc_connection_info pm_info = {0};
+	QDF_STATUS status;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx)
+		return QDF_STATUS_E_FAILURE;
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+
+	/*
+	 * Scenario: Standalone XPAN is present and CSA happens on
+	 * LL_LT_SAP interface.
+	 * During CSA, it will check the PCL list to get the new freq.
+	 * Since there is already LL_LT_SAP interface entry in PCL index.
+	 * It will lead to LL_LT_SAP + LL_LT_SAP concurrencies. To avoid
+	 * that, delete the existing connection entry from PCL index,
+	 * get the PCL list and restore it back.
+	 */
+	policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id,
+						      &pm_info, &num_cxn_del);
+
+	status = policy_mgr_get_pcl(psoc, PM_LL_LT_SAP_MODE, pcl->pcl_list,
+				    &pcl->pcl_len, pcl->weight_list,
+				    QDF_ARRAY_SIZE(pcl->weight_list),
+				    vdev_id);
+
+	/*
+	 * Get existing connection info before updating LL_LT_SAP freq list
+	 * This will help to avoid updation of SCC channel in LL_LT_SAP
+	 * freq list.
+	 */
+	*connection_count = policy_mgr_get_connection_info(psoc, info);
+
+	/* Restore the connection entry */
+	if (num_cxn_del > 0)
+		policy_mgr_restore_deleted_conn_info(psoc, &pm_info,
+						     num_cxn_del);
+
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+#endif

Файловите разлики са ограничени, защото са твърде много
+ 129 - 196
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h


Файловите разлики са ограничени, защото са твърде много
+ 129 - 197
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_sbs_i.h


+ 6 - 9
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h

@@ -398,14 +398,12 @@ void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc,
  * 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
+ * @req_freq: freq for which rx clear count require
  *
- * Return: None
+ * Return: channel load
  */
-void wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
-				      uint8_t vdev_id, uint8_t channel,
-				      uint8_t *chan_load);
+uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
+					 uint8_t vdev_id, qdf_freq_t req_freq);
 
 /**
  * ucfg_mc_cp_stats_clear_channel_status() - API to clear chan stats
@@ -520,9 +518,8 @@ 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)
+uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
+					 uint8_t vdev_id, qdf_freq_t req_freq)
 {
 }
 

+ 15 - 13
components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c

@@ -1049,23 +1049,23 @@ void ucfg_mc_cp_stats_register_lost_link_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)
+uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
+					 uint8_t vdev_id, qdf_freq_t req_freq)
 {
 	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 total_channel, chan_load = 0;
 	uint8_t i;
 	uint32_t rx_clear_count = 0, cycle_count = 0;
+	bool found = false;
 
 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
 						    WLAN_CP_STATS_ID);
 	if (!vdev)
-		return;
+		return 0;
 
 	pdev = wlan_vdev_get_pdev(vdev);
 	if (!pdev) {
@@ -1083,16 +1083,17 @@ void wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
 	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) {
+	for (i = 0; i < total_channel; i++) {
+		if (channel_status_list[i].channel_freq == req_freq) {
 			rx_clear_count = channel_status_list[i].rx_clear_count;
 			cycle_count = channel_status_list[i].cycle_count;
+			found = true;
 			break;
 		}
 	}
 
-	if (i == total_channel) {
-		cp_stats_debug("no channel found for chan:%d", channel);
+	if (!found) {
+		cp_stats_debug("no channel found for freq:%d", req_freq);
 		goto release_ref;
 	}
 
@@ -1101,14 +1102,15 @@ void wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
 		goto release_ref;
 	}
 
-	*chan_load = ((rx_clear_count * 255) / cycle_count);
+	chan_load = ((rx_clear_count * 255) / cycle_count);
 
-	cp_stats_debug("t_chan:%d, chan:%d, rcc:%u, cc:%u, chan_load:%d",
-		       total_channel, channel, rx_clear_count, cycle_count,
-		       *chan_load);
+	cp_stats_debug("t_chan:%d, freq:%d, rcc:%u, cc:%u, chan_load:%d",
+		       total_channel, req_freq, rx_clear_count, cycle_count,
+		       chan_load);
 
 release_ref:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
+	return chan_load;
 }
 #endif
 

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

@@ -867,7 +867,7 @@ QDF_STATUS dp_softap_rx_packet_cbk(void *link_ctx, qdf_nbuf_t rx_buf)
 			is_eapol = true;
 
 		if (qdf_unlikely(is_eapol &&
-		    !(!qdf_mem_cmp(dp_intf->mac_addr.bytes,
+		    !(!qdf_mem_cmp(dp_link->mac_addr.bytes,
 				   qdf_nbuf_data(nbuf) +
 				   QDF_NBUF_DEST_MAC_OFFSET,
 				   QDF_MAC_ADDR_SIZE) ||

+ 25 - 7
components/dp/core/src/wlan_dp_txrx.c

@@ -49,7 +49,7 @@ uint32_t wlan_dp_intf_get_pkt_type_bitmap_value(void *intf_ctx)
 	struct wlan_dp_intf *dp_intf = (struct wlan_dp_intf *)intf_ctx;
 
 	if (!dp_intf) {
-		dp_err("DP Context is NULL");
+		dp_err_rl("DP Context is NULL");
 		return 0;
 	}
 
@@ -421,6 +421,17 @@ void dp_get_transmit_mac_addr(struct wlan_dp_link *dp_link,
 	bool is_mc_bc_addr = false;
 	enum nan_datapath_state state;
 
+	/* Check for VDEV validity before accessing it. Since VDEV references
+	 * are not taken in the per packet path, there is a change for VDEV
+	 * getting deleted in a parallel context. Because DP VDEV object is
+	 * protected by dp_intf::num_active_task, the chance of VDEV object
+	 * getting deleted while executing dp_start_xmit() is sparse. So, a
+	 * simple VDEV NULL check should be sufficient to handle the case of
+	 * VDEV getting destroyed first followed by dp_start_xmit().
+	 */
+	if (!dp_link->vdev)
+		return;
+
 	switch (dp_intf->device_mode) {
 	case QDF_NDI_MODE:
 		state = wlan_nan_get_ndi_state(dp_link->vdev);
@@ -518,6 +529,13 @@ static void dp_mark_icmp_req_to_fw(struct wlan_dp_psoc_context *dp_ctx,
 	if (time_interval_ms == WLAN_CFG_ICMP_REQ_TO_FW_MARK_ALL)
 		QDF_NBUF_CB_TX_PACKET_TO_FW(nbuf) = 1;
 
+	/* For fragment IPV4 ICMP frames
+	 * only mark last segment once to FW
+	 */
+	if (qdf_nbuf_is_ipv4_pkt(nbuf) &&
+	    qdf_nbuf_is_ipv4_fragment(nbuf))
+		return;
+
 	curr_time = qdf_get_log_timestamp();
 	time_delta = curr_time - prev_marked_icmp_time;
 	if (time_delta >= (time_interval_ms *
@@ -674,7 +692,7 @@ dp_start_xmit(struct wlan_dp_link *dp_link, qdf_nbuf_t nbuf)
 
 	/* check whether need to linearize nbuf, like non-linear udp data */
 	if (dp_nbuf_nontso_linearize(nbuf) != QDF_STATUS_SUCCESS) {
-		dp_err(" nbuf %pK linearize failed. drop the pkt", nbuf);
+		dp_err_rl(" nbuf %pK linearize failed. drop the pkt", nbuf);
 		goto drop_pkt_and_release_nbuf;
 	}
 
@@ -682,7 +700,7 @@ dp_start_xmit(struct wlan_dp_link *dp_link, qdf_nbuf_t nbuf)
 	 * If a transmit function is not registered, drop packet
 	 */
 	if (!dp_intf->txrx_ops.tx.tx) {
-		dp_err("TX function not registered by the data path");
+		dp_err_rl("TX function not registered by the data path");
 		goto drop_pkt_and_release_nbuf;
 	}
 
@@ -838,14 +856,14 @@ QDF_STATUS dp_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf)
 
 	/* Sanity check on inputs */
 	if ((!context) || (!rxbuf)) {
-		dp_err("Null params being passed");
+		dp_err_rl("Null params being passed");
 		return QDF_STATUS_E_FAILURE;
 	}
 
 	dp_link = (struct wlan_dp_link *)context;
 	dp_intf = dp_link->dp_intf;
 	if (!dp_intf) {
-		dp_err("dp_intf is NULL for dp_link %pK", dp_link);
+		dp_err_rl("dp_intf is NULL for dp_link %pK", dp_link);
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -1364,7 +1382,7 @@ QDF_STATUS dp_rx_pkt_thread_enqueue_cbk(void *link_ctx,
 	qdf_nbuf_t head_ptr;
 
 	if (qdf_unlikely(!link_ctx || !nbuf_list)) {
-		dp_err("Null params being passed");
+		dp_err_rl("Null params being passed");
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -1650,7 +1668,7 @@ QDF_STATUS dp_rx_packet_cbk(void *dp_link_context,
 
 	/* Sanity check on inputs */
 	if (qdf_unlikely((!dp_link_context) || (!rxBuf))) {
-		dp_err("Null params being passed");
+		dp_err_rl("Null params being passed");
 		return QDF_STATUS_E_FAILURE;
 	}
 

+ 13 - 1
components/dsc/inc/wlan_dsc_vdev.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -167,4 +167,16 @@ uint8_t dsc_vdev_get_cached_cmd(struct dsc_vdev *vdev);
  */
 void dsc_vdev_cache_command(struct dsc_vdev *vdev, uint8_t cmd_id);
 
+/*
+ * dsc_vdev_wait_for_uptree_ops() - Wait for any uptree operations
+ * @vdev: The DSC vdev
+ *
+ * This function checks and waits for any uptree operations if there is any
+ * uptree operation is in progress.
+ *
+ * Return: None.
+ */
+
+void dsc_vdev_wait_for_uptree_ops(struct dsc_vdev *vdev);
+
 #endif /* __WLAN_DSC_VDEV_H */

+ 32 - 1
components/dsc/src/wlan_dsc_vdev.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -104,6 +104,37 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev)
 	__dsc_vdev_destroy(out_vdev);
 }
 
+static void __dsc_vdev_wait_for_uptree_ops(struct dsc_vdev *vdev)
+{
+	bool wait;
+
+	if (!dsc_assert(vdev))
+		return;
+
+	__dsc_driver_lock(vdev);
+	wait = vdev->psoc->ops.count > 0;
+	if (wait)
+		qdf_event_reset(&vdev->psoc->ops.event);
+	__dsc_driver_unlock(vdev);
+
+	if (wait)
+		qdf_wait_single_event(&vdev->psoc->ops.event, 0);
+
+	__dsc_driver_lock(vdev);
+	wait = vdev->psoc->driver->ops.count > 0;
+	if (wait)
+		qdf_event_reset(&vdev->psoc->driver->ops.event);
+	__dsc_driver_unlock(vdev);
+
+	if (wait)
+		qdf_wait_single_event(&vdev->psoc->driver->ops.event, 0);
+}
+
+void dsc_vdev_wait_for_uptree_ops(struct dsc_vdev *vdev)
+{
+	__dsc_vdev_wait_for_uptree_ops(vdev);
+}
+
 #define __dsc_vdev_can_op(vdev) __dsc_vdev_can_trans(vdev)
 
 /*

+ 27 - 12
components/mlme/core/inc/wlan_mlme_main.h

@@ -718,12 +718,6 @@ struct roam_scan_chn {
  *  For non-MLO scenario, it indicates the original connected AP BSSID.
  *  For MLO scenario, it indicates the original BSSID of the link
  *  for which the reassociation occurred during the roam.
- * @candidate_bssid: roam candidate AP BSSID when roam failed.
- *  If the firmware updates more than one candidate AP BSSID
- *  to the driver, the driver only fills the last candidate AP BSSID.
- *  For non-MLO scenario, it indicates the last candidate AP BSSID.
- *  For MLO scenario, it indicates the AP BSSID which may be the primary
- *  link BSSID or a nonprimary link BSSID.
  * @roamed_bssid: roamed AP BSSID when roam succeeds.
  *  For non-MLO case, it indicates new AP BSSID which has been
  *  successfully roamed.
@@ -735,7 +729,6 @@ struct eroam_scan_info {
 	struct roam_scan_chn roam_chn[MAX_ROAM_SCAN_CHAN];
 	uint32_t total_scan_time;
 	struct qdf_mac_addr original_bssid;
-	struct qdf_mac_addr candidate_bssid;
 	struct qdf_mac_addr roamed_bssid;
 };
 
@@ -746,15 +739,15 @@ struct eroam_scan_info {
  * @timestamp: timestamp of the auth/assoc/eapol-M1/M2/M3/M4 frame,
  *  if status is successful, indicate received or send success,
  *  if status is failed, timestamp indicate roaming fail at that time
+ * @bssid: Source address for auth/assoc/eapol frame.
  */
 struct eroam_frame_info {
 	enum eroam_frame_subtype frame_type;
 	enum eroam_frame_status status;
 	uint64_t timestamp;
-};
+	struct qdf_mac_addr bssid;
 
-/* Key frame num during roaming: PREAUTH/PREASSOC/EAPOL M1-M4 */
-#define ROAM_FRAME_NUM 6
+};
 
 /**
  * struct enhance_roam_info - enhance roam information
@@ -765,7 +758,7 @@ struct eroam_frame_info {
 struct enhance_roam_info {
 	struct eroam_trigger_info trigger;
 	struct eroam_scan_info scan;
-	struct eroam_frame_info timestamp[ROAM_FRAME_NUM];
+	struct eroam_frame_info timestamp[WLAN_ROAM_MAX_FRAME_INFO];
 };
 
 /**
@@ -825,6 +818,7 @@ struct enhance_roam_info {
  *				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
+ * @best_6g_power_type: best 6g power type
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -896,6 +890,7 @@ struct mlme_legacy_priv {
 	qdf_wake_lock_t bss_color_change_wakelock;
 	qdf_runtime_lock_t bss_color_change_runtime_lock;
 	qdf_runtime_lock_t disconnect_runtime_lock;
+	enum reg_6g_ap_type best_6g_power_type;
 };
 
 /**
@@ -1116,6 +1111,24 @@ void mlme_set_follow_ap_edca_flag(struct wlan_objmgr_vdev *vdev, bool flag);
  */
 bool mlme_get_follow_ap_edca_flag(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * mlme_set_best_6g_power_type() - Set best 6g power type
+ * @vdev: vdev pointer
+ * @best_6g_power_type: best 6g power type
+ *
+ * Return: None
+ */
+void mlme_set_best_6g_power_type(struct wlan_objmgr_vdev *vdev,
+				 enum reg_6g_ap_type best_6g_power_type);
+
+/**
+ * mlme_get_best_6g_power_type() - Get best 6g power type
+ * @vdev: vdev pointer
+ *
+ * Return: value of best 6g power type
+ */
+enum reg_6g_ap_type mlme_get_best_6g_power_type(struct wlan_objmgr_vdev *vdev);
+
 /**
  * mlme_set_reconn_after_assoc_timeout_flag() - Set reconn after assoc timeout
  * flag
@@ -1218,6 +1231,7 @@ QDF_STATUS wlan_mlme_get_bssid_vdev_id(struct wlan_objmgr_pdev *pdev,
  * @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
+ * @cen320_freq: 320 MHz center freq
  *
  * Return: QDF_STATUS
  */
@@ -1225,7 +1239,8 @@ 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);
+				   qdf_freq_t scan_freq,
+				   qdf_freq_t cen320_freq);
 
 /**
  * wlan_get_operation_chan_freq() - get operating chan freq of

+ 19 - 0
components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h

@@ -586,6 +586,25 @@ wlan_handle_emlsr_sta_concurrency(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS
 wlan_ll_sap_sort_channel_list(uint8_t vdev_id, qdf_list_t *list,
 			      struct sap_sel_ch_info *ch_info);
+
+/**
+ * wlan_ll_sap_free_chan_info() - API to free allocated memory
+ * @ch_param: pointer to sap_sel_ch_info structure
+ *
+ * Return: None
+ */
+void wlan_ll_sap_free_chan_info(struct sap_sel_ch_info *ch_param);
+
+/**
+ * wlan_ll_sap_freq_present_in_pcl() - API to check whether given
+ * frequency is present in PCL or not
+ * @pcl: pcl list
+ * @freq: Frequency to check in PCL list
+ *
+ * Return: True/False
+ */
+bool wlan_ll_sap_freq_present_in_pcl(struct policy_mgr_pcl_list *pcl,
+				     qdf_freq_t freq);
 #endif
 
 /**

+ 86 - 24
components/mlme/core/src/wlan_mlme_main.c

@@ -388,39 +388,63 @@ wlan_scan_get_scan_phy_mode(struct wlan_objmgr_vdev *vdev, qdf_freq_t op_freq,
 	return scan_phymode;
 }
 
+#ifdef WLAN_FEATURE_11BE
+/**
+ * mlme_get_scan_phy_mode_for_chan_load() - get scan phymode from ch width
+ * @scan_ch_width: channel width
+ *
+ * Return: enum scan_phy_mode
+ */
+static enum scan_phy_mode
+mlme_get_scan_phy_mode_for_chan_load(enum phy_ch_width scan_ch_width)
+{
+	enum scan_phy_mode scan_phymode = SCAN_PHY_MODE_UNKNOWN;
+
+	switch (scan_ch_width) {
+	case CH_WIDTH_20MHZ:
+		scan_phymode = SCAN_PHY_MODE_11BE_EHT20;
+		break;
+	case CH_WIDTH_40MHZ:
+		scan_phymode = SCAN_PHY_MODE_11BE_EHT40;
+		break;
+	case CH_WIDTH_80MHZ:
+		scan_phymode = SCAN_PHY_MODE_11BE_EHT80;
+		break;
+	case CH_WIDTH_160MHZ:
+		scan_phymode = SCAN_PHY_MODE_11BE_EHT160;
+		break;
+	default:
+		mlme_debug("Invalid scan_ch_width:%d", scan_ch_width);
+		break;
+	}
+
+	return scan_phymode;
+}
+#else
+static inline enum scan_phy_mode
+mlme_get_scan_phy_mode_for_chan_load(enum phy_ch_width scan_ch_width)
+{
+	return SCAN_PHY_MODE_UNKNOWN;
+}
+#endif
+
 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)
+				   qdf_freq_t scan_freq,
+				   qdf_freq_t cen320_freq)
 {
 	const struct bonded_channel_freq *range;
 	uint8_t num_chan;
 	qdf_freq_t op_freq, center_20_freq, start_freq, end_freq;
-	qdf_freq_t cen320_freq = 0;
 	enum scan_phy_mode phymode = SCAN_PHY_MODE_UNKNOWN;
-	uint8_t vdev_id;
-	struct wlan_channel *des_chan;
-	struct mlme_legacy_priv *mlme_priv;
-
-	vdev_id = vdev->vdev_objmgr.vdev_id;
+	uint8_t vdev_id = vdev->vdev_objmgr.vdev_id;
 
-	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
-	if (!mlme_priv)
-		return QDF_STATUS_E_FAILURE;
-
-	if (scan_freq != INVALID_CHANNEL) {
+	if (scan_freq != INVALID_CHANNEL)
 		op_freq = scan_freq;
-	} else {
-		des_chan = wlan_vdev_mlme_get_des_chan(vdev);
-		if (!des_chan) {
-			mlme_debug("null des chan");
-			return QDF_STATUS_E_FAILURE;
-		}
-		op_freq = des_chan->ch_freq;
-		/* Set center_freq1 to center frequency of complete 320MHz */
-		cen320_freq = mlme_priv->connect_info.assoc_chan_info.cen320_freq;
-	}
+	else
+		op_freq = wlan_get_operation_chan_freq(vdev);
 
 	mlme_debug("vdev %d :op_freq:%d, cen320_freq:%d, scan_ch_width: %d",
 		   vdev_id, op_freq, cen320_freq, scan_ch_width);
@@ -463,7 +487,11 @@ mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev,
 		num_chan += 1;
 		req->scan_req.chan_list.num_chan = num_chan;
 	} else {
-		phymode = wlan_scan_get_scan_phy_mode(vdev, op_freq, vdev_id);
+		if (scan_freq != INVALID_CHANNEL)
+			phymode = mlme_get_scan_phy_mode_for_chan_load(scan_ch_width);
+		else
+			phymode = wlan_scan_get_scan_phy_mode(vdev, op_freq, vdev_id);
+
 		if (phymode == SCAN_PHY_MODE_UNKNOWN) {
 			mlme_debug("vdev %d : invalid scan phymode for freq %d",
 				   vdev_id, op_freq);
@@ -623,6 +651,7 @@ mlme_fill_freq_in_wide_scan_start_request(struct wlan_objmgr_vdev *vdev,
 	struct mlme_legacy_priv *mlme_priv;
 	enum phy_ch_width associated_ch_width;
 	QDF_STATUS status;
+	qdf_freq_t assoc_cen320_freq = 0;
 
 	req->scan_req.chan_list.num_chan = 0;
 
@@ -646,9 +675,13 @@ mlme_fill_freq_in_wide_scan_start_request(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	/* Set center frequency of complete 320MHz */
+	assoc_cen320_freq = mlme_priv->connect_info.assoc_chan_info.cen320_freq;
+
 	status = mlme_update_freq_in_scan_start_req(vdev, req,
 						    associated_ch_width,
-						    INVALID_CHANNEL);
+						    INVALID_CHANNEL,
+						    assoc_cen320_freq);
 	if (QDF_IS_STATUS_ERROR(status))
 		return QDF_STATUS_E_FAILURE;
 
@@ -2716,6 +2749,8 @@ static void mlme_init_sta_cfg(struct wlan_objmgr_psoc *psoc,
 	mlme_init_sta_mlo_cfg(psoc, sta);
 	wlan_mlme_set_epcs_capability(psoc, false);
 	wlan_mlme_set_usr_disable_sta_eht(psoc, false);
+	wlan_mlme_set_eht_disable_punct_in_us_lpi(psoc,
+						  cfg_default(CFG_EHT_DISABLE_PUNCT_IN_US_LPI));
 }
 
 static void mlme_init_stats_cfg(struct wlan_objmgr_psoc *psoc,
@@ -4260,6 +4295,33 @@ bool mlme_get_follow_ap_edca_flag(struct wlan_objmgr_vdev *vdev)
 	return mlme_priv->follow_ap_edca;
 }
 
+void mlme_set_best_6g_power_type(struct wlan_objmgr_vdev *vdev,
+				 enum reg_6g_ap_type best_6g_power_type)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return;
+	}
+
+	mlme_priv->best_6g_power_type = best_6g_power_type;
+}
+
+enum reg_6g_ap_type mlme_get_best_6g_power_type(struct wlan_objmgr_vdev *vdev)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return REG_VERY_LOW_POWER_AP;
+	}
+
+	return mlme_priv->best_6g_power_type;
+}
+
 void mlme_set_reconn_after_assoc_timeout_flag(struct wlan_objmgr_psoc *psoc,
 					      uint8_t vdev_id, bool flag)
 {

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

@@ -2120,6 +2120,20 @@ vdevmgr_vdev_reconfig_notify(struct vdev_mlme_obj *vdev_mlme,
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS
+vdevmgr_vdev_reconfig_notify_standby(struct vdev_mlme_obj *vdev_mlme,
+				     struct ml_rv_info *reconfig_info)
+{
+	struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
+
+	if (!vdev) {
+		mlme_err("invalid vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return policy_mgr_handle_link_removal_on_standby(vdev, reconfig_info);
+}
+
 static void
 vdevmgr_vdev_reconfig_timer_complete(struct vdev_mlme_obj *vdev_mlme)
 {
@@ -2288,6 +2302,24 @@ wlan_ll_sap_sort_channel_list(uint8_t vdev_id, qdf_list_t *list,
 {
 	return wlansap_sort_channel_list(vdev_id, list, ch_info);
 }
+
+void wlan_ll_sap_free_chan_info(struct sap_sel_ch_info *ch_param)
+{
+	return wlansap_free_chan_info(ch_param);
+}
+
+bool wlan_ll_sap_freq_present_in_pcl(struct policy_mgr_pcl_list *pcl,
+				     qdf_freq_t freq)
+{
+	uint8_t i;
+
+	for (i = 0; i < pcl->pcl_len; i++) {
+		if (pcl->pcl_list[i] == freq)
+			return true;
+	}
+
+	return false;
+}
 #endif
 
 void
@@ -2321,6 +2353,9 @@ static struct vdev_mlme_ops sta_mlme_ops = {
 			vdevmgr_vdev_reconfig_notify,
 	.mlme_vdev_reconfig_timer_complete =
 			vdevmgr_vdev_reconfig_timer_complete,
+	.mlme_vdev_reconfig_notify_standby =
+			vdevmgr_vdev_reconfig_notify_standby,
+
 #endif
 };
 

+ 28 - 1
components/mlme/dispatcher/inc/cfg_mlme_sta.h

@@ -718,6 +718,32 @@
 #define CFG_MLO_SAME_LINK_MLD_ADDR_CFG
 #endif
 
+/*
+ * <ini>
+ * eht_disable_punct_in_us_lpi - Flag to Disable eht puncture in US LPI mode
+ * @Min: false
+ * @Max: true
+ * @Default: false
+ *
+ * Related: None
+ *
+ * Supported Feature: 802.11be protocol
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#define CFG_EHT_DISABLE_PUNCT_IN_US_LPI \
+	CFG_BOOL("eht_disable_punct_in_us_lpi", \
+		 false, \
+		 "Disable eht puncture in US LPI mode")
+
+#ifdef WLAN_FEATURE_11BE
+#define CFG_EHT_DISABLE_PUNCT_IN_US_LPI_CFG CFG(CFG_EHT_DISABLE_PUNCT_IN_US_LPI)
+#else
+#define CFG_EHT_DISABLE_PUNCT_IN_US_LPI_CFG
+#endif
+
 #define CFG_STA_ALL \
 	CFG(CFG_INFRA_STA_KEEP_ALIVE_PERIOD) \
 	CFG(CFG_STA_BSS_MAX_IDLE_PERIOD) \
@@ -743,5 +769,6 @@
 	CFG_MLO_MAX_SIMULTANEOUS_LINKS_CFG \
 	CFG_MLO_SUPPORT_LINK_BAND_CFG \
 	CFG_MLO_PREFER_PERCENTAGE_CFG \
-	CFG_MLO_SAME_LINK_MLD_ADDR_CFG
+	CFG_MLO_SAME_LINK_MLD_ADDR_CFG \
+	CFG_EHT_DISABLE_PUNCT_IN_US_LPI_CFG
 #endif /* CFG_MLME_STA_H__ */

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

@@ -1318,6 +1318,52 @@ bool wlan_mlme_get_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc);
  */
 void wlan_mlme_set_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc,
 				       bool disable);
+
+/**
+ * wlan_mlme_get_eht_disable_punct_in_us_lpi() - Get disable eht punct in us
+ * lpi mode flag.
+ * @psoc: psoc object
+ *
+ * Return: true if eht punct disabled in us lpi mode
+ */
+bool wlan_mlme_get_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_mlme_set_eht_disable_punct_in_us_lpi() - Set disable eht punct in us
+ * lpi mode flag.
+ * @psoc: psoc object
+ * @flag: true if eht punct disabled in us lpi mode
+ *
+ * Return: void
+ */
+void wlan_mlme_set_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc,
+					       bool flag);
+/**
+ * wlan_mlme_update_bw_no_punct() - update connected VDEV
+ * channel bandwidth without puncture bitmap for FCC requirement
+ * @psoc: pointer to SOC object
+ * @vdev_id: vdev id
+ *
+ * Return: none
+ */
+QDF_STATUS
+wlan_mlme_update_bw_no_punct(struct wlan_objmgr_psoc *psoc,
+			     uint8_t vdev_id);
+
+/**
+ * wlan_mlme_get_bw_no_punct() - Get connected VDEV
+ * channel bandwidth without puncture bitmap for FCC requirement
+ * @psoc: pointer to SOC object
+ * @vdev: pointer to vdev
+ * @bss_chan: bss chan with puncture
+ * @new_ch_width: pointer to new channel bandwidth without puncture
+ * Return: none
+ */
+QDF_STATUS
+wlan_mlme_get_bw_no_punct(struct wlan_objmgr_psoc *psoc,
+			  struct wlan_objmgr_vdev *vdev,
+			  struct wlan_channel *bss_chan,
+			  enum phy_ch_width *new_ch_width);
 #else
 static inline
 bool wlan_mlme_get_epcs_capability(struct wlan_objmgr_psoc *psoc)
@@ -1341,6 +1387,34 @@ void wlan_mlme_set_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc,
 				       bool disable)
 {
 }
+
+static inline
+bool wlan_mlme_get_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc)
+{
+	return false;
+}
+
+static inline
+void wlan_mlme_set_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc,
+					       bool flag)
+{
+}
+
+static inline QDF_STATUS
+wlan_mlme_update_bw_no_punct(struct wlan_objmgr_psoc *psoc,
+			     uint8_t vdev_id)
+{
+	return QDF_STATUS_E_INVAL;
+}
+
+static inline QDF_STATUS
+wlan_mlme_get_bw_no_punct(struct wlan_objmgr_psoc *psoc,
+			  struct wlan_objmgr_vdev *vdev,
+			  struct wlan_channel *bss_chan,
+			  enum phy_ch_width *new_ch_width)
+{
+	return QDF_STATUS_E_INVAL;
+}
 #endif
 
 /**

+ 8 - 1
components/mlme/dispatcher/inc/wlan_mlme_public_struct.h

@@ -234,6 +234,7 @@ struct mlme_edca_ac_vo {
  * @MLME_DOT11_MODE_11AX_ONLY: vdev just supports 11AX mode
  * @MLME_DOT11_MODE_11BE: vdev supports 11BE mode, and modes above it
  * @MLME_DOT11_MODE_11BE_ONLY: vdev just supports 11BE mode
+ * @MLME_DOT11_MODE_ABG: vdev supports just 11A, 11B and 11G modes
  */
 enum mlme_dot11_mode {
 	MLME_DOT11_MODE_ALL,
@@ -248,7 +249,8 @@ enum mlme_dot11_mode {
 	MLME_DOT11_MODE_11AX,
 	MLME_DOT11_MODE_11AX_ONLY,
 	MLME_DOT11_MODE_11BE,
-	MLME_DOT11_MODE_11BE_ONLY
+	MLME_DOT11_MODE_11BE_ONLY,
+	MLME_DOT11_MODE_ABG
 };
 
 /**
@@ -1818,6 +1820,7 @@ enum station_prefer_bw {
  * @mlo_prefer_percentage:          percentage to boost/reduce mlo scoring
  * @epcs_capability:                epcs capability enable or disable flag
  * @usr_disable_eht:                user disable the eht for STA
+ * @eht_disable_punct_in_us_lpi:    Disable eht puncture in us lpi mode
  */
 struct wlan_mlme_sta_cfg {
 	uint32_t sta_keep_alive_period;
@@ -1856,6 +1859,7 @@ struct wlan_mlme_sta_cfg {
 #ifdef WLAN_FEATURE_11BE
 	bool epcs_capability;
 	bool usr_disable_eht;
+	bool eht_disable_punct_in_us_lpi;
 #endif
 };
 
@@ -1963,6 +1967,8 @@ struct fw_scan_channels {
  * @roam_trigger_bitmap: Bitmap of roaming triggers.
  * @sta_roam_disable: STA roaming disabled by interfaces
  * @roam_info_stats_num: STA roaming information cache number
+ * @roam_high_rssi_delta: Delta change in high RSSI at which roam scan is
+ * triggered in 2.4/5 GHz.
  * @early_stop_scan_enable: Set early stop scan
  * @enable_5g_band_pref: Enable preference for 5G from INI
  * @ese_enabled: Enable ESE feature
@@ -2092,6 +2098,7 @@ struct wlan_mlme_lfr_cfg {
 	uint32_t roam_trigger_bitmap;
 	uint32_t sta_roam_disable;
 	uint32_t roam_info_stats_num;
+	uint8_t roam_high_rssi_delta;
 #endif
 	bool early_stop_scan_enable;
 	bool enable_5g_band_pref;

+ 4 - 4
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -4904,17 +4904,17 @@ QDF_STATUS ucfg_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc,
  * ucfg_mlme_send_ch_width_update_with_notify() - Send chwidth with notify
  * capability of FW
  * @psoc: pointer to psoc object
- * @vdev_id: Vdev id
+ * @link_vdev: Link VDEV object
  * @ch_width: channel width to update
- * @link_id: mlo link id
+ * @link_vdev_id: vdev id for each link
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS
 ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
-					   uint8_t vdev_id,
+					   struct wlan_objmgr_vdev *link_vdev,
 					   enum phy_ch_width ch_width,
-					   uint8_t link_id);
+					   uint8_t link_vdev_id);
 
 /**
  * ucfg_mlme_is_chwidth_with_notify_supported() - Get chwidth with notify

+ 138 - 7
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -39,6 +39,7 @@
 #include "wmi_unified_vdev_api.h"
 #include "wlan_mlme_api.h"
 #include "../../core/src/wlan_cp_stats_defs.h"
+#include "wlan_reg_services_api.h"
 
 /* quota in milliseconds */
 #define MCC_DUTY_CYCLE 70
@@ -372,13 +373,12 @@ void wlan_mlme_ll_lt_sap_send_oce_flags_fw(struct wlan_objmgr_vdev *vdev)
 
 	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);
+	wma_debug("Vdev %d Disable FILS discovery", 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");
+		mlme_legacy_err("Vdev %d failed to send OCE update", vdev_id);
 }
 
 QDF_STATUS wlan_mlme_set_ap_policy(struct wlan_objmgr_vdev *vdev,
@@ -1397,6 +1397,27 @@ void wlan_mlme_set_epcs_capability(struct wlan_objmgr_psoc *psoc, bool flag)
 	mlme_obj->cfg.sta.epcs_capability = flag;
 }
 
+bool wlan_mlme_get_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc);
+
+	if (!mlme_obj)
+		return false;
+
+	return mlme_obj->cfg.sta.eht_disable_punct_in_us_lpi;
+}
+
+void wlan_mlme_set_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc, bool flag)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc);
+
+	if (!mlme_obj)
+		return;
+
+	mlme_debug("set mlme epcs capability to %d", flag);
+	mlme_obj->cfg.sta.eht_disable_punct_in_us_lpi = flag;
+}
+
 bool wlan_mlme_get_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc);
@@ -7354,9 +7375,25 @@ wlan_mlme_update_vdev_chwidth_with_notify(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
+#ifdef WLAN_FEATURE_11BE
+static
+void wlan_mlme_set_puncture(struct wlan_channel *des_chan,
+			    uint16_t puncture_bitmap)
+{
+	des_chan->puncture_bitmap = puncture_bitmap;
+}
+#else
+static
+void wlan_mlme_set_puncture(struct wlan_channel *des_chan,
+			    uint16_t puncture_bitmap)
+{
+}
+#endif
+
 static QDF_STATUS wlan_mlme_update_ch_width(struct wlan_objmgr_vdev *vdev,
 					    uint8_t vdev_id,
 					    enum phy_ch_width ch_width,
+					    uint16_t puncture_bitmap,
 					    qdf_freq_t sec_2g_freq)
 {
 	struct wlan_channel *des_chan;
@@ -7392,6 +7429,7 @@ static QDF_STATUS wlan_mlme_update_ch_width(struct wlan_objmgr_vdev *vdev,
 	des_chan->ch_freq_seg2 = ch_params.center_freq_seg1;
 	des_chan->ch_cfreq1 = ch_params.mhz_freq_seg0;
 	des_chan->ch_cfreq2 = ch_params.mhz_freq_seg1;
+	wlan_mlme_set_puncture(des_chan, puncture_bitmap);
 
 	status = wlan_update_peer_phy_mode(des_chan, vdev);
 	if (QDF_IS_STATUS_ERROR(status)) {
@@ -7639,7 +7677,7 @@ wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 	}
 
 	/* update ch width to internal host structure */
-	status = wlan_mlme_update_ch_width(vdev, vdev_id, ch_width,
+	status = wlan_mlme_update_ch_width(vdev, vdev_id, ch_width, 0,
 					   sec_2g_freq);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_err("vdev %d: Failed to update CW:%d to host, status:%d",
@@ -7992,9 +8030,6 @@ wlan_mlme_get_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev)
 		return CH_WIDTH_INVALID;
 	}
 
-	mlme_debug("SAP oper ch_width: %d, vdev %d",
-		   mlme_priv->mlme_ap.oper_ch_width, wlan_vdev_get_id(vdev));
-
 	return mlme_priv->mlme_ap.oper_ch_width;
 }
 
@@ -8004,3 +8039,99 @@ wlan_mlme_send_csa_event_status_ind(struct wlan_objmgr_vdev *vdev,
 {
 	return wlan_mlme_send_csa_event_status_ind_cmd(vdev, csa_status);
 }
+
+#ifdef WLAN_FEATURE_11BE
+QDF_STATUS
+wlan_mlme_get_bw_no_punct(struct wlan_objmgr_psoc *psoc,
+			  struct wlan_objmgr_vdev *vdev,
+			  struct wlan_channel *bss_chan,
+			  enum phy_ch_width *new_ch_width)
+{
+	uint16_t new_punct_bitmap = 0;
+	enum phy_ch_width ch_width;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint8_t country[REG_ALPHA2_LEN + 1];
+
+	if (!wlan_mlme_get_eht_disable_punct_in_us_lpi(psoc))
+		return status;
+
+	wlan_reg_read_current_country(psoc, country);
+
+	if (!wlan_reg_is_6ghz_chan_freq(bss_chan->ch_freq) ||
+	    !bss_chan->puncture_bitmap ||
+	    qdf_mem_cmp(country, "US", REG_ALPHA2_LEN) ||
+	    mlme_get_best_6g_power_type(vdev) != REG_INDOOR_AP ||
+	    !IS_WLAN_PHYMODE_EHT(bss_chan->ch_phymode))
+		goto err;
+
+	ch_width = bss_chan->ch_width;
+
+	while (ch_width != CH_WIDTH_INVALID) {
+		status = wlan_reg_extract_puncture_by_bw(bss_chan->ch_width,
+							 bss_chan->puncture_bitmap,
+							 bss_chan->ch_freq,
+							 bss_chan->ch_cfreq2,
+							 ch_width,
+							 &new_punct_bitmap);
+		if (QDF_IS_STATUS_SUCCESS(status) && new_punct_bitmap)
+			ch_width = wlan_get_next_lower_bandwidth(ch_width);
+		else
+			break;
+	}
+
+	if (ch_width == bss_chan->ch_width)
+		return QDF_STATUS_E_FAILURE;
+
+	mlme_debug("freq %d ccfs2 %d punct 0x%x BW old %d, new %d",
+		   bss_chan->ch_freq, bss_chan->ch_cfreq2, bss_chan->puncture_bitmap,
+		   bss_chan->ch_width, ch_width);
+
+	*new_ch_width = ch_width;
+	bss_chan->puncture_bitmap = 0;
+err:
+	return status;
+}
+
+QDF_STATUS
+wlan_mlme_update_bw_no_punct(struct wlan_objmgr_psoc *psoc,
+			     uint8_t vdev_id)
+{
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	enum phy_ch_width new_ch_width;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (!wlan_mlme_get_eht_disable_punct_in_us_lpi(psoc))
+		return status;
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
+					  WLAN_MLME_NB_ID);
+	if (!pdev) {
+		sme_err("pdev is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
+						    WLAN_MLME_NB_ID);
+	if (!vdev) {
+		mlme_err("VDEV not found for vdev id : %d", vdev_id);
+		goto rel_pdev;
+	}
+
+	status = wlan_mlme_get_bw_no_punct(psoc, vdev,
+					   wlan_vdev_mlme_get_des_chan(vdev),
+					   &new_ch_width);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto rel_vdev;
+
+	status = wlan_mlme_send_ch_width_update_with_notify(psoc,
+							    vdev,
+							    vdev_id,
+							    new_ch_width);
+rel_vdev:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID);
+rel_pdev:
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_MLME_NB_ID);
+
+	return status;
+}
+#endif

+ 2 - 42
components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c

@@ -414,55 +414,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,
+					   struct wlan_objmgr_vdev *link_vdev,
 					   enum phy_ch_width ch_width,
-					   uint8_t link_id)
+					   uint8_t link_vdev_id)
 {
-	struct wlan_objmgr_vdev *vdev;
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
-	enum QDF_OPMODE op_mode;
-	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);
-	if (!vdev) {
-		mlme_legacy_err("vdev %d: vdev not found", vdev_id);
-		return QDF_STATUS_E_FAILURE;
-	}
-
-	op_mode = wlan_vdev_mlme_get_opmode(vdev);
-	if (op_mode != QDF_STA_MODE) {
-		mlme_legacy_debug("vdev %d: op mode %d, CW update not supported",
-				  vdev_id, op_mode);
-		status = QDF_STATUS_E_NOSUPPORT;
-		goto release;
-	}
 
-	if (wlan_vdev_mlme_is_mlo_vdev(vdev) && link_id != 0xFF) {
-		link_vdev = mlo_get_vdev_by_link_id(vdev, link_id,
-						    WLAN_MLME_OBJMGR_ID);
-		if (!link_vdev) {
-			mlme_legacy_debug("vdev is null for the link id:%u",
-					  link_id);
-			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)
-		wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLME_OBJMGR_ID);
-
-release:
-	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
 
 	return status;
 }

+ 3 - 8
components/nan/dispatcher/src/nan_ucfg_api.c

@@ -1001,7 +1001,7 @@ ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id)
 	int err;
 	static const struct osif_request_params params = {
 		.priv_size = 0,
-		.timeout_ms = 1000,
+		.timeout_ms = 2000,
 	};
 
 	if (!ucfg_is_ndi_dbs_supported(psoc))
@@ -1056,21 +1056,16 @@ ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id)
 	if (err) {
 		nan_err("Disabling NDP's timed out waiting for confirmation");
 		status = QDF_STATUS_E_TIMEOUT;
-		goto cleanup;
 	}
 
+cleanup:
 	/*
 	 * Host can assume NDP delete is successful and
 	 * remove policy mgr entry
 	 */
 	policy_mgr_decr_session_set_pcl(psoc, QDF_NDI_MODE, ndi_vdev_id);
 
-cleanup:
-	/* Restore original NDI state in case of failure */
-	if (QDF_IS_STATUS_SUCCESS(status))
-		ucfg_nan_set_ndi_state(ndi_vdev, NAN_DATA_DISCONNECTED_STATE);
-	else
-		ucfg_nan_set_ndi_state(ndi_vdev, curr_ndi_state);
+	ucfg_nan_set_ndi_state(ndi_vdev, NAN_DATA_DISCONNECTED_STATE);
 
 	if (request)
 		osif_request_put(request);

+ 20 - 6
components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c

@@ -730,6 +730,26 @@ static void pkt_capture_rx_get_phy_info(void *context, void *psoc,
 			IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN;
 		rx_status->he_data2 |= IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN;
 		rx_status->he_data3 |= mcs << 0x8;
+
+		/* Map uCode SGI values to Radiotap header
+		 * as per Radiotap header expectation.
+		 *
+		 * uCode has:
+		 *	enum 0     0_8_us_sgi
+		 *	enum 1     0_4_us_sgi
+		 *	enum 2     1_6_us_sgi
+		 *	enum 3     3_2_us_sgi
+		 *
+		 * Radiotap header expectation:
+		 *	enum 0     0_8_us_sgi
+		 *	enum 1     1_6_us_sgi
+		 *	enum 2     3_2_us_sgi
+		 */
+		if (sgi == HE_GI_1_6)
+			sgi = HE_GI_RADIOTAP_1_6;
+		else if (sgi == HE_GI_3_2)
+			sgi = HE_GI_RADIOTAP_3_2;
+
 		rx_status->he_data5 |= (bw | (sgi << 0x4));
 		rx_status->he_data6 |= nss;
 	default:
@@ -937,9 +957,6 @@ pkt_capture_rx_data_cb(
 		/* need to update this to fill rx_status*/
 		htt_rx_mon_get_rx_status(pdev, rx_desc, &rx_status);
 		rx_status.chan_noise_floor = NORMALIZED_TO_NOISE_FLOOR;
-		rx_status.tx_status = status;
-		rx_status.tx_retry_cnt = tx_retry_cnt;
-		rx_status.add_rtap_ext = true;
 
 		/* clear IEEE80211_RADIOTAP_F_FCS flag*/
 		rx_status.rtap_flags &= ~(BIT(4));
@@ -1046,9 +1063,6 @@ pkt_capture_rx_data_cb(
 		/* need to update this to fill rx_status*/
 		pkt_capture_rx_mon_get_rx_status(vdev, psoc,
 						 rx_tlv_hdr, &rx_status);
-		rx_status.tx_status = status;
-		rx_status.tx_retry_cnt = tx_retry_cnt;
-		rx_status.add_rtap_ext = true;
 
 		/* clear IEEE80211_RADIOTAP_F_FCS flag*/
 		rx_status.rtap_flags &= ~(BIT(4));

+ 0 - 1
components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c

@@ -741,7 +741,6 @@ pkt_capture_mgmt_rx_data_cb(struct wlan_objmgr_psoc *psoc,
 
 	/* Convert rate from Mbps to 500 Kbps */
 	txrx_status.rate = txrx_status.rate * 2;
-	txrx_status.add_rtap_ext = true;
 
 	wh = (struct ieee80211_frame *)qdf_nbuf_data(nbuf);
 	wh->i_fc[1] &= ~IEEE80211_FC1_WEP;

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

@@ -148,6 +148,55 @@ QDF_STATUS pmo_core_vdev_get_ps_params(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * pmo_vdev_set_ps_opm_mode() - set OPM mode
+ * @vdev: objmgr vdev handle
+ * @opm_mode: OPM mode
+ *
+ * Return: QDF_STATUS
+ */
+static inline
+QDF_STATUS pmo_vdev_set_ps_opm_mode(struct wlan_objmgr_vdev *vdev,
+					 enum powersave_mode opm_mode)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	if (!vdev_ctx) {
+		pmo_err("vdev ctx is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->ps_params.opm_mode = opm_mode;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * pmo_vdev_get_ps_opm_mode() - get OPM mode
+ * @vdev: objmgr vdev handle
+ * @opm_mode: OPM mode
+ *
+ * Return: QDF_STATUS
+ */
+static inline
+QDF_STATUS pmo_vdev_get_ps_opm_mode(struct wlan_objmgr_vdev *vdev,
+					 enum powersave_mode *opm_mode)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	if (!vdev_ctx)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	*opm_mode = vdev_ctx->ps_params.opm_mode;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+	return QDF_STATUS_SUCCESS;
+}
+
 #ifdef WLAN_FEATURE_NAN
 /**
  * pmo_set_ndp_wow_bitmask() - set predefined NDP wow wakeup events

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

@@ -829,6 +829,26 @@ ucfg_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS ucfg_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
 				  struct pmo_ps_params *ps_params);
 
+/**
+ * ucfg_pmo_core_vdev_set_ps_opm_mode() - Set OPM mode
+ * @vdev: pointer to vdev object
+ * @opm_mode: OPM mode
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS ucfg_pmo_core_vdev_set_ps_opm_mode(struct wlan_objmgr_vdev *vdev,
+					      enum powersave_mode opm_mode);
+
+/**
+ * ucfg_pmo_core_vdev_get_ps_opm_mode() - Get OPM mode
+ * @vdev: pointer to vdev object
+ * @opm_mode: OPM mode
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS ucfg_pmo_core_vdev_get_ps_opm_mode(struct wlan_objmgr_vdev *vdev,
+					      enum powersave_mode *opm_mode);
+
 /**
  * ucfg_pmo_get_gtk_rsp(): API to send gtk response request to fwr
  * @vdev: objmgr vdev handle

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

@@ -607,6 +607,18 @@ QDF_STATUS ucfg_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
 	return pmo_core_vdev_get_ps_params(vdev, ps_params);
 }
 
+QDF_STATUS ucfg_pmo_core_vdev_set_ps_opm_mode(struct wlan_objmgr_vdev *vdev,
+					      enum powersave_mode opm_mode)
+{
+	return pmo_vdev_set_ps_opm_mode(vdev, opm_mode);
+}
+
+QDF_STATUS ucfg_pmo_core_vdev_get_ps_opm_mode(struct wlan_objmgr_vdev *vdev,
+					      enum powersave_mode *opm_mode)
+{
+	return pmo_vdev_get_ps_opm_mode(vdev, opm_mode);
+}
+
 bool
 ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc)
 {

+ 61 - 0
components/target_if/connection_mgr/src/target_if_cm_roam_offload.c

@@ -454,6 +454,56 @@ target_if_cm_roam_rssi_diff_6ghz(struct wlan_objmgr_vdev *vdev,
 	return status;
 }
 
+static QDF_STATUS
+target_if_cm_roam_scan_offload_rssi_thresh(
+				wmi_unified_t wmi_handle,
+				struct wlan_roam_offload_scan_rssi_params *req);
+
+/**
+ * target_if_cm_roam_scan_offload_rssi_params() - Set the RSSI parameters
+ * for roam offload scan
+ * @vdev: vdev object
+ * @roam_rssi_params: structure containing parameters for roam offload scan
+ * based on RSSI
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+target_if_cm_roam_scan_offload_rssi_params(
+		struct wlan_objmgr_vdev *vdev,
+		struct wlan_roam_offload_scan_rssi_params *roam_rssi_params)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	wmi_unified_t wmi_handle;
+
+	wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev);
+	if (!wmi_handle)
+		return status;
+
+	status = target_if_cm_roam_scan_offload_rssi_thresh(wmi_handle,
+							    roam_rssi_params);
+
+	return status;
+}
+
+static void
+target_if_check_hi_rssi_5ghz_support(
+		wmi_unified_t wmi_handle,
+		struct wlan_roam_offload_scan_rssi_params *roam_rssi_params)
+{
+	if ((roam_rssi_params->flags &
+	     ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G) &&
+	    wmi_service_enabled(wmi_handle,
+				wmi_service_5ghz_hi_rssi_roam_support)) {
+		target_if_debug("FW supports Hi RSSI roam in 5 GHz");
+		roam_rssi_params->flags |=
+			WMI_ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G;
+	} else {
+		roam_rssi_params->flags &=
+			~ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G;
+	}
+}
+
 static void
 target_if_cm_roam_register_lfr3_ops(struct wlan_cm_roam_tx_ops *tx_ops)
 {
@@ -467,6 +517,8 @@ target_if_cm_roam_register_lfr3_ops(struct wlan_cm_roam_tx_ops *tx_ops)
 				target_if_cm_exclude_rm_partial_scan_freq;
 	tx_ops->send_roam_full_scan_6ghz_on_disc =
 				target_if_cm_roam_full_scan_6ghz_on_disc;
+	tx_ops->send_roam_scan_offload_rssi_params =
+				target_if_cm_roam_scan_offload_rssi_params;
 	target_if_cm_roam_register_vendor_handoff_ops(tx_ops);
 	target_if_cm_roam_register_linkspeed_state(tx_ops);
 }
@@ -516,6 +568,12 @@ target_if_cm_roam_rssi_diff_6ghz(struct wlan_objmgr_vdev *vdev,
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
+
+static inline void
+target_if_check_hi_rssi_5ghz_support(
+		wmi_unified_t wmi_handle,
+		struct wlan_roam_offload_scan_rssi_params *roam_rssi_params)
+{}
 #endif
 
 /**
@@ -959,6 +1017,9 @@ target_if_cm_roam_scan_offload_rssi_thresh(
 		}
 	}
 
+	if (req->hi_rssi_scan_rssi_delta)
+		target_if_check_hi_rssi_5ghz_support(wmi_handle, req);
+
 	target_if_debug("RSO_CFG: vdev %d: db2dbm enabled:%d, good_rssi_threshold:%d, early_stop_thresholds en:%d, min:%d, max:%d, roam_scan_rssi_thresh:%d, roam_rssi_thresh_diff:%d",
 			req->vdev_id, db2dbm_enabled, req->good_rssi_threshold,
 			req->early_stop_scan_enable,

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

@@ -1026,6 +1026,11 @@ exit:
 #ifdef WLAN_FEATURE_TDLS_CONCURRENCIES
 bool tdls_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc)
 {
+	if (policy_mgr_is_mlo_in_mode_emlsr(psoc, NULL, NULL)) {
+		tdls_debug("eMLSR STA present. Don't allow TDLS");
+		return false;
+	}
+
 	if (!wlan_psoc_nif_fw_ext2_cap_get(psoc,
 					   WLAN_TDLS_CONCURRENCIES_SUPPORT)) {
 		tdls_debug("fw cap is not advertised");

+ 47 - 23
components/tdls/core/src/wlan_tdls_mgmt.c

@@ -33,6 +33,7 @@
 #include "wlan_policy_mgr_api.h"
 #include <wlan_reg_services_api.h>
 #include <wlan_mlo_mgr_sta.h>
+#include "wlan_mlo_link_force.h"
 
 static
 const char *const tdls_action_frames_type[] = { "TDLS Setup Request",
@@ -403,12 +404,13 @@ exit:
 
 void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag)
 {
-	uint8_t i, count = 0;
+	uint8_t i;
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_objmgr_vdev *mlo_vdev;
 	struct wlan_mlo_dev_context *mlo_dev_ctx;
-	uint8_t mlo_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS];
 	bool is_mlo_vdev;
+	struct ml_nlink_change_event data;
+	QDF_STATUS status;
 
 	if (!vdev)
 		return;
@@ -421,22 +423,32 @@ void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag)
 	if (!psoc)
 		return;
 
+	qdf_mem_zero(&data, sizeof(data));
+
 	mlo_dev_ctx = vdev->mlo_dev_ctx;
 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
 		mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i];
+		if (!mlo_vdev)
+			continue;
 
 		/* flag: true means no force all vdevs,
 		 * false means except the current one
 		 */
 		if (!flag && (mlo_vdev == vdev))
 			continue;
-		mlo_vdev_lst[count] = wlan_vdev_get_id(mlo_vdev);
-		count++;
+		data.evt.tdls.link_bitmap |=
+				1 << wlan_vdev_get_link_id(mlo_vdev);
+		data.evt.tdls.mlo_vdev_lst[data.evt.tdls.vdev_count] =
+				wlan_vdev_get_id(mlo_vdev);
+		data.evt.tdls.vdev_count++;
 	}
 
-	policy_mgr_mlo_sta_set_link(psoc, MLO_LINK_FORCE_REASON_TDLS,
-				    MLO_LINK_FORCE_MODE_NO_FORCE,
-				    count, mlo_vdev_lst);
+	data.evt.tdls.mode = MLO_LINK_FORCE_MODE_NO_FORCE;
+	data.evt.tdls.reason = MLO_LINK_FORCE_REASON_TDLS;
+	status = ml_nlink_conn_change_notify(psoc,
+					     wlan_vdev_get_id(vdev),
+					     ml_nlink_tdls_request_evt,
+					     &data);
 }
 #else
 struct wlan_objmgr_vdev *
@@ -879,12 +891,11 @@ tdls_send_mgmt_serialize_callback(struct wlan_serialization_command *cmd,
 #ifdef WLAN_FEATURE_11BE_MLO
 QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
 {
-	uint8_t mlo_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {-1};
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_objmgr_vdev *mlo_tdls_vdev;
-	uint8_t vdev_count = 0;
 	bool is_mlo_vdev;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct ml_nlink_change_event data;
 
 	is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(req->vdev);
 	if (!is_mlo_vdev)
@@ -902,24 +913,37 @@ QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
 		if (mlo_tdls_vdev)
 			return status;
 
-		mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev);
-		vdev_count = 1;
-
-		status = policy_mgr_mlo_sta_set_link(psoc,
-						     MLO_LINK_FORCE_REASON_TDLS,
-						     MLO_LINK_FORCE_MODE_ACTIVE,
-						     vdev_count, mlo_vdev_lst);
-		if (status == QDF_STATUS_SUCCESS)
+		qdf_mem_zero(&data, sizeof(data));
+		data.evt.tdls.link_bitmap =
+				1 << wlan_vdev_get_link_id(req->vdev);
+		data.evt.tdls.mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev);
+		data.evt.tdls.vdev_count = 1;
+		data.evt.tdls.mode = MLO_LINK_FORCE_MODE_ACTIVE;
+		data.evt.tdls.reason = MLO_LINK_FORCE_REASON_TDLS;
+		status =
+		ml_nlink_conn_change_notify(psoc,
+					    wlan_vdev_get_id(req->vdev),
+					    ml_nlink_tdls_request_evt,
+					    &data);
+		if (status == QDF_STATUS_SUCCESS ||
+		    status == QDF_STATUS_E_PENDING)
 			req->link_active = true;
 	} else if (req->tdls_mgmt.frame_type == TDLS_MAX_ACTION_CODE) {
-		mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev);
-		vdev_count = 1;
+		qdf_mem_zero(&data, sizeof(data));
+		data.evt.tdls.link_bitmap =
+				1 << wlan_vdev_get_link_id(req->vdev);
+		data.evt.tdls.mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev);
+		data.evt.tdls.vdev_count = 1;
+		data.evt.tdls.mode = MLO_LINK_FORCE_MODE_NO_FORCE;
+		data.evt.tdls.reason = MLO_LINK_FORCE_REASON_TDLS;
 		status =
-		    policy_mgr_mlo_sta_set_link(psoc,
-						MLO_LINK_FORCE_REASON_TDLS,
-						MLO_LINK_FORCE_MODE_NO_FORCE,
-						vdev_count, mlo_vdev_lst);
+		ml_nlink_conn_change_notify(psoc,
+					    wlan_vdev_get_id(req->vdev),
+					    ml_nlink_tdls_request_evt,
+					    &data);
 	}
+	if (status == QDF_STATUS_E_PENDING)
+		status = QDF_STATUS_SUCCESS;
 
 	return status;
 }

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

@@ -447,7 +447,7 @@ cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev,
 
 		channel.ch_freq = ml_link->channel.mhz;
 		channel.ch_cfreq1 = ml_link->channel.band_center_freq1;
-		channel.ch_cfreq1 = ml_link->channel.band_center_freq2;
+		channel.ch_cfreq2 = ml_link->channel.band_center_freq2;
 
 		/*
 		 * Update Link switch context for each vdev with roamed AP link
@@ -1115,8 +1115,7 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	mlme_cm_osif_connect_complete(vdev, connect_rsp);
 	mlme_cm_osif_roam_complete(vdev);
 
-	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
-	    roam_synch_data->auth_status == ROAM_AUTH_STATUS_CONNECTED)
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev))
 		mlo_roam_copy_reassoc_rsp(vdev, connect_rsp);
 	mlme_debug(CM_PREFIX_FMT, CM_PREFIX_REF(vdev_id, cm_id));
 	cm_remove_cmd(cm_ctx, &cm_id);

+ 161 - 16
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -50,7 +50,7 @@
 #include "wlan_mlme_api.h"
 #include "wlan_policy_mgr_api.h"
 #include "wlan_mlo_mgr_link_switch.h"
-
+#include "wlan_mlo_mgr_sta.h"
 
 #ifdef WLAN_FEATURE_SAE
 #define CM_IS_FW_FT_SAE_SUPPORTED(fw_akm_bitmap) \
@@ -1166,6 +1166,7 @@ cm_roam_scan_offload_rssi_thresh(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	struct wlan_mlme_psoc_ext_obj *mlme_obj;
 	struct wlan_mlme_lfr_cfg *lfr_cfg;
 	struct rso_config_params *rso_config;
+	struct wlan_objmgr_vdev *vdev;
 
 	mlme_obj = mlme_get_psoc_ext_obj(psoc);
 	if (!mlme_obj)
@@ -1200,6 +1201,40 @@ cm_roam_scan_offload_rssi_thresh(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	else
 		params->hi_rssi_scan_rssi_delta =
 			rso_cfg->cfg_param.hi_rssi_scan_rssi_delta;
+	/*
+	 * When the STA operating band is 2.4/5 GHz and if the high RSSI delta
+	 * is configured through vendor command then the priority should be
+	 * given to it and the high RSSI delta value will be overridden with it.
+	 */
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("Cannot set high RSSI offset as vdev object is NULL for vdev %d",
+			 vdev_id);
+	} else {
+		qdf_freq_t op_freq;
+
+		op_freq = wlan_get_operation_chan_freq(vdev);
+		if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(op_freq)) {
+			uint8_t roam_high_rssi_delta;
+
+			roam_high_rssi_delta =
+				wlan_cm_get_roam_scan_high_rssi_offset(psoc);
+			if (roam_high_rssi_delta)
+				params->hi_rssi_scan_rssi_delta =
+							roam_high_rssi_delta;
+			/*
+			 * Firmware will use this flag to enable 5 to 6 GHz
+			 * high RSSI roam
+			 */
+			if (roam_high_rssi_delta &&
+			    WLAN_REG_IS_5GHZ_CH_FREQ(op_freq))
+				params->flags |=
+					ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G;
+		}
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+	}
+
 	params->hi_rssi_scan_rssi_ub =
 		rso_cfg->cfg_param.hi_rssi_scan_rssi_ub;
 	params->raise_rssi_thresh_5g = lfr_cfg->rssi_boost_threshold_5g;
@@ -3484,9 +3519,12 @@ cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	if (!pdev)
 		goto rel_vdev_ref;
 
+	mlme_debug("vdev:%d process rso stop for reason: %d", vdev_id, reason);
+
 	stop_req->btm_config.vdev_id = vdev_id;
-	MLME_SET_BIT(stop_req->btm_config.btm_offload_config,
-		     BTM_OFFLOAD_CONFIG_BIT_0);
+	if (reason == REASON_SUPPLICANT_DISABLED_ROAMING)
+		MLME_SET_BIT(stop_req->btm_config.btm_offload_config,
+			     BTM_OFFLOAD_CONFIG_BIT_0);
 	stop_req->disconnect_params.vdev_id = vdev_id;
 	stop_req->idle_params.vdev_id = vdev_id;
 	stop_req->roam_triggers.vdev_id = vdev_id;
@@ -3721,6 +3759,59 @@ cm_akm_roam_allowed(struct wlan_objmgr_psoc *psoc,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+QDF_STATUS cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc,
+					     uint8_t vdev_id,
+					     uint8_t param_value)
+{
+	struct rso_config *rso_cfg;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_roam_offload_scan_rssi_params *roam_rssi_params;
+	QDF_STATUS status = QDF_STATUS_E_INVAL;
+	qdf_freq_t op_freq;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev object is NULL for vdev %d", vdev_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	op_freq = wlan_get_operation_chan_freq(vdev);
+	if (WLAN_REG_IS_6GHZ_CHAN_FREQ(op_freq)) {
+		mlme_err("vdev:%d High RSSI offset can't be set in 6 GHz band",
+			 vdev_id);
+		goto rel_vdev_ref;
+	}
+
+	rso_cfg = wlan_cm_get_rso_config(vdev);
+	if (!rso_cfg)
+		goto rel_vdev_ref;
+
+	roam_rssi_params = qdf_mem_malloc(sizeof(*roam_rssi_params));
+	if (!roam_rssi_params)
+		goto rel_vdev_ref;
+
+	wlan_cm_set_roam_scan_high_rssi_offset(psoc, param_value);
+	qdf_mem_zero(roam_rssi_params, sizeof(*roam_rssi_params));
+	cm_roam_scan_offload_rssi_thresh(psoc, vdev_id,
+					 roam_rssi_params, rso_cfg);
+	mlme_debug("vdev:%d Configured high RSSI delta=%d, 5 GHZ roam flag=%d",
+		   vdev_id, roam_rssi_params->hi_rssi_scan_rssi_delta,
+		   (roam_rssi_params->flags &
+		    ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G));
+
+	status = wlan_cm_tgt_send_roam_scan_offload_rssi_params(
+							vdev, roam_rssi_params);
+	if (QDF_IS_STATUS_ERROR(status))
+		mlme_err("fail to set roam scan high RSSI offset");
+
+	qdf_mem_free(roam_rssi_params);
+rel_vdev_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+
+	return status;
+}
 #endif
 
 #ifdef WLAN_ADAPTIVE_11R
@@ -6128,7 +6219,6 @@ void cm_roam_scan_info_event(struct wlan_objmgr_psoc *psoc,
 	uint32_t *chan_freq = NULL;
 	uint8_t count = 0, status, num_chan;
 	uint32_t band_capability = 0, band_mask = 0;
-	bool is_full_scan;
 	struct wlan_diag_roam_scan_done *wlan_diag_event = NULL;
 
 	wlan_diag_event = qdf_mem_malloc(sizeof(*wlan_diag_event));
@@ -6157,9 +6247,7 @@ void cm_roam_scan_info_event(struct wlan_objmgr_psoc *psoc,
 	if (scan->num_ap)
 		wlan_diag_event->cand_ap_count = scan->num_ap - 1;
 
-	is_full_scan = scan->type && scan->present;
-
-	if (is_full_scan) {
+	if (scan->type == ROAM_STATS_SCAN_TYPE_FULL && scan->present) {
 		status = mlme_get_fw_scan_channels(psoc, chan_freq, &num_chan);
 		if (QDF_IS_STATUS_ERROR(status))
 			goto out;
@@ -6312,6 +6400,58 @@ void cm_roam_candidate_info_event(struct wmi_roam_candidate_info *ap,
 #define WLAN_ROAM_SCAN_TYPE_PARTIAL_SCAN 0
 #define WLAN_ROAM_SCAN_TYPE_FULL_SCAN 1
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static void
+cm_populate_roam_success_mlo_param(struct wlan_objmgr_psoc *psoc,
+				   struct wlan_diag_roam_result *event,
+				   uint8_t vdev_id)
+{
+	struct wlan_objmgr_vdev *vdev = NULL;
+	struct wlan_objmgr_vdev *assoc_vdev = NULL;
+	struct qdf_mac_addr bss_peer;
+	QDF_STATUS status;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev: %d not found", vdev_id);
+		return;
+	}
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
+		goto out;
+
+	event->is_mlo = true;
+
+	assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
+	if (!assoc_vdev) {
+		mlme_err("assoc vdev not found");
+		goto out;
+	}
+
+	status = wlan_vdev_get_bss_peer_mac(assoc_vdev,
+					    &bss_peer);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("vdev: %d bss peer not found",
+			 wlan_vdev_get_id(assoc_vdev));
+		goto out;
+	}
+
+	qdf_mem_copy(event->diag_cmn.bssid,
+		     bss_peer.bytes, QDF_MAC_ADDR_SIZE);
+
+out:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+}
+#else
+static void
+cm_populate_roam_success_mlo_param(struct wlan_objmgr_psoc *psoc,
+				   struct wlan_diag_roam_result *event,
+				   uint8_t vdev_id)
+{
+}
+#endif
+
 void cm_roam_result_info_event(struct wlan_objmgr_psoc *psoc,
 			       struct wmi_roam_trigger_info *trigger,
 			       struct wmi_roam_result *res,
@@ -6383,6 +6523,10 @@ void cm_roam_result_info_event(struct wlan_objmgr_psoc *psoc,
 			     QDF_MAC_ADDR_SIZE);
 	}
 
+	if (!wlan_diag_event.is_roam_successful)
+		cm_populate_roam_success_mlo_param(psoc, &wlan_diag_event,
+						   vdev_id);
+
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_ROAM_RESULT);
 	qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event));
 
@@ -6400,6 +6544,7 @@ void cm_roam_result_info_event(struct wlan_objmgr_psoc *psoc,
 				       trigger->trigger_reason,
 				       wlan_diag_event.is_roam_successful,
 				       is_full_scan, res->fail_reason);
+
 }
 
 #endif
@@ -6897,7 +7042,8 @@ wlan_convert_bitmap_to_band(uint8_t bitmap)
 	enum wlan_diag_wifi_band band = WLAN_INVALID_BAND;
 
 	for (i = WLAN_24GHZ_BAND; i <= WLAN_6GHZ_BAND; i++) {
-		if (qdf_test_bit(i, (unsigned long *)&bitmap)) {
+		/* 2.4 GHz band will be populated at 0th bit in the bitmap*/
+		if (qdf_test_bit((i - 1), (unsigned long *)&bitmap)) {
 			band = i;
 			break;
 		}
@@ -6963,21 +7109,20 @@ cm_roam_mgmt_frame_event(struct wlan_objmgr_vdev *vdev,
 
 	} else {
 		wlan_diag_event.subtype =
-		(uint8_t)cm_roam_get_tag(frame_data->subtype,
-					 !frame_data->is_rsp);
+			(uint8_t)cm_roam_get_tag(frame_data->subtype,
+						 !frame_data->is_rsp);
 		diag_event = EVENT_WLAN_MGMT;
 
-		wlan_diag_event.supported_links = frame_data->band;
-
-		status =
-			wlan_populate_mlo_mgmt_event_param(vdev,
-							   &wlan_diag_event,
-							   wlan_diag_event.subtype);
+		status = wlan_populate_roam_mld_log_param(vdev,
+							  &wlan_diag_event,
+							  wlan_diag_event.subtype);
 		if (QDF_IS_STATUS_ERROR(status)) {
 			mlme_err("vdev: %d Unable to populate MLO parameter",
 				 wlan_vdev_get_id(vdev));
 			return status;
 		}
+
+		wlan_diag_event.supported_links = frame_data->band;
 	}
 
 	if (wlan_diag_event.subtype > WLAN_CONN_DIAG_REASSOC_RESP_EVENT &&

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

@@ -476,6 +476,21 @@ cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc,
  */
 QDF_STATUS cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc,
 					  uint8_t vdev_id, uint8_t param_value);
+
+/**
+ * cm_set_roam_scan_high_rssi_offset() - Set the delta change in high RSSI at
+ * which roam scan is triggered in 2.4/5 GHz.
+ * @psoc: PSOC pointer
+ * @vdev_id: vdev id
+ * @param_value: Set the High RSSI delta for roam scan trigger
+ * * 1-16 - Set an offset value in this range
+ * * 0    - Disable
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc,
+				  uint8_t vdev_id, uint8_t param_value);
 #else
 static inline QDF_STATUS
 cm_roam_send_rt_stats_config(struct wlan_objmgr_psoc *psoc,

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

@@ -1171,6 +1171,9 @@ cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev,
 	uint8_t mlo_support_link_num;
 	struct wlan_objmgr_psoc *psoc;
 
+	/* Initialize number of partner links as zero */
+	partner_info->num_partner_links = 0;
+
 	/* If ML IE is not present then return failure*/
 	if (!scan_entry->ie_list.multi_link_bv)
 		return QDF_STATUS_E_FAILURE;

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

@@ -1276,6 +1276,29 @@ wlan_cm_roam_set_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc,
  */
 uint8_t wlan_cm_roam_get_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * wlan_cm_set_roam_scan_high_rssi_offset() - Set the delta change in high RSSI
+ * at which roam scan is triggered in 2.4/5 GHz.
+ * @psoc: PSOC pointer
+ * @roam_high_rssi_delta: Set the High RSSI delta for roam scan trigger
+ * * 1-16 - Set an offset value in this range
+ * * 0    - Disable
+ *
+ * Return: none
+ */
+void
+wlan_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc,
+				       uint8_t roam_high_rssi_delta);
+
+/**
+ * wlan_cm_get_roam_scan_high_rssi_offset() - Get the delta change in high RSSI
+ * at which roam scan is triggered in 2.4/5 GHz.
+ * @psoc: PSOC pointer
+ *
+ * Return: High RSSI delta for roam scan trigger
+ */
+uint8_t wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc);
+
 #ifdef WLAN_FEATURE_ROAM_INFO_STATS
 /**
  * mlme_cm_alloc_roam_stats_info() - alloc roam stats info buffer
@@ -1625,6 +1648,12 @@ wlan_cm_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline uint8_t
+wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc)
+{
+	return 0;
+}
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD)

+ 28 - 4
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -1038,24 +1038,28 @@ enum roam_scan_dwell_type {
 /**
  * enum eroam_frame_subtype - Enhanced roam frame subtypes.
  *
- * @WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH: Pre-authentication frame
- * @WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC: Reassociation frame
+ * @WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP: Authentication resp frame
+ * @WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP: Reassociation resp frame
  * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1: EAPOL-Key M1 frame
  * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2: EAPOL-Key M2 frame
  * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3: EAPOL-Key M3 frame
  * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4: EAPOL-Key M4 frame
  * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1: EAPOL-Key GTK M1 frame
  * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2: EAPOL-Key GTK M2 frame
+ * @WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ: Authentication req frame
+ * @WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ: Reassociation req frame
  */
 enum eroam_frame_subtype {
-	WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH = 1,
-	WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC = 2,
+	WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP = 1,
+	WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP = 2,
 	WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1 = 3,
 	WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2 = 4,
 	WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3 = 5,
 	WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4 = 6,
 	WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1 = 7,
 	WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2 = 8,
+	WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ = 9,
+	WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ = 10,
 };
 
 /**
@@ -1759,6 +1763,19 @@ struct wlan_roam_scan_offload_params {
 #endif
 };
 
+/**
+ * enum wlan_roam_offload_scan_rssi_flags - Flags for roam scan RSSI threshold
+ * params, this enums will be used in flags param of the structure
+ * wlan_roam_offload_scan_rssi_params
+ * @ROAM_SCAN_RSSI_THRESHOLD_INVALID_FLAG: invalid flag
+ * @ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G: enable high RSSI roam
+ * trigger support to roam from 5 GHz to 6 GHz band
+ */
+enum wlan_roam_offload_scan_rssi_flags {
+	ROAM_SCAN_RSSI_THRESHOLD_INVALID_FLAG,
+	ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G = BIT(0),
+};
+
 /**
  * struct wlan_roam_offload_scan_rssi_params - structure containing
  *              parameters for roam offload scan based on RSSI
@@ -1796,6 +1813,7 @@ struct wlan_roam_scan_offload_params {
  *                                  roam
  * @roam_data_rssi_threshold: Bad data RSSI threshold to roam
  * @rx_data_inactivity_time: Rx duration to check data RSSI
+ * @flags: Flags for roam scan RSSI threshold params
  */
 struct wlan_roam_offload_scan_rssi_params {
 	int8_t rssi_thresh;
@@ -1827,6 +1845,7 @@ struct wlan_roam_offload_scan_rssi_params {
 	uint32_t roam_data_rssi_threshold_triggers;
 	int32_t roam_data_rssi_threshold;
 	uint32_t rx_data_inactivity_time;
+	uint32_t flags;
 };
 
 /**
@@ -2581,6 +2600,8 @@ struct roam_pmkid_req_event {
  * @send_roam_linkspeed_state: Send roam link speed good/poor state to FW
  * @send_roam_vendor_handoff_config: send vendor handoff config command to FW
  * @send_roam_mlo_config: send MLO config to FW
+ * @send_roam_scan_offload_rssi_params: Set the RSSI parameters for roam
+ * offload scan
  */
 struct wlan_cm_roam_tx_ops {
 	QDF_STATUS (*send_vdev_set_pcl_cmd)(struct wlan_objmgr_vdev *vdev,
@@ -2622,6 +2643,9 @@ struct wlan_cm_roam_tx_ops {
 						uint8_t value);
 	QDF_STATUS (*send_roam_mcc_disallow)(struct wlan_objmgr_vdev *vdev,
 					     uint8_t vdev_id, uint8_t value);
+	QDF_STATUS (*send_roam_scan_offload_rssi_params)(
+		struct wlan_objmgr_vdev *vdev,
+		struct wlan_roam_offload_scan_rssi_params *roam_rssi_params);
 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
 	QDF_STATUS (*send_roam_linkspeed_state)(struct wlan_objmgr_vdev *vdev,
 						uint8_t vdev_id, bool value);

+ 25 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h

@@ -405,6 +405,24 @@ ucfg_cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_pdev *pdev,
 QDF_STATUS ucfg_cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_pdev *pdev,
 					       uint8_t vdev_id,
 					       uint8_t param_value);
+
+/**
+ * ucfg_cm_set_roam_scan_high_rssi_offset() - Set the delta change in high RSSI
+ * at which roam scan is triggered in 2.4/5 GHz.
+ * @psoc: Pointer to psoc object
+ * @vdev_id: vdev id
+ * @param_value: Set the High RSSI delta for roam scan trigger
+ * 0    - Disable
+ * 1-16 - Set an offset value in this range
+ *
+ * Return: QDF_STATUS
+ */
+static inline QDF_STATUS
+ucfg_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id, uint8_t param_value)
+{
+	return cm_set_roam_scan_high_rssi_offset(psoc, vdev_id, param_value);
+}
 #else
 static inline void
 ucfg_cm_reset_key(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) {}
@@ -436,6 +454,13 @@ ucfg_cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_pdev *pdev,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline QDF_STATUS
+ucfg_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id, uint8_t param_value)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
 #ifdef WLAN_VENDOR_HANDOFF_CONTROL

+ 14 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_tgt_if_tx_api.h

@@ -116,6 +116,20 @@ QDF_STATUS wlan_cm_tgt_send_roam_full_scan_6ghz_on_disc(
 					uint8_t vdev_id,
 					uint8_t roam_full_scan_6ghz_on_disc);
 
+/**
+ * wlan_cm_tgt_send_roam_scan_offload_rssi_params() - Set the RSSI parameters
+ * for roam offload scan
+ * @vdev: Pointer to vdev object
+ * @roam_rssi_params: structure containing parameters for roam offload scan
+ * based on RSSI
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_cm_tgt_send_roam_scan_offload_rssi_params(
+		struct wlan_objmgr_vdev *vdev,
+		struct wlan_roam_offload_scan_rssi_params *roam_rssi_params);
+
 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
 /**
  * wlan_cm_tgt_send_roam_linkspeed_state() - Send roam link speed state

+ 79 - 50
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -3438,7 +3438,7 @@ cm_roam_print_frame_info(struct wlan_objmgr_psoc *psoc,
 {
 	struct roam_frame_info *frame_info;
 	char time[TIME_STRING_LEN];
-	uint8_t i, vdev_id;
+	uint8_t i, vdev_id, cached_vdev_id;
 
 	if (!frame_data->num_frame)
 		return;
@@ -3446,27 +3446,35 @@ cm_roam_print_frame_info(struct wlan_objmgr_psoc *psoc,
 	vdev_id = wlan_vdev_get_id(vdev);
 
 	for (i = 0; i < frame_data->num_frame; i++) {
+		cached_vdev_id = vdev_id;
 		frame_info = &frame_data->frame_info[i];
+		/*
+		 * For SAE auth frame, since host sends the authentication
+		 * frames, its cached in the TX/RX path and the cached
+		 * frames are printed from here.
+		 */
 		if (frame_info->auth_algo == WLAN_SAE_AUTH_ALGO &&
-		    wlan_is_log_record_present_for_bssid(psoc,
-							 &frame_info->bssid,
-							 vdev_id)) {
+		    wlan_is_sae_auth_log_present_for_bssid(psoc,
+							   &frame_info->bssid,
+							   &cached_vdev_id)) {
 			wlan_print_cached_sae_auth_logs(psoc,
 							&frame_info->bssid,
-							vdev_id);
+							cached_vdev_id);
 			continue;
 		}
 
 		qdf_mem_zero(time, TIME_STRING_LEN);
 		mlme_get_converted_timestamp(frame_info->timestamp, time);
 
+		/* Log the auth & reassoc frames here to driver log */
 		if (frame_info->type != ROAM_FRAME_INFO_FRAME_TYPE_EXT)
-			mlme_nofl_info("%s [%s%s] VDEV[%d] status:%d seq_num:%d",
+			mlme_nofl_info("%s [%s%s] VDEV[%d] bssid: " QDF_MAC_ADDR_FMT " status:%d seq_num:%d",
 				       time,
 				       cm_get_frame_subtype_str(frame_info->subtype),
 				       frame_info->subtype ==  MGMT_SUBTYPE_AUTH ?
 				       (frame_info->is_rsp ? " RX" : " TX") : "",
 				       vdev_id,
+				       QDF_MAC_ADDR_REF(frame_info->bssid.bytes),
 				       frame_info->status_code,
 				       frame_info->seq_num);
 
@@ -4000,18 +4008,24 @@ wlan_cm_update_roam_scan_info(struct wlan_objmgr_vdev *vdev,
 
 /**
  * wlan_cm_roam_frame_subtype() - Convert roam host enum
+ * @frame: Roam frame info
  * @frame_type: roam frame type
  *
  * Return: Roam frame type defined in host driver
  */
 static enum eroam_frame_subtype
-wlan_cm_roam_frame_subtype(uint8_t frame_type)
+wlan_cm_roam_frame_subtype(struct roam_frame_info *frame, uint8_t frame_type)
 {
 	switch (frame_type) {
 	case MGMT_SUBTYPE_AUTH:
-		return WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH;
+		if (frame->is_rsp)
+			return WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP;
+		else
+			return WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
+	case MGMT_SUBTYPE_REASSOC_REQ:
+		return WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ;
 	case MGMT_SUBTYPE_REASSOC_RESP:
-		return WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC;
+		return WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP;
 	case ROAM_FRAME_SUBTYPE_M1:
 		return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1;
 	case ROAM_FRAME_SUBTYPE_M2:
@@ -4025,33 +4039,23 @@ wlan_cm_roam_frame_subtype(uint8_t frame_type)
 	case ROAM_FRAME_SUBTYPE_GTK_M2:
 		return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2;
 	default:
-		return WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH;
+		return WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
 	}
 }
 
-static uint8_t
-wlan_cm_get_index_from_frame_type(struct roam_frame_info *frame)
-{
-	uint8_t index;
-
-	if (frame->subtype == MGMT_SUBTYPE_AUTH && frame->is_rsp) {
-		index = WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH - 1;
-	} else if (frame->subtype == MGMT_SUBTYPE_REASSOC_RESP) {
-		index = WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC - 1;
-	} else if (frame->subtype == ROAM_FRAME_SUBTYPE_M1) {
-		index = WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1 - 1;
-	} else if (frame->subtype == ROAM_FRAME_SUBTYPE_M2) {
-		index = WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2 - 1;
-	} else if (frame->subtype == ROAM_FRAME_SUBTYPE_M3) {
-		index = WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3 - 1;
-	} else if (frame->subtype == ROAM_FRAME_SUBTYPE_M4) {
-		index = WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4 - 1;
-	} else {
-		mlme_err("Invalid subtype: %d", frame->subtype);
-		index =  ROAM_FRAME_NUM;
-	}
-
-	return index;
+static bool
+wlan_cm_get_valid_frame_type(struct roam_frame_info *frame)
+{
+	if (frame->subtype == MGMT_SUBTYPE_AUTH ||
+	    frame->subtype == MGMT_SUBTYPE_REASSOC_REQ ||
+	    frame->subtype == MGMT_SUBTYPE_REASSOC_RESP ||
+	    frame->subtype == ROAM_FRAME_SUBTYPE_M1 ||
+	    frame->subtype == ROAM_FRAME_SUBTYPE_M2 ||
+	    frame->subtype == ROAM_FRAME_SUBTYPE_M3 ||
+	    frame->subtype == ROAM_FRAME_SUBTYPE_M4)
+		return true;
+	else
+		return false;
 }
 
 /**
@@ -4070,35 +4074,40 @@ wlan_cm_update_roam_frame_info(struct mlme_legacy_priv *mlme_priv,
 			       struct roam_frame_stats *frame_data)
 {
 	struct enhance_roam_info *info;
-	uint32_t i, j, index;
+	uint32_t index, i, j = 0;
 	uint8_t subtype;
 
 	index = mlme_priv->roam_write_index;
 	info = &mlme_priv->roam_info[index];
 
 	for (i = 0; i < frame_data->num_frame; i++) {
-		j = wlan_cm_get_index_from_frame_type(&frame_data->frame_info[i]);
-
-		if (j == ROAM_FRAME_NUM)
+		if (!wlan_cm_get_valid_frame_type(&frame_data->frame_info[i]))
 			continue;
-
+		j++;
+		if (j >= WLAN_ROAM_MAX_FRAME_INFO)
+			break;
 		/*
-		 * fill frame info into roam buffer from zero
-		 * only need preauth/reassoc/EAPOL-M1/M2/M3/M4
-		 * types of frame cache in driver.
+		 * fill frame preauth req/rsp, reassoc req/rsp
+		 * and EAPOL-M1/M2/M3/M4 into roam buffer
 		 */
 		subtype = frame_data->frame_info[i].subtype;
 		info->timestamp[j].frame_type =
-			wlan_cm_roam_frame_subtype(subtype);
+			wlan_cm_roam_frame_subtype(&frame_data->frame_info[i],
+						   subtype);
 		info->timestamp[j].timestamp =
 			frame_data->frame_info[i].timestamp;
 		info->timestamp[j].status =
 			frame_data->frame_info[i].status_code;
 
-		mlme_debug("frame:subtype %x time %llu status:%u, index:%u",
-			   info->timestamp[j].frame_type,
+		qdf_mem_copy(info->timestamp[j].bssid.bytes,
+			     frame_data->frame_info[i].bssid.bytes,
+			     QDF_MAC_ADDR_SIZE);
+
+		mlme_debug("frame:idx:%u subtype:%x time:%llu status:%u AP BSSID" QDF_MAC_ADDR_FMT,
+			   j, info->timestamp[j].frame_type,
 			   info->timestamp[j].timestamp,
-			   info->timestamp[j].status, j);
+			   info->timestamp[j].status,
+			   QDF_MAC_ADDR_REF(info->timestamp[j].bssid.bytes));
 	}
 }
 
@@ -4156,11 +4165,6 @@ wlan_cm_update_roam_bssid(struct mlme_legacy_priv *mlme_priv,
 			qdf_mem_copy(info->scan.original_bssid.bytes,
 				     ap->bssid.bytes,
 				     QDF_MAC_ADDR_SIZE);
-		else if (ap->type == WLAN_ROAM_SCAN_CANDIDATE_AP &&
-			 qdf_is_macaddr_zero(&info->scan.candidate_bssid))
-			qdf_mem_copy(info->scan.candidate_bssid.bytes,
-				     ap->bssid.bytes,
-				     QDF_MAC_ADDR_SIZE);
 		else if (ap->type == WLAN_ROAM_SCAN_ROAMED_AP)
 			qdf_mem_copy(info->scan.roamed_bssid.bytes,
 				     ap->bssid.bytes,
@@ -4701,6 +4705,31 @@ uint8_t wlan_cm_roam_get_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc)
 	return mlme_obj->cfg.lfr.roam_full_scan_6ghz_on_disc;
 }
 
+void
+wlan_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc,
+				       uint8_t roam_high_rssi_delta)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return;
+
+	mlme_obj->cfg.lfr.roam_high_rssi_delta = roam_high_rssi_delta;
+}
+
+uint8_t
+wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return 0;
+
+	return mlme_obj->cfg.lfr.roam_high_rssi_delta;
+}
+
 #else
 QDF_STATUS
 cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,

+ 29 - 1
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -336,6 +336,34 @@ QDF_STATUS wlan_cm_tgt_send_roam_linkspeed_state(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 #endif
+
+QDF_STATUS
+wlan_cm_tgt_send_roam_scan_offload_rssi_params(
+		struct wlan_objmgr_vdev *vdev,
+		struct wlan_roam_offload_scan_rssi_params *roam_rssi_params)
+{
+	QDF_STATUS status;
+	uint8_t vdev_id;
+	struct wlan_cm_roam_tx_ops *roam_tx_ops;
+
+	vdev_id = wlan_vdev_get_id(vdev);
+
+	roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev);
+	if (!roam_tx_ops || !roam_tx_ops->send_roam_scan_offload_rssi_params) {
+		mlme_err("vdev %d send_roam_scan_offload_rssi_params is NULL",
+			 vdev_id);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = roam_tx_ops->send_roam_scan_offload_rssi_params(
+						vdev, roam_rssi_params);
+	if (QDF_IS_STATUS_ERROR(status))
+		mlme_debug("vdev %d fail to send roam scan offload RSSI params",
+			   vdev_id);
+
+	return status;
+}
 #endif
 
 #ifdef WLAN_VENDOR_HANDOFF_CONTROL

+ 22 - 0
components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h

@@ -37,6 +37,7 @@
  * @ml_nlink_ap_started_evt: SAP/GO bss started
  * @ml_nlink_ap_stopped_evt: SAP/GO bss stopped
  * @ml_nlink_connection_updated_evt: connection home channel changed
+ * @ml_nlink_tdls_request_evt: tdls request link enable/disable
  */
 enum ml_nlink_change_event_type {
 	ml_nlink_link_switch_start_evt,
@@ -50,12 +51,14 @@ enum ml_nlink_change_event_type {
 	ml_nlink_ap_started_evt,
 	ml_nlink_ap_stopped_evt,
 	ml_nlink_connection_updated_evt,
+	ml_nlink_tdls_request_evt,
 };
 
 /**
  * struct ml_nlink_change_event - connection change event data struct
  * @evt: event parameters
  * @link_switch: link switch start parameters
+ * @tdls: tdls parameters
  */
 struct ml_nlink_change_event {
 	union {
@@ -65,6 +68,13 @@ struct ml_nlink_change_event {
 			uint32_t new_primary_freq;
 			enum wlan_mlo_link_switch_reason reason;
 		} link_switch;
+		struct {
+			uint32_t link_bitmap;
+			uint8_t vdev_count;
+			uint8_t mlo_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS];
+			enum mlo_link_force_mode mode;
+			enum mlo_link_force_reason reason;
+		} tdls;
 	} evt;
 };
 
@@ -108,6 +118,7 @@ static inline const char *link_evt_to_string(uint32_t evt)
 	CASE_RETURN_STRING(ml_nlink_ap_started_evt);
 	CASE_RETURN_STRING(ml_nlink_ap_stopped_evt);
 	CASE_RETURN_STRING(ml_nlink_connection_updated_evt);
+	CASE_RETURN_STRING(ml_nlink_tdls_request_evt);
 	default:
 		return "Unknown";
 	}
@@ -335,6 +346,17 @@ ml_nlink_clr_force_state(struct wlan_objmgr_psoc *psoc,
  * Return: true if supported
  */
 bool ml_is_nlink_service_supported(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ml_nlink_get_standby_link_bitmap() - Get standby link info
+ * @psoc: psoc
+ * @vdev: vdev object
+ *
+ * Return: standby link bitmap
+ */
+uint32_t
+ml_nlink_get_standby_link_bitmap(struct wlan_objmgr_psoc *psoc,
+				 struct wlan_objmgr_vdev *vdev);
 #else
 static inline QDF_STATUS
 ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,

+ 79 - 1
components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c

@@ -524,7 +524,7 @@ ml_nlink_get_standby_link_info(struct wlan_objmgr_psoc *psoc,
 	}
 }
 
-static uint32_t
+uint32_t
 ml_nlink_get_standby_link_bitmap(struct wlan_objmgr_psoc *psoc,
 				 struct wlan_objmgr_vdev *vdev)
 {
@@ -1976,6 +1976,80 @@ ml_nlink_state_change_handler(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
+static QDF_STATUS
+ml_nlink_tdls_event_handler(struct wlan_objmgr_psoc *psoc,
+			    struct wlan_objmgr_vdev *vdev,
+			    enum ml_nlink_change_event_type evt,
+			    struct ml_nlink_change_event *data)
+{
+	struct ml_link_force_state curr_force_state = {0};
+	QDF_STATUS status;
+
+	ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state);
+
+	switch (data->evt.tdls.mode) {
+	case MLO_LINK_FORCE_MODE_ACTIVE:
+		if ((data->evt.tdls.link_bitmap &
+		    curr_force_state.force_active_bitmap) ==
+		    data->evt.tdls.link_bitmap) {
+			mlo_debug("link_bitmap 0x%x already active, 0x%x",
+				  data->evt.tdls.link_bitmap,
+				  curr_force_state.force_active_bitmap);
+			return QDF_STATUS_SUCCESS;
+		}
+		if (data->evt.tdls.link_bitmap &
+		    (curr_force_state.force_inactive_bitmap |
+		     curr_force_state.curr_dynamic_inactive_bitmap)) {
+			mlo_debug("link_bitmap 0x%x can't be active due to concurrency, 0x%x 0x%x",
+				  data->evt.tdls.link_bitmap,
+				  curr_force_state.force_inactive_bitmap,
+				  curr_force_state.
+				  curr_dynamic_inactive_bitmap);
+			return QDF_STATUS_E_INVAL;
+		}
+		break;
+	case MLO_LINK_FORCE_MODE_NO_FORCE:
+		if (data->evt.tdls.link_bitmap &
+		    curr_force_state.force_inactive_bitmap) {
+			mlo_debug("link_bitmap 0x%x can't be no_force due to concurrency, 0x%x",
+				  data->evt.tdls.link_bitmap,
+				  curr_force_state.force_inactive_bitmap);
+			return QDF_STATUS_E_INVAL;
+		}
+		if (!(data->evt.tdls.link_bitmap &
+			curr_force_state.force_active_bitmap)) {
+			mlo_debug("link_bitmap 0x%x already no force, 0x%x",
+				  data->evt.tdls.link_bitmap,
+				  curr_force_state.force_active_bitmap);
+			return QDF_STATUS_SUCCESS;
+		}
+		break;
+	default:
+		mlo_err("unhandled for tdls force mode %d",
+			data->evt.tdls.mode);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (ml_is_nlink_service_supported(psoc))
+		status = policy_mgr_mlo_sta_set_nlink(
+				psoc, wlan_vdev_get_id(vdev),
+				data->evt.tdls.reason,
+				data->evt.tdls.mode,
+				0,
+				data->evt.tdls.link_bitmap,
+				0,
+				0);
+	else
+		status =
+		policy_mgr_mlo_sta_set_link(psoc,
+					    data->evt.tdls.reason,
+					    data->evt.tdls.mode,
+					    data->evt.tdls.vdev_count,
+					    data->evt.tdls.mlo_vdev_lst);
+
+	return status;
+}
+
 static QDF_STATUS
 ml_nlink_swtich_dynamic_inactive_link(struct wlan_objmgr_psoc *psoc,
 				      struct wlan_objmgr_vdev *vdev)
@@ -2145,6 +2219,10 @@ ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,
 			psoc, vdev, MLO_LINK_FORCE_REASON_CONNECT,
 			evt, data);
 		break;
+	case ml_nlink_tdls_request_evt:
+		status = ml_nlink_tdls_event_handler(
+			psoc, vdev, evt, data);
+		break;
 	default:
 		break;
 	}

+ 50 - 40
components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c

@@ -987,57 +987,67 @@ mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
 	if (!sta_ctx)
 		return QDF_STATUS_E_NULL_VALUE;
 
-	if (sta_ctx) {
-		wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
-
-		sta_ctx->copied_reassoc_rsp = qdf_mem_malloc(
-				sizeof(struct wlan_cm_connect_resp));
-		if (!sta_ctx->copied_reassoc_rsp)
-			return QDF_STATUS_E_NOMEM;
+	wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp);
+	/* Free assoc rsp, so that reassoc rsp can be used during
+	 * reassociation.
+	 */
+	if (sta_ctx->assoc_rsp.ptr) {
+		qdf_mem_free(sta_ctx->assoc_rsp.ptr);
+		sta_ctx->assoc_rsp.ptr = NULL;
+		sta_ctx->assoc_rsp.len = 0;
+	}
+	sta_ctx->copied_reassoc_rsp = qdf_mem_malloc(
+			sizeof(struct wlan_cm_connect_resp));
+	if (!sta_ctx->copied_reassoc_rsp)
+		return QDF_STATUS_E_NOMEM;
 
-		qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp,
-			     sizeof(struct wlan_cm_connect_resp));
+	qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp,
+		     sizeof(struct wlan_cm_connect_resp));
 
-		sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc(
-				sizeof(struct wlan_roam_sync_info));
+	sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc(
+			sizeof(struct wlan_roam_sync_info));
 
-		if (!sta_ctx->copied_reassoc_rsp->roaming_info) {
-			qdf_mem_free(sta_ctx->copied_reassoc_rsp);
-			return QDF_STATUS_E_NOMEM;
-		}
+	if (!sta_ctx->copied_reassoc_rsp->roaming_info) {
+		qdf_mem_free(sta_ctx->copied_reassoc_rsp);
+		sta_ctx->copied_reassoc_rsp = NULL;
+		return QDF_STATUS_E_NOMEM;
+	}
 
-		qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info,
-			     reassoc_rsp->roaming_info,
-			     sizeof(struct wlan_roam_sync_info));
+	qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info,
+		     reassoc_rsp->roaming_info,
+		     sizeof(struct wlan_roam_sync_info));
 
-		connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies;
+	connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies;
 
-		connect_ies->assoc_rsp.len =
-			reassoc_rsp->connect_ies.assoc_rsp.len;
+	connect_ies->assoc_rsp.len =
+		reassoc_rsp->connect_ies.assoc_rsp.len;
 
-		connect_ies->assoc_rsp.ptr = qdf_mem_malloc(
-				connect_ies->assoc_rsp.len);
+	connect_ies->assoc_rsp.ptr = qdf_mem_malloc(
+			connect_ies->assoc_rsp.len);
 
-		if (!connect_ies->assoc_rsp.ptr) {
-			qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info);
-			qdf_mem_free(sta_ctx->copied_reassoc_rsp);
-			return QDF_STATUS_E_NOMEM;
-		}
+	if (!connect_ies->assoc_rsp.ptr) {
+		qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info);
+		sta_ctx->copied_reassoc_rsp->roaming_info = NULL;
+		qdf_mem_free(sta_ctx->copied_reassoc_rsp);
+		sta_ctx->copied_reassoc_rsp = NULL;
+		connect_ies->assoc_rsp.len = 0;
+		return QDF_STATUS_E_NOMEM;
+	}
 
-		qdf_mem_copy(connect_ies->assoc_rsp.ptr,
-			     reassoc_rsp->connect_ies.assoc_rsp.ptr,
-			     reassoc_rsp->connect_ies.assoc_rsp.len);
+	qdf_mem_copy(connect_ies->assoc_rsp.ptr,
+		     reassoc_rsp->connect_ies.assoc_rsp.ptr,
+		     reassoc_rsp->connect_ies.assoc_rsp.len);
 
-		connect_ies->assoc_req.len = 0;
-		connect_ies->assoc_req.ptr = NULL;
-		connect_ies->bcn_probe_rsp.len = 0;
-		connect_ies->bcn_probe_rsp.ptr = NULL;
-		connect_ies->link_bcn_probe_rsp.len = 0;
-		connect_ies->link_bcn_probe_rsp.ptr = NULL;
-		connect_ies->fils_ie = NULL;
+	connect_ies->assoc_req.len = 0;
+	connect_ies->assoc_req.ptr = NULL;
+	connect_ies->bcn_probe_rsp.len = 0;
+	connect_ies->bcn_probe_rsp.ptr = NULL;
+	connect_ies->link_bcn_probe_rsp.len = 0;
+	connect_ies->link_bcn_probe_rsp.ptr = NULL;
+	connect_ies->fils_ie = NULL;
 
-		mlo_debug("Copied reassoc response");
-	}
+	mlo_debug("Copied reassoc response for vdev: %d len: %d",
+		  wlan_vdev_get_id(vdev), connect_ies->assoc_rsp.len);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 156 - 109
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c

@@ -21,6 +21,9 @@
 #include "wlan_policy_mgr_ll_sap.h"
 
 #define BEARER_SWITCH_TIMEOUT 5000
+#define BS_PREFIX_FMT "BS_SM vdev %d req_id 0x%x: "
+#define BS_PREFIX_REF(vdev_id, req_id) (vdev_id), (req_id)
+
 
 wlan_bs_req_id ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_psoc *psoc)
 {
@@ -29,27 +32,29 @@ wlan_bs_req_id ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_psoc *psoc)
 	struct wlan_objmgr_vdev *vdev;
 	uint8_t vdev_id;
 
-	vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev(psoc);
+	vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc);
 	if (vdev_id == WLAN_INVALID_VDEV_ID)
 		return request_id;
 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
 						    WLAN_LL_SAP_ID);
 	if (!vdev) {
-		ll_sap_err("BS_SM ll vdev %d is NULL");
+		ll_sap_err(BS_PREFIX_FMT "Vdev is NULL",
+			   BS_PREFIX_REF(vdev_id, request_id));
 		return request_id;
 	}
 
 	ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev);
 	if (!ll_sap_obj) {
-		ll_sap_err("BS_SM vdev %d ll_sap obj null",
-			   wlan_vdev_get_id(vdev));
+		ll_sap_err(BS_PREFIX_FMT "ll sap obj is NULL",
+			   BS_PREFIX_REF(vdev_id, request_id));
+
 		goto rel_ref;
 	}
 
 	request_id = qdf_atomic_inc_return(
 				&ll_sap_obj->bearer_switch_ctx->request_id);
 
-	ll_sap_nofl_debug("BS_SM vdev %d request_id %d", request_id, vdev_id);
+	ll_sap_nofl_debug(BS_PREFIX_FMT, BS_PREFIX_REF(vdev_id, request_id));
 rel_ref:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID);
 
@@ -137,12 +142,14 @@ void bs_req_timer_deinit(struct bearer_switch_info *bs_ctx)
 /**
  * ll_lt_sap_stop_bs_timer() - Stop bearer switch timer
  * @bs_ctx: Bearer switch context
+ * @req_id: Request id for which timer needs to be stopped
  *
  * API to stop bearer switch request timer
  *
  * Return: None
  */
-static void ll_lt_sap_stop_bs_timer(struct bearer_switch_info *bs_ctx)
+static void ll_lt_sap_stop_bs_timer(struct bearer_switch_info *bs_ctx,
+				    uint32_t req_id)
 {
 	QDF_STATUS status;
 
@@ -150,11 +157,13 @@ static void ll_lt_sap_stop_bs_timer(struct bearer_switch_info *bs_ctx)
 		qdf_mc_timer_get_current_state(&bs_ctx->bs_request_timer)) {
 		status = qdf_mc_timer_stop(&bs_ctx->bs_request_timer);
 		if (QDF_IS_STATUS_ERROR(status))
-			ll_sap_err("BS_SM vdev %d failed to stop timer",
-				   wlan_vdev_get_id(bs_ctx->vdev));
+			ll_sap_err(BS_PREFIX_FMT "failed to stop timer",
+				   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+						 req_id));
 	} else {
-		ll_sap_err("BS_SM vdev %d timer is not running",
-			   wlan_vdev_get_id(bs_ctx->vdev));
+		ll_sap_err(BS_PREFIX_FMT "timer is not running",
+			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					 req_id));
 	}
 }
 
@@ -221,9 +230,8 @@ ll_lt_sap_invoke_req_callback_f(struct bearer_switch_info *bs_ctx,
 /**
  * ll_lt_sap_bs_increament_ref_count() - Increment the bearer switch ref count
  * @bs_ctx: Bearer switch context
- * @vdev_id: Vdev id corresponding to which the ref count needs to be
- * incremented
- * @src: source of req
+ * @bs_req: Bearer switch request corresponding to which the ref count needs to
+ * be incremented
  *
  * API to increment the bearer switch ref count
  *
@@ -231,25 +239,26 @@ ll_lt_sap_invoke_req_callback_f(struct bearer_switch_info *bs_ctx,
  */
 static inline void
 ll_lt_sap_bs_increament_ref_count(struct bearer_switch_info *bs_ctx,
-				  uint8_t vdev_id,
-				  enum bearer_switch_req_source src)
+				  struct wlan_bearer_switch_request *bs_req)
 {
 	uint32_t ref_count;
 	uint32_t total_ref_count;
 
 	total_ref_count = qdf_atomic_inc_return(&bs_ctx->total_ref_count);
-	ref_count = qdf_atomic_inc_return(&bs_ctx->ref_count[vdev_id][src]);
+	ref_count = qdf_atomic_inc_return(&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]);
 
-	ll_sap_nofl_debug("BS_SM vdev_id %d src %d ref_count %d Total ref count %d",
-			  vdev_id, src, ref_count, total_ref_count);
+	ll_sap_nofl_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count %d Total ref count %d",
+			  BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					bs_req->request_id),
+			  bs_req->vdev_id, bs_req->source, ref_count,
+			  total_ref_count);
 }
 
 /**
  * ll_lt_sap_bs_decreament_ref_count() - Decreament the bearer switch ref count
  * @bs_ctx: Bearer switch context
- * @vdev_id: Vdev id corresponding to which the ref count needs to be
- * decreament
- * @src: source of req
+ * @bs_req: Bearer switch request corresponding to which the ref count needs to
+ * be decremented
  *
  * API to decreament the bearer switch ref count
  *
@@ -257,8 +266,7 @@ ll_lt_sap_bs_increament_ref_count(struct bearer_switch_info *bs_ctx,
  */
 static inline QDF_STATUS
 ll_lt_sap_bs_decreament_ref_count(struct bearer_switch_info *bs_ctx,
-				  uint8_t vdev_id,
-				  enum bearer_switch_req_source src)
+				  struct wlan_bearer_switch_request *bs_req)
 {
 	uint32_t ref_count;
 	uint32_t total_ref_count;
@@ -268,16 +276,21 @@ ll_lt_sap_bs_decreament_ref_count(struct bearer_switch_info *bs_ctx,
 	 * module did not requested for wlan to non wlan transition earlier, so
 	 * reject this operation.
 	 */
-	if (!qdf_atomic_read(&bs_ctx->ref_count[vdev_id][src])) {
-		ll_sap_debug("BS_SM vdev_id %d src %d ref_count is zero",
-			     vdev_id, src);
+	if (!qdf_atomic_read(&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source])) {
+		ll_sap_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count is zero",
+			     BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					   bs_req->request_id),
+			     bs_req->vdev_id, bs_req->source);
 		return QDF_STATUS_E_INVAL;
 	}
 	total_ref_count = qdf_atomic_dec_return(&bs_ctx->total_ref_count);
-	ref_count = qdf_atomic_dec_return(&bs_ctx->ref_count[vdev_id][src]);
+	ref_count = qdf_atomic_dec_return(&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]);
 
-	ll_sap_nofl_debug("BS_SM vdev_id %d src %d ref_count %d Total ref count %d",
-			  vdev_id, src, ref_count, total_ref_count);
+	ll_sap_nofl_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count %d Total ref count %d",
+			  BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					bs_req->request_id),
+			  bs_req->vdev_id, bs_req->source,
+			  ref_count, total_ref_count);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -304,8 +317,10 @@ ll_lt_sap_cache_bs_request(struct bearer_switch_info *bs_ctx,
 		 */
 		if (bs_ctx->requests[i].requester_cb)
 			continue;
-		ll_sap_debug("BS_SM vdev_id %d cache %d request at %d",
-			     wlan_vdev_get_id(bs_ctx->vdev), bs_req->req_type);
+		ll_sap_debug(BS_PREFIX_FMT "req_vdev %d cache %d request at %d",
+			     BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					   bs_req->request_id),
+			     bs_req->vdev_id, bs_req->req_type, i);
 		bs_ctx->requests[i].vdev_id = bs_req->vdev_id;
 		bs_ctx->requests[i].request_id = bs_req->request_id;
 		bs_ctx->requests[i].req_type = bs_req->req_type;
@@ -316,8 +331,9 @@ ll_lt_sap_cache_bs_request(struct bearer_switch_info *bs_ctx,
 		break;
 	}
 	if (i >= MAX_BEARER_SWITCH_REQUESTERS)
-		ll_sap_err("BS_SM vdev_id %d Max number of requests reached",
-			   wlan_vdev_get_id(bs_ctx->vdev));
+		ll_sap_err(BS_PREFIX_FMT "Max number of requests reached",
+			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					 bs_req->request_id));
 }
 
 /*
@@ -444,13 +460,13 @@ ll_lt_sap_send_bs_req_to_userspace(struct wlan_objmgr_vdev *vdev,
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
 	QDF_STATUS status;
 
-	status = ll_lt_sap_bs_decreament_ref_count(bs_ctx, bs_req->vdev_id,
-						   bs_req->source);
+	status = ll_lt_sap_bs_decreament_ref_count(bs_ctx, bs_req);
 	if (QDF_IS_STATUS_ERROR(status))
 		return;
 
@@ -464,9 +480,9 @@ ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state(struct bearer_switch_info *bs_ctx,
 	status = qdf_mc_timer_start(&bs_ctx->bs_request_timer,
 				    BEARER_SWITCH_TIMEOUT);
 	if (QDF_IS_STATUS_ERROR(status))
-		ll_sap_err("BS_SM vdev %d failed to start time req %dr",
-			   wlan_vdev_get_id(bs_ctx->vdev),
-			   bs_req->request_id);
+		ll_sap_err(BS_PREFIX_FMT "Failed to start timer",
+			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					 bs_req->request_id));
 
 	bs_sm_transition_to(bs_ctx, BEARER_WLAN_REQUESTED);
 
@@ -474,6 +490,25 @@ invoke_requester_cb:
 	ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, status);
 }
 
+/**
+ * ll_lt_sap_handle_bs_to_wlan_completed_wlan_in_non_wlan_state() - API to
+ * handle bearer switch to wlan completed event in non-wlan state.
+ * @bs_ctx: Bearer switch context
+ *
+ * This event is possible only if current bearer is non-wlan and user space
+ * switches the bearer to wlan first time after bringing up the LL_LT_SAP.
+ * Since host driver did not request for the bearer switch so there will not
+ * be any valid bearer switch request.
+ *
+ * Return: None
+ */
+static void
+ll_lt_sap_handle_bs_to_wlan_completed_wlan_in_non_wlan_state(
+				struct bearer_switch_info *bs_ctx)
+{
+	bs_sm_transition_to(bs_ctx, BEARER_WLAN);
+}
+
 /**
  * ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state() - API to handle bearer
  * switch to non-wlan in non-wlan state.
@@ -496,8 +531,7 @@ ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state(
 {
 	QDF_STATUS status;
 
-	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req->vdev_id,
-					  bs_req->source);
+	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req);
 
 	if (QDF_IS_STATUS_SUCCESS(bs_ctx->last_status))
 		return ll_lt_sap_invoke_req_callback(bs_ctx, bs_req,
@@ -508,8 +542,9 @@ ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state(
 	status = qdf_mc_timer_start(&bs_ctx->bs_request_timer,
 				    BEARER_SWITCH_TIMEOUT);
 	if (QDF_IS_STATUS_ERROR(status))
-		ll_sap_err("BS_SM vdev %d failed to start timer",
-			   wlan_vdev_get_id(bs_ctx->vdev));
+		ll_sap_err(BS_PREFIX_FMT "Failed to start timer",
+			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					 bs_req->request_id));
 
 	bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN_REQUESTED);
 }
@@ -543,17 +578,17 @@ ll_lt_sap_handle_bs_to_wlan_in_non_wlan_requested_state(
 {
 	QDF_STATUS status;
 
-	status = ll_lt_sap_bs_decreament_ref_count(bs_ctx, bs_req->vdev_id,
-						   bs_req->source);
+	status = ll_lt_sap_bs_decreament_ref_count(bs_ctx, bs_req);
 
 	if (QDF_IS_STATUS_ERROR(status))
 		return;
 
 	if (!bs_req->requester_cb) {
-		ll_sap_err("BS_SM vdev %d NULL cbk, req_vdev %d src %d req %d arg val %d",
-			   wlan_vdev_get_id(bs_ctx->vdev),
+		ll_sap_err(BS_PREFIX_FMT "NULL cbk, req_vdev %d src %d arg val %d",
+			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					 bs_req->request_id),
 			   bs_req->vdev_id, bs_req->source,
-			   bs_req->request_id, bs_req->arg_value);
+			   bs_req->arg_value);
 		return;
 	}
 
@@ -580,8 +615,7 @@ ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_requested_state(
 				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
-	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req->vdev_id,
-					  bs_req->source);
+	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req);
 
 	ll_lt_sap_cache_bs_request(bs_ctx, bs_req);
 }
@@ -593,7 +627,7 @@ ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_requested_state(
  * @bs_req: Bearer switch request
  *
  * Move the bearer state to BEARER_NON_WLAN, even if this request is timedout as
- * requester of this request needs to invoke the earer switch to wlan again
+ * requester of this request needs to invoke the bearer switch to wlan again
  * to reset the ref counts and in that path the state will be moved to
  * BEARER_WLAN and the request to switch the bearer to userspace will still be
  * sent irrespective of last_status and userspace should return success as
@@ -610,7 +644,8 @@ ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_requested_state(
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_non_wlan_timeout(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_non_wlan_timeout(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
 	struct wlan_bearer_switch_request *first_bs_req;
@@ -633,7 +668,6 @@ ll_lt_sap_handle_bs_to_non_wlan_timeout(struct bearer_switch_info *bs_ctx,
 		ll_sap_err("BS_SM vdev %d Invalid total ref count %d",
 			   wlan_vdev_get_id(bs_ctx->vdev),
 			   qdf_atomic_read(&bs_ctx->total_ref_count));
-
 		QDF_BUG(0);
 	}
 
@@ -660,12 +694,13 @@ ll_lt_sap_handle_bs_to_non_wlan_timeout(struct bearer_switch_info *bs_ctx,
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_non_wlan_completed(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_non_wlan_completed(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
 	struct wlan_bearer_switch_request *first_bs_req;
 
-	ll_lt_sap_stop_bs_timer(bs_ctx);
+	ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id);
 
 	bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN);
 
@@ -718,12 +753,13 @@ ll_lt_sap_handle_bs_to_non_wlan_completed(struct bearer_switch_info *bs_ctx,
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_non_wlan_failure(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_non_wlan_failure(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
 	struct wlan_bearer_switch_request *first_bs_req;
 
-	ll_lt_sap_stop_bs_timer(bs_ctx);
+	ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id);
 
 	bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN);
 
@@ -764,7 +800,8 @@ ll_lt_sap_handle_bs_to_non_wlan_failure(struct bearer_switch_info *bs_ctx,
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_wlan_in_wlan_state(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_wlan_in_wlan_state(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
 	ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, QDF_STATUS_E_ALREADY);
@@ -782,22 +819,22 @@ ll_lt_sap_handle_bs_to_wlan_in_wlan_state(struct bearer_switch_info *bs_ctx,
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_non_wlan_in_wlan_state(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_non_wlan_in_wlan_state(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
 	QDF_STATUS status;
 
 	if (!bs_req->requester_cb) {
-		ll_sap_err("BS_SM vdev %d NULL cbk req_vdev %d src %d req %d",
-			   wlan_vdev_get_id(bs_ctx->vdev),
+		ll_sap_err(BS_PREFIX_FMT "NULL cbk, req_vdev %d src %d arg val %d",
+			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					 bs_req->request_id),
 			   bs_req->vdev_id, bs_req->source,
-			   bs_req->request_id);
-
+			   bs_req->arg_value);
 		return;
 	}
 
-	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req->vdev_id,
-					  bs_req->source);
+	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req);
 
 	ll_lt_sap_cache_bs_request(bs_ctx, bs_req);
 
@@ -810,9 +847,9 @@ ll_lt_sap_handle_bs_to_non_wlan_in_wlan_state(struct bearer_switch_info *bs_ctx,
 	status = qdf_mc_timer_start(&bs_ctx->bs_request_timer,
 				    BEARER_SWITCH_TIMEOUT);
 	if (QDF_IS_STATUS_ERROR(status))
-		ll_sap_err("BS_SM vdev %d failed to start timer",
-			   wlan_vdev_get_id(bs_ctx->vdev));
-
+		ll_sap_err(BS_PREFIX_FMT "Failed to start timer",
+			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
+					 bs_req->request_id));
 	/*
 	 * Todo, upon receiving response for non-wlan request, deliver event
 	 * WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_COMPLETED from the vendor command
@@ -859,8 +896,7 @@ ll_lt_sap_handle_bs_to_non_wlan_in_wlan_req_state(
 				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
-	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req->vdev_id,
-					  bs_req->source);
+	ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req);
 
 	ll_lt_sap_cache_bs_request(bs_ctx, bs_req);
 }
@@ -892,7 +928,6 @@ ll_lt_sap_switch_to_non_wlan_from_wlan(struct bearer_switch_info *bs_ctx)
 		ll_sap_err("BS_SM vdev %d Invalid total ref count %d",
 			   wlan_vdev_get_id(bs_ctx->vdev),
 			   qdf_atomic_read(&bs_ctx->total_ref_count));
-
 		QDF_BUG(0);
 	}
 
@@ -916,7 +951,8 @@ ll_lt_sap_switch_to_non_wlan_from_wlan(struct bearer_switch_info *bs_ctx)
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_wlan_timeout(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_wlan_timeout(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
 	bs_sm_transition_to(bs_ctx, BEARER_WLAN);
@@ -941,10 +977,11 @@ ll_lt_sap_handle_bs_to_wlan_timeout(struct bearer_switch_info *bs_ctx,
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_wlan_completed(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_wlan_completed(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
-	ll_lt_sap_stop_bs_timer(bs_ctx);
+	ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id);
 
 	bs_sm_transition_to(bs_ctx, BEARER_WLAN);
 
@@ -970,10 +1007,11 @@ ll_lt_sap_handle_bs_to_wlan_completed(struct bearer_switch_info *bs_ctx,
  * Return: None
  */
 static void
-ll_lt_sap_handle_bs_to_wlan_failure(struct bearer_switch_info *bs_ctx,
+ll_lt_sap_handle_bs_to_wlan_failure(
+				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
-	ll_lt_sap_stop_bs_timer(bs_ctx);
+	ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id);
 
 	bs_sm_transition_to(bs_ctx, BEARER_WLAN);
 
@@ -1030,7 +1068,8 @@ static bool bs_state_non_wlan_event(void *ctx, uint16_t event,
 	struct bearer_switch_info *bs_ctx = ctx;
 	struct wlan_bearer_switch_request *bs_req = data;
 
-	if (!ll_lt_sap_is_bs_req_valid(bs_req))
+	if (event != WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED &&
+	    !ll_lt_sap_is_bs_req_valid(bs_req))
 		return false;
 	if (!ll_lt_sap_is_bs_ctx_valid(bs_ctx))
 		return false;
@@ -1043,6 +1082,14 @@ static bool bs_state_non_wlan_event(void *ctx, uint16_t event,
 		ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state(bs_ctx,
 								  bs_req);
 		break;
+	/*
+	 * This event is possible when userspace first time sends the request
+	 * to switch the bearer.
+	 */
+	case WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED:
+		ll_lt_sap_handle_bs_to_wlan_completed_wlan_in_non_wlan_state(
+									bs_ctx);
+		break;
 	default:
 		event_handled = false;
 		break;
@@ -1355,7 +1402,8 @@ QDF_STATUS bs_sm_create(struct bearer_switch_info *bs_ctx)
 			    bs_sm_event_names,
 			    QDF_ARRAY_SIZE(bs_sm_event_names));
 	if (!sm) {
-		ll_sap_err("BS_SM State Machine creation failed");
+		ll_sap_err("Vdev %d BS_SM State Machine creation failed",
+			   wlan_vdev_get_id(bs_ctx->vdev));
 		return QDF_STATUS_E_NOMEM;
 	}
 	bs_ctx->sm.sm_hdl = sm;
@@ -1438,7 +1486,7 @@ QDF_STATUS bs_sm_deliver_event(struct wlan_objmgr_psoc *psoc,
 	struct ll_sap_vdev_priv_obj *ll_sap_obj;
 	uint8_t vdev_id;
 
-	vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev(psoc);
+	vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc);
 	if (vdev_id == WLAN_INVALID_VDEV_ID)
 		return QDF_STATUS_E_INVAL;
 
@@ -1501,7 +1549,8 @@ ll_lt_sap_switch_bearer_to_wlan(struct wlan_objmgr_psoc *psoc,
 }
 
 QDF_STATUS
-ll_lt_sap_request_for_audio_transport_switch(struct wlan_objmgr_vdev *vdev,
+ll_lt_sap_request_for_audio_transport_switch(
+					struct wlan_objmgr_vdev *vdev,
 					enum bearer_switch_req_type req_type)
 {
 	struct ll_sap_vdev_priv_obj *ll_sap_obj;
@@ -1519,7 +1568,7 @@ ll_lt_sap_request_for_audio_transport_switch(struct wlan_objmgr_vdev *vdev,
 		return QDF_STATUS_E_INVAL;
 
 	/*
-	 * Request to switch to non-wlan can always be acceptes so,
+	 * Request to switch to non-wlan can always be accepted so,
 	 * always return success
 	 */
 	if (req_type == WLAN_BS_REQ_TO_NON_WLAN) {
@@ -1541,7 +1590,8 @@ ll_lt_sap_request_for_audio_transport_switch(struct wlan_objmgr_vdev *vdev,
 
 		return QDF_STATUS_E_FAILURE;
 	}
-	ll_sap_err("BS_SM vdev %d Invalid audio transport type %d", req_type);
+	ll_sap_err("BS_SM vdev %d Invalid audio transport type %d",
+		   wlan_vdev_get_id(vdev), req_type);
 
 	return QDF_STATUS_E_INVAL;
 }
@@ -1580,31 +1630,21 @@ static void ll_lt_sap_deliver_wlan_audio_transport_switch_resp(
 	 * If bs_request is cached in the BS_SM, it means this is a response
 	 * to the host driver's request of bearer switch so deliver the event
 	 * to the BS_SM
-	 */
-	if (bs_request) {
-		if (status == WLAN_BS_STATUS_COMPLETED)
-			bs_sm_deliver_event(
-					wlan_vdev_get_psoc(vdev),
-					WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED,
-					sizeof(*bs_request), bs_request);
-		else if (status == WLAN_BS_STATUS_REJECTED)
-			bs_sm_deliver_event(
-					wlan_vdev_get_psoc(vdev),
-					WLAN_BS_SM_EV_SWITCH_TO_WLAN_FAILURE,
-					sizeof(*bs_request), bs_request);
-		else
-			ll_sap_err("BS_SM vdev %d Invalid BS status %d",
-				   wlan_vdev_get_id(vdev), status);
-		return;
-	}
-
-	/*
 	 * If there is no cached request in BS_SM, it means that some other
-	 * module has performed the bearer switch and it is not a response of
-	 * the wlan bearer switch request, so just update the current state of
-	 * the state machine
+	 * module (other than wlan) has performed the bearer switch and it is
+	 * not a response of the wlan module's bearer switch request.
 	 */
-	bs_sm_state_update(bs_ctx, BEARER_WLAN);
+	if (status == WLAN_BS_STATUS_COMPLETED)
+		bs_sm_deliver_event(wlan_vdev_get_psoc(vdev),
+				    WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED,
+				    sizeof(*bs_request), bs_request);
+	else if (status == WLAN_BS_STATUS_REJECTED)
+		bs_sm_deliver_event(wlan_vdev_get_psoc(vdev),
+				    WLAN_BS_SM_EV_SWITCH_TO_WLAN_FAILURE,
+				    sizeof(*bs_request), bs_request);
+	else
+		ll_sap_err("BS_SM vdev %d Invalid BS status %d",
+			   wlan_vdev_get_id(vdev), status);
 }
 
 /**
@@ -1654,8 +1694,11 @@ static void ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp(
 				WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_FAILURE,
 				sizeof(*bs_request), bs_request);
 		else
-			ll_sap_err("BS_SM vdev %d Invalid BS status %d",
-				   wlan_vdev_get_id(vdev), status);
+			ll_sap_err(BS_PREFIX_FMT "Invalid BS status %d",
+				   BS_PREFIX_REF(wlan_vdev_get_id(vdev),
+						 bs_request->request_id),
+				   status);
+
 		return;
 	}
 
@@ -1669,7 +1712,8 @@ static void ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp(
 }
 
 void
-ll_lt_sap_deliver_audio_transport_switch_resp(struct wlan_objmgr_vdev *vdev,
+ll_lt_sap_deliver_audio_transport_switch_resp(
+				struct wlan_objmgr_vdev *vdev,
 				enum bearer_switch_req_type req_type,
 				enum bearer_switch_status status)
 {
@@ -1678,8 +1722,11 @@ ll_lt_sap_deliver_audio_transport_switch_resp(struct wlan_objmgr_vdev *vdev,
 								vdev,
 								status);
 
-	if (req_type == WLAN_BS_REQ_TO_WLAN)
+	else if (req_type == WLAN_BS_REQ_TO_WLAN)
 		ll_lt_sap_deliver_wlan_audio_transport_switch_resp(
 								vdev,
 								status);
+	else
+		ll_sap_err("Vdev %d Invalid req_type %d ",
+			   wlan_vdev_get_id(vdev), req_type);
 }

+ 301 - 23
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c

@@ -15,10 +15,13 @@
  */
 
 #include "wlan_ll_lt_sap_main.h"
-#include "wlan_scan_ucfg_api.h"
+#include "wlan_reg_services_api.h"
+#include "wlan_ll_sap_public_structs.h"
+#include "wlan_policy_mgr_i.h"
 #include "wlan_mlme_vdev_mgr_interface.h"
 #include "wlan_ll_sap_main.h"
 #include "wlan_ll_lt_sap_bearer_switch.h"
+#include "wlan_scan_api.h"
 
 bool ll_lt_sap_is_supported(void)
 {
@@ -28,10 +31,20 @@ bool ll_lt_sap_is_supported(void)
 	return true;
 }
 
-QDF_STATUS
-ll_lt_sap_get_sorted_user_config_acs_ch_list(struct wlan_objmgr_psoc *psoc,
-					     uint8_t vdev_id,
-					     struct sap_sel_ch_info *ch_info)
+/**
+ * ll_lt_sap_get_sorted_user_config_acs_ch_list() - API to get sorted user
+ * configured ACS channel list
+ * @psoc: Pointer to psoc object
+ * @vdev_id: Vdev Id
+ * @ch_info: Pointer to ch_info
+ *
+ * Return: None
+ */
+static
+QDF_STATUS ll_lt_sap_get_sorted_user_config_acs_ch_list(
+					struct wlan_objmgr_psoc *psoc,
+					uint8_t vdev_id,
+					struct sap_sel_ch_info *ch_info)
 {
 	struct scan_filter *filter;
 	qdf_list_t *list = NULL;
@@ -87,12 +100,12 @@ QDF_STATUS ll_lt_sap_init(struct wlan_objmgr_vdev *vdev)
 		return QDF_STATUS_E_INVAL;
 	}
 
-	bs_ctx = ll_sap_obj->bearer_switch_ctx;
-
 	bs_ctx = qdf_mem_malloc(sizeof(struct bearer_switch_info));
 	if (!bs_ctx)
 		return QDF_STATUS_E_NOMEM;
 
+	ll_sap_obj->bearer_switch_ctx = bs_ctx;
+
 	qdf_atomic_init(&bs_ctx->request_id);
 
 	for (i = 0; i < WLAN_UMAC_PSOC_MAX_VDEVS; i++)
@@ -146,27 +159,292 @@ QDF_STATUS ll_lt_sap_deinit(struct wlan_objmgr_vdev *vdev)
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS ll_lt_sap_switch_bearer_to_ble(struct wlan_objmgr_psoc *psoc,
-				struct wlan_bearer_switch_request *bs_request)
+static
+void ll_lt_sap_update_mac_freq(struct wlan_ll_lt_sap_mac_freq *freq_list,
+			       qdf_freq_t sbs_cut_off_freq,
+			       qdf_freq_t given_freq, uint32_t given_weight)
+{
+	if (WLAN_REG_IS_5GHZ_CH_FREQ(given_freq) &&
+	    ((sbs_cut_off_freq && given_freq < sbs_cut_off_freq) ||
+	    !sbs_cut_off_freq) && !freq_list->freq_5GHz_low) {
+		freq_list->freq_5GHz_low = given_freq;
+		freq_list->weight_5GHz_low = given_weight;
+
+		/*
+		 * Update same freq in 5GHz high freq if sbs_cut_off_freq
+		 * is not present
+		 */
+		if (!sbs_cut_off_freq) {
+			freq_list->freq_5GHz_high = given_freq;
+			freq_list->weight_5GHz_high = given_weight;
+		}
+	} else if (WLAN_REG_IS_5GHZ_CH_FREQ(given_freq) &&
+		   ((sbs_cut_off_freq && given_freq > sbs_cut_off_freq) ||
+		   !sbs_cut_off_freq) && !freq_list->freq_5GHz_high) {
+			freq_list->freq_5GHz_high = given_freq;
+			freq_list->weight_5GHz_high = given_weight;
+
+		/*
+		 * Update same freq for 5GHz low freq if sbs_cut_off_freq
+		 * is not present
+		 */
+		if (!sbs_cut_off_freq) {
+			freq_list->freq_5GHz_low = given_freq;
+			freq_list->weight_5GHz_low = given_weight;
+		}
+	} else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(given_freq) &&
+		   !freq_list->freq_6GHz) {
+		freq_list->freq_6GHz = given_freq;
+		freq_list->weight_6GHz = given_weight;
+	}
+}
+
+/* Threshold value of channel weight */
+#define CHANNEL_WEIGHT_THRESHOLD_VALUE 20000
+static
+void ll_lt_sap_update_freq_list(struct wlan_objmgr_psoc *psoc,
+				struct sap_sel_ch_info *ch_param,
+				struct wlan_ll_lt_sap_freq_list *freq_list,
+				struct policy_mgr_pcl_list *pcl,
+				struct connection_info *info,
+				uint8_t connection_count,
+				uint8_t vdev_id)
 {
-	return bs_sm_deliver_event(psoc, WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN,
-				   sizeof(*bs_request), bs_request);
+	qdf_freq_t freq, sbs_cut_off_freq;
+	qdf_freq_t same_mac_freq, standalone_mac_freq;
+	uint8_t i = 0, count;
+	uint32_t weight;
+	enum policy_mgr_con_mode con_mode = PM_MAX_NUM_OF_MODE;
+
+	sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc);
+
+	for (i = 0; i < ch_param->num_ch; i++) {
+		if (!ch_param->ch_info[i].valid)
+			continue;
+
+		freq = ch_param->ch_info[i].chan_freq;
+		weight = ch_param->ch_info[i].weight;
+
+		/*
+		 * Do not select same channel where LL_LT_SAP was
+		 * present earlier
+		 */
+		if (freq_list->prev_freq == freq)
+			continue;
+
+		/* Check if channel is present in PCL or not */
+		if (!wlan_ll_sap_freq_present_in_pcl(pcl, freq))
+			continue;
+
+		/*
+		 * Store first valid best channel from ACS final list
+		 * This will be used if there is no valid freq present
+		 * within threshold value or no concurrency present
+		 */
+		if (!freq_list->best_freq) {
+			freq_list->best_freq = freq;
+			freq_list->weight_best_freq = weight;
+		}
+
+		if (!connection_count)
+			break;
+
+		/*
+		 * Instead of selecting random channel, select those
+		 * channel whose weight is less than
+		 * CHANNEL_WEIGHT_THRESHOLD_VALUE value. This will help
+		 * to get the best channel compartively and avoid multiple
+		 * times of channel switch.
+		 */
+		if (weight > CHANNEL_WEIGHT_THRESHOLD_VALUE)
+			continue;
+
+		same_mac_freq = 0;
+		standalone_mac_freq = 0;
+
+		/*
+		 * Loop through all existing connections before updating
+		 * channels for LL_LT_SAP.
+		 */
+		for (count = 0; count < connection_count; count++) {
+			/* Do not select SCC channel to update freq_list */
+			if (freq == info[count].ch_freq) {
+				same_mac_freq = 0;
+				standalone_mac_freq = 0;
+				break;
+			}
+			/*
+			 * Check whether ch_param frequency is in same mac
+			 * or not.
+			 */
+			if (policy_mgr_2_freq_always_on_same_mac(
+							psoc, freq,
+							info[count].ch_freq)) {
+				con_mode = policy_mgr_get_mode_by_vdev_id(
+						psoc, info[count].vdev_id);
+				/*
+				 * Check whether SAP is present in same mac or
+				 * not. If yes then do not select that frequency
+				 * because two beacon entity can't be in same
+				 * mac.
+				 * Also, do not fill same_mac_freq if it's
+				 * already filled i.e two existing connection
+				 * are present on same mac.
+				 */
+				if (con_mode == PM_SAP_MODE || same_mac_freq) {
+					same_mac_freq = 0;
+					standalone_mac_freq = 0;
+					break;
+				}
+				same_mac_freq = freq;
+			} else if (!standalone_mac_freq) {
+				/*
+				 * Fill standalone_mac_freq only if it's not
+				 * filled
+				 */
+				standalone_mac_freq = freq;
+			}
+		}
+
+		/*
+		 * Scenario: Let say two concurrent connection(other than
+		 * LL_LT_SAP) are present in both mac and one channel from
+		 * ch_param structure needs to select to fill in freq_list for
+		 * LL_LT_SAP.
+		 * Since, there is an existing connection present in both mac
+		 * then there is chance that channel from ch_param structure
+		 * may get select for both same_mac_freq and standalone_mac_freq
+		 *
+		 * But ideally standalone_mac_freq is not free, some existing
+		 * connection is already present in it.
+		 * So, instead of giving priority to fill standalone_mac_freq
+		 * first, fill same_mac_freq first.
+		 *
+		 * Example: Let say 2 concurrent interface present in channel
+		 * 36 and 149. Now channel 48 from ch_param structure needs to
+		 * be validate and fill based on existing interface.
+		 * With respect to channel 36, it will fit to same_mac_freq
+		 * and with respect to channel 149, it will fit to
+		 * standalone_mac_freq. But in standalone_mac_freq, there is
+		 * already existing interface present. So, give priority to
+		 * same_mac_freq to fill the freq list.
+		 */
+		if (same_mac_freq)
+			ll_lt_sap_update_mac_freq(&freq_list->shared_mac,
+						  sbs_cut_off_freq,
+						  same_mac_freq,
+						  weight);
+		else if (standalone_mac_freq)
+			ll_lt_sap_update_mac_freq(&freq_list->standalone_mac,
+						  sbs_cut_off_freq,
+						  standalone_mac_freq,
+						  weight);
+
+		if (freq_list->shared_mac.freq_5GHz_low &&
+		    freq_list->shared_mac.freq_5GHz_high &&
+		    freq_list->shared_mac.freq_6GHz &&
+		    freq_list->standalone_mac.freq_5GHz_low &&
+		    freq_list->standalone_mac.freq_5GHz_high &&
+		    freq_list->standalone_mac.freq_6GHz)
+			break;
+	}
+
+	ll_sap_debug("vdev %d, best %d[%d] Shared: low %d[%d] high %d[%d] 6Ghz %d[%d], Standalone: low %d[%d] high %d[%d] 6Ghz %d[%d], prev %d, existing connection cnt %d",
+		     vdev_id, freq_list->best_freq,
+		     freq_list->weight_best_freq,
+		     freq_list->shared_mac.freq_5GHz_low,
+		     freq_list->shared_mac.weight_5GHz_low,
+		     freq_list->shared_mac.freq_5GHz_high,
+		     freq_list->shared_mac.weight_5GHz_high,
+		     freq_list->shared_mac.freq_6GHz,
+		     freq_list->shared_mac.weight_6GHz,
+		     freq_list->standalone_mac.freq_5GHz_low,
+		     freq_list->standalone_mac.weight_5GHz_low,
+		     freq_list->standalone_mac.freq_5GHz_high,
+		     freq_list->standalone_mac.weight_5GHz_high,
+		     freq_list->standalone_mac.freq_6GHz,
+		     freq_list->standalone_mac.weight_6GHz,
+		     freq_list->prev_freq, connection_count);
 }
 
-QDF_STATUS ll_lt_sap_request_for_audio_transport_switch(
-					enum bearer_switch_req_type req_type)
+static
+QDF_STATUS ll_lt_sap_get_allowed_freq_list(
+				struct wlan_objmgr_psoc *psoc,
+				uint8_t vdev_id,
+				struct sap_sel_ch_info *ch_param,
+				struct wlan_ll_lt_sap_freq_list *freq_list)
 {
+	struct connection_info conn_info[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint8_t count;
+	struct policy_mgr_pcl_list *pcl;
+	QDF_STATUS status;
+
+	pcl = qdf_mem_malloc(sizeof(*pcl));
+	if (!pcl)
+		return QDF_STATUS_E_FAILURE;
+
+	status = policy_mgr_get_pcl_ch_list_for_ll_sap(psoc, pcl, vdev_id,
+						       conn_info, &count);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto end;
+
+	ll_lt_sap_update_freq_list(psoc, ch_param, freq_list, pcl,
+				   conn_info, count, vdev_id);
+
+	status = QDF_STATUS_SUCCESS;
+end:
+	qdf_mem_free(pcl);
+	return status;
+}
+
+QDF_STATUS ll_lt_sap_get_freq_list(struct wlan_objmgr_psoc *psoc,
+				   struct wlan_ll_lt_sap_freq_list *freq_list,
+				   uint8_t vdev_id)
+{
+	struct sap_sel_ch_info ch_param = { NULL, 0 };
+	QDF_STATUS status;
+
 	/*
-	 * return status as QDF_STATUS_SUCCESS or failure based on the current
-	 * pending requests of the transport switch
+	 * This memory will be allocated in sap_chan_sel_init() as part
+	 * of sap_sort_channel_list(). But the caller has to free up the
+	 * allocated memory
 	 */
-	if (req_type == WLAN_BS_REQ_TO_NON_WLAN) {
-		ll_sap_debug("request SWITCH_TYPE_NON_WLAN accepted");
-		return QDF_STATUS_SUCCESS;
-	} else if (req_type == WLAN_BS_REQ_TO_WLAN) {
-		ll_sap_debug("request SWITCH_TYPE_WLAN accepted");
-		return QDF_STATUS_SUCCESS;
-	}
 
-	return QDF_STATUS_E_RESOURCES;
+	status = ll_lt_sap_get_sorted_user_config_acs_ch_list(psoc, vdev_id,
+							      &ch_param);
+
+	if (!ch_param.num_ch || QDF_IS_STATUS_ERROR(status))
+		goto release_mem;
+
+	status = ll_lt_sap_get_allowed_freq_list(psoc, vdev_id, &ch_param,
+						 freq_list);
+
+release_mem:
+	wlan_ll_sap_free_chan_info(&ch_param);
+	return status;
+}
+
+qdf_freq_t ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc,
+				    uint8_t vdev_id)
+{
+	struct wlan_ll_lt_sap_freq_list freq_list;
+
+	qdf_mem_zero(&freq_list, sizeof(freq_list));
+
+	ll_lt_sap_get_freq_list(psoc, &freq_list, vdev_id);
+
+	if (freq_list.standalone_mac.freq_5GHz_low)
+		return freq_list.standalone_mac.freq_5GHz_low;
+	if (freq_list.shared_mac.freq_5GHz_low)
+		return freq_list.shared_mac.freq_5GHz_low;
+	if (freq_list.standalone_mac.freq_6GHz)
+		return freq_list.standalone_mac.freq_6GHz;
+	if (freq_list.standalone_mac.freq_5GHz_high)
+		return freq_list.standalone_mac.freq_5GHz_high;
+	if (freq_list.shared_mac.freq_6GHz)
+		return freq_list.shared_mac.freq_6GHz;
+	if (freq_list.shared_mac.freq_5GHz_high)
+		return freq_list.shared_mac.freq_5GHz_high;
+
+	return freq_list.best_freq;
 }

+ 16 - 27
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.h

@@ -36,18 +36,27 @@
 bool ll_lt_sap_is_supported(void);
 
 /**
- * ll_lt_sap_get_sorted_user_config_acs_ch_list() - API to get sorted user
- * configured channel list
+ * ll_lt_sap_get_freq_list() - API to get frequency list for LL_LT_SAP
  * @psoc: Pointer to psoc object
+ * @freq_list: Pointer to wlan_ll_lt_sap_freq_list structure
  * @vdev_id: Vdev Id
- * @ch_info: Pointer to ch_info
  *
  * Return: QDF_STATUS
  */
-QDF_STATUS ll_lt_sap_get_sorted_user_config_acs_ch_list(
-					struct wlan_objmgr_psoc *psoc,
-					uint8_t vdev_id,
-					struct sap_sel_ch_info *ch_info);
+QDF_STATUS ll_lt_sap_get_freq_list(struct wlan_objmgr_psoc *psoc,
+				   struct wlan_ll_lt_sap_freq_list *freq_list,
+				   uint8_t vdev_id);
+
+/**
+ * ll_lt_sap_get_valid_freq() - API to get valid frequency for LL_LT_SAP
+ * @psoc: Pointer to psoc object
+ * @vdev_id: Vdev Id of ll_lt_sap
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc,
+				    uint8_t vdev_id);
+
 /*
  * ll_lt_sap_init() - Initialize ll_lt_sap infrastructure
  * @vdev: Pointer to vdev
@@ -65,24 +74,4 @@ QDF_STATUS ll_lt_sap_init(struct wlan_objmgr_vdev *vdev);
  * else error code
  */
 QDF_STATUS ll_lt_sap_deinit(struct wlan_objmgr_vdev *vdev);
-
-/**
- * ll_lt_sap_switch_bearer_to_ble() - Switch audio transport to BLE
- * @psoc: Pointer to psoc
- * @bs_request: Pointer to bearer switch request
- * Return: QDF_STATUS_SUCCESS on successful bearer switch else failure
- */
-QDF_STATUS
-ll_lt_sap_switch_bearer_to_ble(struct wlan_objmgr_psoc *psoc,
-			       struct wlan_bearer_switch_request *bs_request);
-
-/**
- * ll_lt_sap_request_for_audio_transport_switch() - Handls audio transport
- * switch request from userspace
- * @req_type: requested transport switch type
- *
- * Return: True/False
- */
-QDF_STATUS ll_lt_sap_request_for_audio_transport_switch(
-					enum bearer_switch_req_type req_type);
 #endif /* _WLAN_LL_SAP_MAIN_H_ */

+ 103 - 2
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_api.h

@@ -16,7 +16,7 @@
 
 /**
  * DOC: contains ll_lt_sap API definitions specific to the bearer
- * switch functionalities
+ * switch, channel selection functionalities
  */
 
 #ifndef _WLAN_LL_LT_SAP_API_H_
@@ -24,10 +24,13 @@
 
 #include <wlan_cmn.h>
 #include <wlan_objmgr_vdev_obj.h>
+#include "wlan_objmgr_psoc_obj.h"
 #include "wlan_ll_sap_public_structs.h"
 #include "wlan_cm_public_struct.h"
+#include "wlan_policy_mgr_public_struct.h"
 
 #ifdef WLAN_FEATURE_LL_LT_SAP
+#ifdef WLAN_FEATURE_BEARER_SWITCH
 /**
  * wlan_ll_lt_sap_bearer_switch_get_id() - Get the request id for bearer switch
  * request
@@ -63,6 +66,38 @@ QDF_STATUS wlan_ll_sap_switch_bearer_on_sta_connect_start(
 						qdf_list_t *scan_list,
 						uint8_t vdev_id,
 						wlan_cm_id cm_id);
+#else
+static inline wlan_bs_req_id
+wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_vdev *vdev)
+{
+	return 0;
+}
+
+static inline QDF_STATUS
+wlan_ll_lt_sap_switch_bearer_to_ble(
+				struct wlan_objmgr_psoc *psoc,
+				struct wlan_bearer_switch_request *bs_request)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
+static inline QDF_STATUS
+wlan_ll_sap_switch_bearer_on_sta_connect_start(struct wlan_objmgr_psoc *psoc,
+					       qdf_list_t *scan_list,
+					       uint8_t vdev_id,
+					       wlan_cm_id cm_id)
+
+{
+	return QDF_STATUS_E_ALREADY;
+}
+
+static inline QDF_STATUS
+wlan_ll_sap_switch_bearer_on_sta_connect_complete(struct wlan_objmgr_psoc *psoc,
+						  uint8_t vdev_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 
 /**
  * wlan_ll_sap_switch_bearer_on_sta_connect_complete() - Switch bearer during
@@ -77,8 +112,57 @@ QDF_STATUS wlan_ll_sap_switch_bearer_on_sta_connect_complete(
 						struct wlan_objmgr_psoc *psoc,
 						uint8_t vdev_id);
 
-#else
+/**
+ * wlan_ll_lt_sap_get_freq_list() - Get frequency list for LL_LT_SAP
+ * @psoc: Pointer to psoc object
+ * @freq_list: Pointer to wlan_ll_lt_sap_freq_list structure
+ * @vdev_id: Vdev Id
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_ll_lt_sap_get_freq_list(
+				struct wlan_objmgr_psoc *psoc,
+				struct wlan_ll_lt_sap_freq_list *freq_list,
+				uint8_t vdev_id);
 
+/**
+ * wlan_ll_lt_sap_override_freq() - Return frequency on which LL_LT_SAP can
+ * be started
+ * @psoc: Pointer to psoc object
+ * @vdev_id: Vdev Id of LL_LT_SAP
+ * @chan_freq: current frequency of ll_lt_sap
+ *
+ * This function checks if ll_lt_sap can come up on the given frequency, if it
+ * can come up on given frequency then return same frequency else return a
+ * different frequency on which ll_lt_sap can come up
+ *
+ * Return: valid ll_lt_sap frequency
+ */
+qdf_freq_t wlan_ll_lt_sap_override_freq(struct wlan_objmgr_psoc *psoc,
+					uint32_t vdev_id,
+					qdf_freq_t chan_freq);
+
+/**
+ * wlan_get_ll_lt_sap_restart_freq() - Get restart frequency on which LL_LT_SAP
+ * can be re-started
+ * @pdev: Pointer to pdev object
+ * @chan_freq: current frequency of ll_lt_sap
+ * @vdev_id: Vdev Id of LL_LT_SAP
+ * @csa_reason: Reason for the CSA
+ *
+ * This function checks if ll_lt_sap needs to be restarted, if yes, it returns
+ * new valid frequency on which ll_lt_sap can be restarted else return same
+ * frequency.
+ *
+ * Return: valid ll_lt_sap frequency
+ */
+qdf_freq_t
+wlan_get_ll_lt_sap_restart_freq(struct wlan_objmgr_pdev *pdev,
+				qdf_freq_t chan_freq,
+				uint8_t vdev_id,
+				enum sap_csa_reason_code *csa_reason);
+
+#else
 static inline wlan_bs_req_id
 wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_vdev *vdev)
 {
@@ -109,5 +193,22 @@ wlan_ll_sap_switch_bearer_on_sta_connect_complete(struct wlan_objmgr_psoc *psoc,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline
+QDF_STATUS wlan_ll_lt_sap_get_freq_list(
+				struct wlan_objmgr_psoc *psoc,
+				struct wlan_ll_lt_sap_freq_list *freq_list,
+				uint8_t vdev_id)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
+static inline
+qdf_freq_t wlan_ll_lt_sap_override_freq(struct wlan_objmgr_psoc *psoc,
+					uint32_t vdev_id,
+					qdf_freq_t chan_freq)
+{
+	return chan_freq;
+}
 #endif /* WLAN_FEATURE_LL_LT_SAP */
 #endif /* _WLAN_LL_LT_SAP_API_H_ */

+ 44 - 6
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_public_structs.h

@@ -16,11 +16,11 @@
 
 /**
  * DOC: contains ll_lt_sap structure definitions specific to the bearer
- * switch functionalities
+ * switch and channel selection functionalities
  */
 
-#ifndef _WLAN_LL_LT_SAP_BEARER_SWITCH_PUBLIC_STRUCTS_H_
-#define _WLAN_LL_LT_SAP_BEARER_SWITCH_PUBLIC_STRUCTS_H_
+#ifndef _WLAN_LL_SAP_PUBLIC_STRUCTS_H_
+#define _WLAN_LL_SAP_PUBLIC_STRUCTS_H_
 
 #include "wlan_objmgr_psoc_obj.h"
 #include <qdf_status.h>
@@ -68,7 +68,46 @@ enum bearer_switch_req_source {
 	BEARER_SWITCH_REQ_MAX,
 };
 
- /**
+/**
+ * struct wlan_ll_lt_sap_mac_freq: LL_LT_SAP mac frequency
+ * @freq_5GHz_low: Low 5GHz frequency
+ * @freq_5GHz_high: High 5GHz frequency
+ * @freq_6GHz: 6GHz frequency
+ * @weight_5GHz_low: Weight of 5GHz low frequency
+ * @weight_5GHz_high: Weight of 5GHz high frequency
+ * @weight_6GHz: Weight of 6GHz frequency
+ */
+struct wlan_ll_lt_sap_mac_freq {
+	qdf_freq_t freq_5GHz_low;
+	qdf_freq_t freq_5GHz_high;
+	qdf_freq_t freq_6GHz;
+	uint32_t weight_5GHz_low;
+	uint32_t weight_5GHz_high;
+	uint32_t weight_6GHz;
+};
+
+/**
+ * struct wlan_ll_lt_sap_freq_list: LL_LT_SAP frequency list structure
+ * @standalone_mac: Select frequency from mac which doesn't have any
+ * concurrent interface present.
+ * @shared_mac: Select frequency from mac which has one concurrent
+ * interface present.
+ * @best_freq: Best freq present in ACS final list. This freq can be
+ * use to bring LL_LT_SAP if none of the above channels are present
+ * @prev_freq: Previous/current freq on which LL_LT_SAP is present.
+ * This will be use to avoid SCC channel selection while updating this
+ * list. This freq should be filled by user.
+ * @weight_best_freq: Weight of best frequency
+ */
+struct wlan_ll_lt_sap_freq_list {
+	struct wlan_ll_lt_sap_mac_freq standalone_mac;
+	struct wlan_ll_lt_sap_mac_freq shared_mac;
+	qdf_freq_t best_freq;
+	qdf_freq_t prev_freq;
+	uint32_t weight_best_freq;
+};
+
+/**
  * typedef bearer_switch_requester_cb() - Callback function, which will
  * be invoked with the bearer switch request status.
  * @psoc: Psoc pointer
@@ -123,5 +162,4 @@ struct ll_sap_ops {
 					struct wlan_objmgr_vdev *vdev,
 					enum bearer_switch_req_type req_type);
 };
-
-#endif /* _WLAN_LL_LT_SAP_BEARER_SWITCH_PUBLIC_STRUCTS_H_ */
+#endif /* _WLAN_LL_SAP_PUBLIC_STRUCTS_H_ */

+ 74 - 5
components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c

@@ -20,7 +20,10 @@
 #include "wlan_cm_api.h"
 #include "wlan_policy_mgr_ll_sap.h"
 #include "wlan_policy_mgr_api.h"
+#include "wlan_reg_services_api.h"
+#include "wlan_dfs_utils_api.h"
 
+#ifdef WLAN_FEATURE_BEARER_SWITCH
 wlan_bs_req_id
 wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_psoc *psoc)
 {
@@ -61,13 +64,13 @@ wlan_ll_sap_switch_bearer_on_sta_connect_start(struct wlan_objmgr_psoc *psoc,
 	qdf_freq_t ll_lt_sap_freq;
 	bool is_bearer_switch_required = false;
 	QDF_STATUS status = QDF_STATUS_E_ALREADY;
-	uint8_t vdev_id;
+	uint8_t ll_lt_sap_vdev_id;
 
-	vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev(psoc);
+	ll_lt_sap_vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc);
 	/* LL_LT SAP is not present, bearer switch is not required */
-	if (vdev_id == WLAN_INVALID_VDEV_ID)
+	if (ll_lt_sap_vdev_id == WLAN_INVALID_VDEV_ID)
 		return status;
-	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, ll_lt_sap_vdev_id,
 						    WLAN_LL_SAP_ID);
 	if (!vdev)
 		return status;
@@ -75,7 +78,7 @@ wlan_ll_sap_switch_bearer_on_sta_connect_start(struct wlan_objmgr_psoc *psoc,
 	if (!scan_list || !qdf_list_size(scan_list))
 		goto rel_ref;
 
-	ll_lt_sap_freq = policy_mgr_get_lt_ll_sap_freq(psoc);
+	ll_lt_sap_freq = policy_mgr_get_ll_lt_sap_freq(psoc);
 	qdf_list_peek_front(scan_list, &cur_node);
 
 	while (cur_node) {
@@ -153,3 +156,69 @@ QDF_STATUS wlan_ll_sap_switch_bearer_on_sta_connect_complete(
 
 	return QDF_STATUS_SUCCESS;
 }
+#endif
+
+QDF_STATUS wlan_ll_lt_sap_get_freq_list(
+				struct wlan_objmgr_psoc *psoc,
+				struct wlan_ll_lt_sap_freq_list *freq_list,
+				uint8_t vdev_id)
+{
+	return ll_lt_sap_get_freq_list(psoc, freq_list, vdev_id);
+}
+
+qdf_freq_t wlan_ll_lt_sap_override_freq(struct wlan_objmgr_psoc *psoc,
+					uint32_t vdev_id,
+					qdf_freq_t chan_freq)
+{
+	qdf_freq_t freq;
+
+	if (!policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id))
+		return chan_freq;
+
+	/*
+	 * If already any concurrent interface is present on this frequency,
+	 * select a different frequency to start ll_lt_sap
+	 */
+	if (!policy_mgr_get_connection_count_with_ch_freq(chan_freq))
+		return chan_freq;
+
+	freq = ll_lt_sap_get_valid_freq(psoc, vdev_id);
+
+	ll_sap_debug("Vdev %d ll_lt_sap old freq %d new freq %d", vdev_id,
+		     chan_freq, freq);
+
+	return freq;
+}
+
+qdf_freq_t wlan_get_ll_lt_sap_restart_freq(struct wlan_objmgr_pdev *pdev,
+					   qdf_freq_t chan_freq,
+					   uint8_t vdev_id,
+					   enum sap_csa_reason_code *csa_reason)
+{
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+	qdf_freq_t restart_freq;
+
+	if (wlan_reg_is_disable_in_secondary_list_for_freq(pdev, chan_freq) &&
+	    !utils_dfs_is_freq_in_nol(pdev, chan_freq)) {
+		*csa_reason = CSA_REASON_CHAN_DISABLED;
+		goto get_new_ll_lt_sap_freq;
+	} else if (wlan_reg_is_passive_for_freq(pdev, chan_freq))  {
+		*csa_reason = CSA_REASON_CHAN_PASSIVE;
+		goto get_new_ll_lt_sap_freq;
+	} else if (!policy_mgr_is_sap_freq_allowed(psoc, chan_freq)) {
+		*csa_reason = CSA_REASON_UNSAFE_CHANNEL;
+		goto get_new_ll_lt_sap_freq;
+	} else if (policy_mgr_is_ll_lt_sap_restart_required(psoc)) {
+		*csa_reason = CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL;
+		goto get_new_ll_lt_sap_freq;
+	}
+
+	return chan_freq;
+
+get_new_ll_lt_sap_freq:
+	restart_freq = ll_lt_sap_get_valid_freq(psoc, vdev_id);
+
+	ll_sap_debug("vdev %d old freq %d restart freq %d CSA reason %d ",
+		     vdev_id, chan_freq, restart_freq, *csa_reason);
+	return restart_freq;
+}

+ 3 - 3
components/umac/twt/core/src/wlan_twt_cfg.c

@@ -446,8 +446,8 @@ wlan_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc)
 
 	twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc);
 
-	if (twt_psoc_obj->twt_pmo_disabled)
+	if (!twt_psoc_obj || twt_psoc_obj->twt_pmo_disabled)
 		return false;
-	else
-		return true;
+
+	return true;
 }

+ 7 - 0
components/umac/twt/dispatcher/inc/wlan_twt_cfg_ext_api.h

@@ -182,5 +182,12 @@ wlan_twt_get_bcast_responder_cfg(struct wlan_objmgr_psoc *psoc, bool *val)
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef FEATURE_SET
+static inline void
+wlan_twt_get_feature_info(struct wlan_objmgr_psoc *psoc,
+			  struct wlan_twt_features *twt_feature_set)
+{
+}
+#endif
 #endif
 #endif

+ 1 - 0
components/umac/twt/dispatcher/src/wlan_twt_cfg_ext_api.c

@@ -85,6 +85,7 @@ void wlan_twt_get_feature_info(struct wlan_objmgr_psoc *psoc,
 		wlan_twt_cfg_get_requestor(
 					psoc,
 					&twt_feature_set->enable_twt_requester);
+		twt_feature_set->enable_twt_flexible = true;
 	}
 }
 #endif

+ 5 - 10
components/wmi/src/wmi_unified_roam_tlv.c

@@ -224,6 +224,7 @@ static QDF_STATUS send_roam_scan_offload_rssi_thresh_cmd_tlv(
 	rssi_threshold_fp->hirssi_upper_bound = roam_req->hi_rssi_scan_rssi_ub;
 	rssi_threshold_fp->rssi_thresh_offset_5g =
 		roam_req->rssi_thresh_offset_5g;
+	rssi_threshold_fp->flags = roam_req->flags;
 
 	buf_ptr += sizeof(wmi_roam_scan_rssi_threshold_fixed_param);
 	WMITLV_SET_HDR(buf_ptr,
@@ -3016,18 +3017,14 @@ extract_roam_stats_with_single_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 {
 	QDF_STATUS status;
 	uint8_t vdev_id = stats_info->vdev_id;
-	uint8_t band;
 
 	status = wmi_unified_extract_roam_scan_stats(
 			wmi_handle, evt_buf, &stats_info->scan[0], 0, 0, 0);
 	if (QDF_IS_STATUS_ERROR(status))
 		wmi_debug("Roam scan stats extract failed vdev %d", vdev_id);
 
-	band = stats_info->scan[0].band;
-
 	status = wmi_unified_extract_roam_11kv_stats(
-			wmi_handle, evt_buf, &stats_info->data_11kv[0], 0, 0,
-			band);
+			wmi_handle, evt_buf, &stats_info->data_11kv[0], 0, 0);
 	if (QDF_IS_STATUS_ERROR(status))
 		wmi_debug("Roam 11kv stats extract failed vdev %d", vdev_id);
 
@@ -3065,7 +3062,7 @@ extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 	struct roam_msg_info *roam_msg_info = NULL;
 	uint8_t vdev_id, i, num_btm = 0, num_frames = 0;
 	uint8_t num_tlv = 0, num_chan = 0, num_ap = 0, num_rpt = 0;
-	uint8_t num_trigger_reason = 0, band;
+	uint8_t num_trigger_reason = 0;
 	uint32_t rem_len;
 	QDF_STATUS status;
 
@@ -3254,14 +3251,12 @@ extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 			}
 		}
 
-		band = stats_info->scan[i].band;
-
 		/* BTM req/resp or Neighbor report/response info */
 		status = wmi_unified_extract_roam_11kv_stats(
 				      wmi_handle,
 				      evt_buf,
 				      &stats_info->data_11kv[i],
-				      i, num_rpt, band);
+				      i, num_rpt);
 		if (QDF_IS_STATUS_ERROR(status))
 			wmi_debug_rl("Roam 11kv stats extract fail vdev %d iter %d",
 				     vdev_id, i);
@@ -4137,7 +4132,7 @@ free_keys:
 			continue;
 
 		wmi_debug("Free key allocated at idx:%d", k);
-		qdf_mem_zero(key_alloc_buf[k], sizeof(key_alloc_buf[k]));
+		qdf_mem_zero(key_alloc_buf[k], sizeof(*key_alloc_buf[k]));
 		qdf_mem_free(key_alloc_buf[k]);
 	}
 

+ 7 - 2
configs/default_defconfig

@@ -164,6 +164,7 @@ endif
 	CONFIG_DP_MULTIPASS_SUPPORT := y
 	CONFIG_WLAN_DP_VDEV_NO_SELF_PEER := y
 	CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY := y
+	CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET := y
 endif
 
 ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM)))
@@ -427,7 +428,11 @@ endif
 CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y
 
 #Disable the Export Symbol config
+ifeq ($(CONFIG_WLAN_MULTI_CHIP_SUPPORT), y)
 CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := n
+else
+CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y
+endif
 
 CONFIG_QCACLD_FEATURE_GREEN_AP := y
 
@@ -1242,6 +1247,8 @@ CONFIG_CONNECTION_ROAMING_CFG := n
 
 CONFIG_FEATURE_SET := y
 
+CONFIG_WLAN_FEATURE_LL_LT_SAP := y
+
 CONFIG_WIFI_POS_CONVERGED := y
 CONFIG_WLAN_TWT_CONVERGED := y
 ifneq ($(CONFIG_WIFI_POS_CONVERGED), y)
@@ -1442,9 +1449,7 @@ ifeq ($(CONFIG_ARCH_MDM9607), y)
 CONFIG_TUFELLO_DUAL_FW_SUPPORT := y
 endif
 
-ifeq ($(CONFIG_ARCH_MSM8996), y)
 CONFIG_CHANNEL_HOPPING_ALL_BANDS := y
-endif
 
 ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515)))
 	ifneq ($(CONFIG_SLUB_DEBUG), y)

+ 4 - 0
configs/kiwi_v2_defconfig

@@ -107,9 +107,13 @@ CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y
 CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 256
 CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 128
 
+CONFIG_WLAN_FEATURE_COAP := n
+
 endif # ARCH_SDXPINN
 
 ifeq ($(CONFIG_ARCH_PINEAPPLE), y)
 CONFIG_WLAN_TX_MON_2_0 := y
 CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE := y
 endif
+
+CONFIG_WLAN_FEATURE_LL_LT_SAP := y

+ 3 - 0
configs/pineapple_gki_kiwi-v2_defconfig

@@ -393,3 +393,6 @@ CONFIG_CNSS_OUT_OF_TREE=y
 CONFIG_SMP=y
 CONFIG_RPS=y
 CONFIG_BCN_RATECODE_ENABLE=y
+CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y
+CONFIG_WLAN_MULTI_CHIP_SUPPORT=y
+CONFIG_WLAN_FEATURE_LL_LT_SAP=y

+ 2 - 0
configs/pineapple_gki_peach_defconfig

@@ -392,3 +392,5 @@ CONFIG_SMP=y
 CONFIG_RPS=y
 CONFIG_BCN_RATECODE_ENABLE=y
 CONFIG_4_BYTES_TLV_TAG=y
+CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y
+CONFIG_WLAN_MULTI_CHIP_SUPPORT=y

+ 2 - 0
configs/qca6390_defconfig

@@ -625,6 +625,8 @@ CONFIG_DISABLE_CHANNEL_LIST :=y
 #Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode)
 CONFIG_WLAN_DYNAMIC_CVM := y
 
+CONFIG_FEATURE_SET := y
+
 CONFIG_WIFI_POS_CONVERGED := y
 ifneq ($(CONFIG_WIFI_POS_CONVERGED), y)
 CONFIG_WIFI_POS_LEGACY := y

+ 2 - 0
configs/sun_gki_kiwi-v2_defconfig

@@ -393,3 +393,5 @@ CONFIG_CNSS_OUT_OF_TREE=y
 CONFIG_SMP=y
 CONFIG_RPS=y
 CONFIG_BCN_RATECODE_ENABLE=y
+CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y
+CONFIG_WLAN_MULTI_CHIP_SUPPORT=y

+ 2 - 0
configs/sun_gki_peach_defconfig

@@ -392,3 +392,5 @@ CONFIG_SMP=y
 CONFIG_RPS=y
 CONFIG_BCN_RATECODE_ENABLE=y
 CONFIG_4_BYTES_TLV_TAG=y
+CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y
+CONFIG_WLAN_MULTI_CHIP_SUPPORT=y

+ 1 - 0
core/bmi/src/ol_fw.c

@@ -1723,6 +1723,7 @@ void ol_dump_target_memory(struct hif_opaque_softc *scn, void *memory_block)
 		case 1:
 			address = AXI_LOCATION;
 			size = AXI_SIZE;
+			break;
 		default:
 			break;
 		}

+ 6 - 0
core/dp/htt/htt_rx_ll.c

@@ -562,6 +562,12 @@ static int htt_rx_ring_size(struct htt_pdev_t *pdev)
 
 	size = qdf_get_pwr2(size);
 
+	if (!soc) {
+		QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR,
+		  "Unable to get 2x2 cap soc is NULL ring size:%u selected ", size);
+		return size;
+	}
+
 	status = wlan_mlme_get_vht_enable2x2((void *)soc->psoc, &enable_2x2);
 	if (QDF_IS_STATUS_SUCCESS(status))
 		size = (enable_2x2) ? size : QDF_MIN(size, HTT_RX_RING_SIZE_1x1);

+ 62 - 8
core/hdd/src/wlan_hdd_cfg.c

@@ -2446,8 +2446,15 @@ int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 	struct sme_config_params *sme_config;
 	int ret;
 	enum phy_ch_width ch_width = CH_WIDTH_INVALID;
+	struct wlan_objmgr_vdev *link_vdev;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_hdd_link_info *link_info_t;
+	bool is_mlo_link = false;
+	uint8_t link_vdev_id;
+	enum QDF_OPMODE op_mode;
 	QDF_STATUS status;
 	uint8_t vdev_id = link_info->vdev_id;
+	enum phy_ch_width new_ch_width;
 
 	hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
 	if (!hdd_ctx) {
@@ -2455,18 +2462,65 @@ int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 		return -EINVAL;
 	}
 
+	vdev = link_info->vdev;
+	if (!vdev) {
+		mlme_legacy_err("vdev %d: vdev not found", vdev_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev) && link_id != 0xFF) {
+		link_vdev = mlo_get_vdev_by_link_id(vdev, link_id,
+						    WLAN_MLME_OBJMGR_ID);
+		if (!link_vdev) {
+			mlme_legacy_debug("vdev is null for the link id:%u",
+					  link_id);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+			return QDF_STATUS_E_FAILURE;
+		}
+		is_mlo_link = true;
+		link_vdev_id = wlan_vdev_get_id(link_vdev);
+		status = wlan_mlme_get_bw_no_punct(hdd_ctx->psoc,
+						   link_vdev,
+						   wlan_vdev_mlme_get_des_chan(link_vdev),
+						   &new_ch_width);
+		if (QDF_IS_STATUS_SUCCESS(status) && ch_width > new_ch_width)
+			ch_width = new_ch_width;
+	} else {
+		link_vdev = vdev;
+		link_vdev_id = vdev_id;
+		mlme_legacy_debug("vdev mlme is not mlo vdev");
+	}
+
+	link_info_t = hdd_get_link_info_by_vdev(hdd_ctx, link_vdev_id);
+	if (!link_info_t) {
+		mlme_legacy_debug("vdev mlme is not mlo vdev");
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	if (ucfg_mlme_is_chwidth_with_notify_supported(hdd_ctx->psoc) &&
-	    hdd_cm_is_vdev_connected(link_info)) {
+	    hdd_cm_is_vdev_connected(link_info_t)) {
+		op_mode = wlan_vdev_mlme_get_opmode(vdev);
+		if (op_mode != QDF_STA_MODE) {
+			mlme_legacy_debug("vdev %d: op mode %d, CW update not supported",
+				          link_vdev_id, op_mode);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+			return QDF_STATUS_E_NOSUPPORT;
+		}
+
 		ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth);
 		hdd_debug("vdev %d : process update ch width request to %d",
-			  vdev_id, ch_width);
+			  link_vdev_id, ch_width);
+
 		status = ucfg_mlme_send_ch_width_update_with_notify(hdd_ctx->psoc,
-								    vdev_id,
+								    link_vdev,
 								    ch_width,
-								    link_id);
+								    link_vdev_id);
+		if (is_mlo_link)
+			wlan_objmgr_vdev_release_ref(link_vdev,
+						     WLAN_MLME_OBJMGR_ID);
 		if (QDF_IS_STATUS_ERROR(status))
 			return -EIO;
-		status = hdd_update_bss_rate_flags(link_info, hdd_ctx->psoc,
+		status = hdd_update_bss_rate_flags(link_info_t, hdd_ctx->psoc,
 						   ch_width);
 		if (QDF_IS_STATUS_ERROR(status))
 			return -EIO;
@@ -2476,7 +2530,7 @@ int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 	if (!sme_config)
 		return -ENOMEM;
 
-	ret = wma_cli_set_command(vdev_id, wmi_vdev_param_chwidth,
+	ret = wma_cli_set_command(link_vdev_id, wmi_vdev_param_chwidth,
 				  chwidth, VDEV_CMD);
 	if (ret)
 		goto free_config;
@@ -2492,8 +2546,8 @@ int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
 		sme_config->csr_config.channelBondingMode24GHz = bonding_mode;
 	}
 	sme_update_config(hdd_ctx->mac_handle, sme_config);
-	sme_set_he_bw_cap(hdd_ctx->mac_handle, vdev_id, chwidth);
-	sme_set_eht_bw_cap(hdd_ctx->mac_handle, vdev_id, chwidth);
+	sme_set_he_bw_cap(hdd_ctx->mac_handle, link_vdev_id, chwidth);
+	sme_set_eht_bw_cap(hdd_ctx->mac_handle, link_vdev_id, chwidth);
 free_config:
 	qdf_mem_free(sme_config);
 	return ret;

+ 159 - 10
core/hdd/src/wlan_hdd_cfg80211.c

@@ -212,6 +212,7 @@
 #include <wlan_mlo_mgr_link_switch.h>
 #include <wlan_hdd_ll_lt_sap.h>
 #include "wlan_cp_stats_mc_defs.h"
+#include "wlan_policy_mgr_ll_sap.h"
 
 /*
  * A value of 100 (milliseconds) can be sent to FW.
@@ -5774,6 +5775,7 @@ roam_control_policy[QCA_ATTR_ROAM_CONTROL_MAX + 1] = {
 			.type = NLA_U8},
 	[QCA_ATTR_ROAM_CONTROL_FULL_SCAN_6GHZ_ONLY_ON_PRIOR_DISCOVERY] = {
 			.type = NLA_U8},
+	[QCA_ATTR_ROAM_CONTROL_CONNECTED_HIGH_RSSI_OFFSET] = {.type = NLA_U8},
 };
 
 /**
@@ -6551,6 +6553,31 @@ hdd_set_roam_with_control_config(struct hdd_context *hdd_ctx,
 			hdd_err("Fail to decide inclusion of 6 GHz channels");
 	}
 
+	attr = tb2[QCA_ATTR_ROAM_CONTROL_CONNECTED_HIGH_RSSI_OFFSET];
+	if (attr) {
+		value = nla_get_u8(attr);
+		if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HI_RSSI_DELTA, value)) {
+			hdd_err("High RSSI offset value %d is out of range",
+				value);
+			return -EINVAL;
+		}
+
+		hdd_debug("%s roam scan high RSSI with offset: %d for vdev %d",
+			  value ? "Enable" : "Disable", value, vdev_id);
+
+		if (!value &&
+		    !wlan_cm_get_roam_scan_high_rssi_offset(hdd_ctx->psoc)) {
+			hdd_debug("Roam scan high RSSI is already disabled");
+			return -EINVAL;
+		}
+
+		status = ucfg_cm_set_roam_scan_high_rssi_offset(hdd_ctx->psoc,
+								vdev_id, value);
+		if (QDF_IS_STATUS_ERROR(status))
+			hdd_err("Fail to set roam scan high RSSI offset for vdev %d",
+				vdev_id);
+	}
+
 	return qdf_status_to_os_return(status);
 }
 
@@ -9881,8 +9908,13 @@ static int hdd_config_power(struct wlan_hdd_link_info *link_info,
 		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL];
 	int ret;
 
-	if (!power_attr && !opm_attr)
+	hdd_enter_dev(adapter->dev);
+
+	if (!power_attr && !opm_attr) {
+		hdd_err_rl("power attr and opm attr is null");
 		return 0;
+	}
+
 
 	if (power_attr && opm_attr) {
 		hdd_err_rl("Invalid OPM set attribute");
@@ -9895,11 +9927,14 @@ static int hdd_config_power(struct wlan_hdd_link_info *link_info,
 	}
 
 	opm_mode = power_attr ? nla_get_u8(power_attr) : nla_get_u8(opm_attr);
-	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED)
+	hdd_debug("opm_mode %d", opm_mode);
+
+	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED) {
 		if (!ps_ito_attr || !spec_wake_attr) {
 			hdd_err_rl("Invalid User defined OPM attributes");
 			return -EINVAL;
 		}
+	}
 
 	ret = hdd_set_power_config(hdd_ctx, adapter, &opm_mode);
 	if (ret)
@@ -9909,19 +9944,34 @@ static int hdd_config_power(struct wlan_hdd_link_info *link_info,
 	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED) {
 		ps_params.ps_ito = nla_get_u16(ps_ito_attr);
 		ps_params.spec_wake = nla_get_u16(spec_wake_attr);
+
+		if (!ps_params.ps_ito)
+			return -EINVAL;
+
+		hdd_debug("ps_ito %d spec_wake %d opm_mode %d",
+			  ps_params.ps_ito, ps_params.spec_wake,
+			  ps_params.opm_mode);
+
 		ret = hdd_set_power_config_params(hdd_ctx, adapter,
 						  ps_params.ps_ito,
 						  ps_params.spec_wake);
+
 		if (ret)
 			return ret;
 	}
 
 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_POWER_ID);
-	if (vdev) {
-		ucfg_pmo_set_ps_params(vdev, &ps_params);
-		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
+	if (!vdev) {
+		hdd_err("vdev is null");
+		return 0;
 	}
 
+	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED)
+		ucfg_pmo_set_ps_params(vdev, &ps_params);
+	else
+		ucfg_pmo_core_vdev_set_ps_opm_mode(vdev, ps_params.opm_mode);
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
 	return 0;
 }
 
@@ -11099,7 +11149,7 @@ skip_mlo:
 		return -EINVAL;
 	}
 set_chan_width:
-	return hdd_set_mac_chan_width(link_info, chwidth, link_id, false);
+	return hdd_set_mac_chan_width(link_info, chwidth, link_id, true);
 }
 
 /**
@@ -11697,6 +11747,27 @@ hdd_test_config_emlsr_action_mode(struct hdd_adapter *adapter,
 #endif
 
 #ifdef WLAN_FEATURE_11BE
+/**
+ * hdd_set_eht_emlsr_capability() - Set EMLSR capability for EHT STA
+ * @link_info: Link info pointer in HDD adapter
+ * @attr: pointer to nla attr
+ *
+ * Return: 0 on success, negative on failure
+ */
+static int
+hdd_set_eht_emlsr_capability(struct wlan_hdd_link_info *link_info,
+			     const struct nlattr *attr)
+{
+	uint8_t cfg_val;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+
+	cfg_val = nla_get_u8(attr);
+	hdd_debug("EMLSR capable: %d", cfg_val);
+	hdd_test_config_emlsr_mode(hdd_ctx, cfg_val);
+
+	return 0;
+}
+
 /**
  * hdd_set_eht_max_simultaneous_links() - Set EHT maximum number of
  * simultaneous links
@@ -11799,6 +11870,13 @@ static int hdd_set_eht_mlo_mode(struct wlan_hdd_link_info *link_info,
 	return 0;
 }
 #else
+static inline int
+hdd_set_eht_emlsr_capability(struct wlan_hdd_link_info *link_info,
+			     const struct nlattr *attr)
+{
+	return 0;
+}
+
 static inline int
 hdd_set_eht_max_simultaneous_links(struct wlan_hdd_link_info *link_info,
 				   const struct nlattr *attr)
@@ -12159,6 +12237,8 @@ static const struct independent_setters independent_setters[] = {
 
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_WFC_STATE,
 	 hdd_set_wfc_state},
+	{QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_EML_CAPABILITY,
+	 hdd_set_eht_emlsr_capability},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_SIMULTANEOUS_LINKS,
 	 hdd_set_eht_max_simultaneous_links},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_CAPABILITY,
@@ -12458,7 +12538,6 @@ static int hdd_get_channel_width(struct wlan_hdd_link_info *link_info,
 	if (!vdev)
 		return -EINVAL;
 
-
 	bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
 	if (!bss_chan) {
 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
@@ -14151,9 +14230,8 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 		} else {
 			hdd_update_channel_width(
 					link_info, eHT_CHANNEL_WIDTH_160MHZ,
-					link_id,
 					WNI_CFG_CHANNEL_BONDING_MODE_ENABLE,
-					false);
+					link_id, false);
 			hdd_set_tx_stbc(link_info, 1);
 			hdd_set_11ax_rate(adapter, 0xFFFF, NULL);
 			status = wma_cli_set_command(
@@ -21773,6 +21851,65 @@ static void wlan_hdd_set_mfp_optional(struct wiphy *wiphy)
 }
 #endif
 
+/**
+ * wlan_hdd_iface_debug_string() - This API converts IFACE type to string
+ * @iface_type: interface type
+ *
+ * Return: name string
+ */
+static char *wlan_hdd_iface_debug_string(uint32_t iface_type)
+{
+	if (iface_type == BIT(NL80211_IFTYPE_STATION))
+		return "STA";
+	else if (iface_type == BIT(NL80211_IFTYPE_AP))
+		return "SAP";
+	else if (iface_type == (BIT(NL80211_IFTYPE_P2P_CLIENT) |
+		 BIT(NL80211_IFTYPE_P2P_GO)))
+		return "(P2P_CLI or P2P_GO)";
+	else if (iface_type == BIT(NL80211_IFTYPE_P2P_CLIENT))
+		return "P2P_CLIENT";
+	else if (iface_type == BIT(NL80211_IFTYPE_P2P_GO))
+		return "P2P_GO";
+	else if (iface_type == BIT(NL80211_IFTYPE_NAN))
+		return "NAN";
+	else if (iface_type == BIT(NL80211_IFTYPE_MONITOR))
+		return "MONITOR";
+
+	return "invalid iface";
+}
+
+#define IFACE_DUMP_SIZE 100
+/**
+ * wlan_hdd_dump_iface_combinations() - This API prints the IFACE combinations
+ * @num: number of combinations
+ * @combination: pointer to iface combination structure
+ *
+ * Return: void
+ */
+static void wlan_hdd_dump_iface_combinations(uint32_t num,
+			const struct ieee80211_iface_combination *combination)
+{
+	int i, j;
+	char buf[IFACE_DUMP_SIZE] = {0};
+	uint8_t len = 0;
+
+	hdd_debug("max combinations %d", num);
+
+	for (i = 0; i < num; i++) {
+		for (j = 0; j < combination[i].max_interfaces; j++) {
+			if (combination[i].limits[j].types)
+				len += qdf_scnprintf(buf + len,
+						     IFACE_DUMP_SIZE - len,
+						     " + %s",
+					wlan_hdd_iface_debug_string(
+					combination[i].limits[j].types));
+		}
+
+		hdd_nofl_debug("iface combination[%d]: %s", i, buf);
+		len = 0;
+	}
+}
+
 /*
  * In this function, wiphy structure is updated after QDF
  * initialization. In wlan_hdd_cfg80211_init, only the
@@ -21868,6 +22005,9 @@ void wlan_hdd_update_wiphy(struct hdd_context *hdd_ctx)
 		}
 
 		wiphy->n_iface_combinations = iface_num;
+
+		wlan_hdd_dump_iface_combinations(wiphy->n_iface_combinations,
+						 wiphy->iface_combinations);
 	}
 
 	mac_spoofing_enabled = ucfg_scan_is_mac_spoofing_enabled(hdd_ctx->psoc);
@@ -28097,6 +28237,7 @@ static int __wlan_hdd_cfg80211_set_chainmask(struct wiphy *wiphy,
 	enum hdd_chain_mode chains;
 	struct dev_set_param setparam[MAX_PDEV_TXRX_PARAMS] = {};
 	uint8_t index = 0;
+	uint8_t ll_lt_sap_vdev_id;
 
 	ret = wlan_hdd_validate_context(hdd_ctx);
 	if (ret)
@@ -28116,6 +28257,14 @@ static int __wlan_hdd_cfg80211_set_chainmask(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
+	ll_lt_sap_vdev_id =
+			wlan_policy_mgr_get_ll_lt_sap_vdev_id(hdd_ctx->psoc);
+	if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) {
+		hdd_info_rl("LL_LT_SAP vdev %d present, chainmask config not allowed",
+			    ll_lt_sap_vdev_id);
+		return -ENOTSUPP;
+	}
+
 	if (sme_validate_txrx_chain_mask(wmi_pdev_param_tx_chain_mask, tx_mask))
 		return -EINVAL;
 
@@ -28640,7 +28789,7 @@ static int __wlan_hdd_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
 			nss = 0;
 			if (band == NL80211_BAND_5GHZ)
 				rate_index += 4;
-			if (rate_index >= 0 && rate_index < 4)
+			if (rate_index < 4)
 				bit_rate = hdd_assemble_rate_code(
 					WMI_RATE_PREAMBLE_CCK, nss,
 					hdd_legacy_rates[rate_index].hw_value);

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

@@ -31,6 +31,7 @@
 #include "wlan_cfr_ucfg_api.h"
 #include "wlan_hdd_object_manager.h"
 #include "wlan_cmn.h"
+#include "wlan_policy_mgr_ll_sap.h"
 
 const struct nla_policy cfr_config_policy[
 		QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1] = {
@@ -716,6 +717,7 @@ static int __wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy,
 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
 	struct net_device *dev = wdev->netdev;
 	struct hdd_adapter *adapter;
+	uint8_t ll_lt_sap_vdev_id;
 
 	hdd_enter();
 
@@ -732,6 +734,14 @@ static int __wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy,
 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
 		return -EINVAL;
 
+	ll_lt_sap_vdev_id =
+			wlan_policy_mgr_get_ll_lt_sap_vdev_id(hdd_ctx->psoc);
+	if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) {
+		hdd_info_rl("LL_LT_SAP vdev %d present, cfr cmd not allowed",
+			     ll_lt_sap_vdev_id);
+		return -EINVAL;
+	}
+
 	wlan_cfg80211_peer_cfr_capture_cfg(wiphy, adapter,
 					   data, data_len);
 

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

@@ -1680,11 +1680,6 @@ hdd_cm_connect_success_pre_user_update(struct wlan_objmgr_vdev *vdev,
 			if (is_auth_required)
 				wlan_acquire_peer_key_wakelock(hdd_ctx->pdev,
 							      rsp->bssid.bytes);
-			/*
-			 * In case of roaming from 3 Link or 2 Link to 1 link
-			 * AP, then reset the STA context for other links
-			 */
-			hdd_adapter_reset_station_ctx(adapter);
 		}
 		hdd_debug("is_roam_offload %d, is_roam %d, is_auth_required %d",
 			  is_roam_offload, is_roam, is_auth_required);

+ 49 - 1
core/hdd/src/wlan_hdd_connectivity_logging.c

@@ -1299,6 +1299,48 @@ void wlan_hdd_start_connectivity_logging(struct hdd_context *hdd_ctx)
 #endif
 
 #ifdef CONNECTIVITY_DIAG_EVENT
+static enum wlan_diag_connect_fail_reason
+wlan_hdd_convert_con_fail_reason_to_diag_reason(
+				enum wlan_cm_connect_fail_reason reason)
+{
+	switch (reason) {
+	case CM_NO_CANDIDATE_FOUND:
+		return WLAN_DIAG_NO_CANDIDATE_FOUND;
+	case CM_ABORT_DUE_TO_NEW_REQ_RECVD:
+		return WLAN_DIAG_ABORT_DUE_TO_NEW_REQ_RECVD;
+	case CM_BSS_SELECT_IND_FAILED:
+		return WLAN_DIAG_BSS_SELECT_IND_FAILED;
+	case CM_PEER_CREATE_FAILED:
+		return WLAN_DIAG_PEER_CREATE_FAILED;
+	case CM_JOIN_FAILED:
+		return WLAN_DIAG_JOIN_FAILED;
+	case CM_JOIN_TIMEOUT:
+		return WLAN_DIAG_JOIN_TIMEOUT;
+	case CM_AUTH_FAILED:
+		return WLAN_DIAG_AUTH_FAILED;
+	case CM_AUTH_TIMEOUT:
+		return WLAN_DIAG_AUTH_TIMEOUT;
+	case CM_ASSOC_FAILED:
+		return WLAN_DIAG_ASSOC_FAILED;
+	case CM_ASSOC_TIMEOUT:
+		return WLAN_DIAG_ASSOC_TIMEOUT;
+	case CM_HW_MODE_FAILURE:
+		return WLAN_DIAG_HW_MODE_FAILURE;
+	case CM_SER_FAILURE:
+		return WLAN_DIAG_SER_FAILURE;
+	case CM_SER_TIMEOUT:
+		return WLAN_DIAG_SER_TIMEOUT;
+	case CM_GENERIC_FAILURE:
+		return WLAN_DIAG_GENERIC_FAILURE;
+	case CM_VALID_CANDIDATE_CHECK_FAIL:
+		return WLAN_DIAG_VALID_CANDIDATE_CHECK_FAIL;
+	default:
+		hdd_err("Invalid connect fail reason code");
+	}
+
+	return WLAN_DIAG_UNSPECIFIC_REASON;
+}
+
 void
 wlan_hdd_connectivity_fail_event(struct wlan_objmgr_vdev *vdev,
 				 struct wlan_cm_connect_resp *rsp)
@@ -1310,6 +1352,11 @@ wlan_hdd_connectivity_fail_event(struct wlan_objmgr_vdev *vdev,
 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
 		return;
 
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	    (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) ||
+	     wlan_vdev_mlme_is_mlo_link_vdev(vdev)))
+		return;
+
 	wlan_diag_event.diag_cmn.vdev_id = wlan_vdev_get_id(vdev);
 
 	wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us();
@@ -1320,7 +1367,8 @@ wlan_hdd_connectivity_fail_event(struct wlan_objmgr_vdev *vdev,
 
 	wlan_diag_event.version = DIAG_CONN_VERSION;
 	wlan_diag_event.freq = rsp->freq;
-	wlan_diag_event.reason = rsp->reason;
+	wlan_diag_event.reason =
+	wlan_hdd_convert_con_fail_reason_to_diag_reason(rsp->reason);
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_CONN);
 }

+ 100 - 97
core/hdd/src/wlan_hdd_driver_ops.c

@@ -202,18 +202,6 @@ void hdd_dp_prealloc_put_multi_pages(uint32_t desc_type,
 }
 #endif
 
-/**
- * hdd_set_recovery_in_progress() - API to set recovery in progress
- * @data: Context
- * @val: Value to set
- *
- * Return: None
- */
-static void hdd_set_recovery_in_progress(void *data, uint8_t val)
-{
-	cds_set_recovery_in_progress(val);
-}
-
 /**
  * hdd_is_driver_unloading() - API to query if driver is unloading
  * @data: Private Data
@@ -289,6 +277,106 @@ static void hdd_send_driver_ready_to_user(void)
 	wlan_cfg80211_vendor_event(nl_event, flags);
 }
 
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+/**
+ * hdd_wlan_ssr_shutdown_event()- send ssr shutdown state
+ *
+ * This Function sends ssr shutdown state diag event
+ *
+ * Return: void.
+ */
+static void hdd_wlan_ssr_shutdown_event(void)
+{
+	WLAN_HOST_DIAG_EVENT_DEF(ssr_shutdown,
+				 struct host_event_wlan_ssr_shutdown);
+	qdf_mem_zero(&ssr_shutdown, sizeof(ssr_shutdown));
+	ssr_shutdown.status = SSR_SUB_SYSTEM_SHUTDOWN;
+	WLAN_HOST_DIAG_EVENT_REPORT(&ssr_shutdown,
+					EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM);
+}
+#else
+static inline void hdd_wlan_ssr_shutdown_event(void) { }
+#endif
+
+/**
+ * hdd_psoc_shutdown_notify() - notify the various interested parties that the
+ *	soc is starting recovery shutdown
+ * @hdd_ctx: the HDD context corresponding to the soc undergoing shutdown
+ *
+ * Return: None
+ */
+static void hdd_psoc_shutdown_notify(struct hdd_context *hdd_ctx)
+{
+	hdd_enter();
+	wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL);
+
+	if (ucfg_ipa_is_enabled()) {
+		ucfg_ipa_uc_force_pipe_shutdown(hdd_ctx->pdev);
+
+		if (pld_is_fw_rejuvenate(hdd_ctx->parent_dev) ||
+		    pld_is_pdr(hdd_ctx->parent_dev))
+			ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev);
+	}
+
+	cds_shutdown_notifier_call();
+	cds_shutdown_notifier_purge();
+
+	hdd_wlan_ssr_shutdown_event();
+	hdd_exit();
+}
+
+/**
+ * hdd_soc_recovery_cleanup() - Perform SSR related cleanup activities.
+ *
+ * This function will perform cleanup activities related to when driver
+ * undergoes SSR. Activities include stopping idle timer and invoking shutdown
+ * notifier.
+ *
+ * Return: None
+ */
+static void hdd_soc_recovery_cleanup(void)
+{
+	struct hdd_context *hdd_ctx;
+
+	hdd_enter();
+	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	if (!hdd_ctx)
+		return;
+
+	/* cancel/flush any pending/active idle shutdown work */
+	hdd_psoc_idle_timer_stop(hdd_ctx);
+	ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc);
+
+	/* nothing to do if the soc is already unloaded */
+	if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
+		hdd_info("Driver modules are already closed");
+		return;
+	}
+
+	if (cds_is_load_or_unload_in_progress()) {
+		hdd_info("Load/unload in progress, ignore SSR shutdown");
+		return;
+	}
+
+	hdd_psoc_shutdown_notify(hdd_ctx);
+	hdd_exit();
+}
+
+/**
+ * hdd_set_recovery_in_progress() - API to set recovery in progress
+ * @data: Context
+ * @val: Value to set
+ *
+ * Return: None
+ */
+static void hdd_set_recovery_in_progress(void *data, uint8_t val)
+{
+	cds_set_recovery_in_progress(val);
+	/* SSR can be triggred late cleanup existing queue for kernel handshake */
+	if (!qdf_in_interrupt())
+		hdd_soc_recovery_cleanup();
+}
+
 /**
  * hdd_hif_init_driver_state_callbacks() - API to initialize HIF callbacks
  * @data: Private Data
@@ -977,27 +1065,6 @@ static void hdd_soc_remove(struct device *dev)
 	__hdd_soc_remove(dev);
 }
 
-#ifdef FEATURE_WLAN_DIAG_SUPPORT
-/**
- * hdd_wlan_ssr_shutdown_event()- send ssr shutdown state
- *
- * This Function send send ssr shutdown state diag event
- *
- * Return: void.
- */
-static void hdd_wlan_ssr_shutdown_event(void)
-{
-	WLAN_HOST_DIAG_EVENT_DEF(ssr_shutdown,
-					struct host_event_wlan_ssr_shutdown);
-	qdf_mem_zero(&ssr_shutdown, sizeof(ssr_shutdown));
-	ssr_shutdown.status = SSR_SUB_SYSTEM_SHUTDOWN;
-	WLAN_HOST_DIAG_EVENT_REPORT(&ssr_shutdown,
-					EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM);
-}
-#else
-static inline void hdd_wlan_ssr_shutdown_event(void) { }
-#endif
-
 /**
  * hdd_send_hang_data() - Send hang data to userspace
  * @data: Hang data
@@ -1018,70 +1085,6 @@ static void hdd_send_hang_data(uint8_t *data, size_t data_len)
 	wlan_hdd_send_hang_reason_event(hdd_ctx, reason, data, data_len);
 }
 
-/**
- * hdd_psoc_shutdown_notify() - notify the various interested parties that the
- *	soc is starting recovery shutdown
- * @hdd_ctx: the HDD context corresponding to the soc undergoing shutdown
- *
- * Return: None
- */
-static void hdd_psoc_shutdown_notify(struct hdd_context *hdd_ctx)
-{
-	hdd_enter();
-	wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL);
-
-	if (ucfg_ipa_is_enabled()) {
-		ucfg_ipa_uc_force_pipe_shutdown(hdd_ctx->pdev);
-
-		if (pld_is_fw_rejuvenate(hdd_ctx->parent_dev) ||
-		    pld_is_pdr(hdd_ctx->parent_dev))
-			ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev);
-	}
-
-	cds_shutdown_notifier_call();
-	cds_shutdown_notifier_purge();
-
-	hdd_wlan_ssr_shutdown_event();
-	hdd_exit();
-}
-
-/**
- * hdd_soc_recovery_cleanup() - Perform SSR related cleanup activities.
- *
- * This function will perform cleanup activities related to when driver
- * undergoes SSR. Activities include stopping idle timer and invoking shutdown
- * notifier.
- *
- * Return: None
- */
-static void hdd_soc_recovery_cleanup(void)
-{
-	struct hdd_context *hdd_ctx;
-
-	hdd_enter();
-	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
-	if (!hdd_ctx)
-		return;
-
-	/* cancel/flush any pending/active idle shutdown work */
-	hdd_psoc_idle_timer_stop(hdd_ctx);
-	ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc);
-
-	/* nothing to do if the soc is already unloaded */
-	if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
-		hdd_info("Driver modules are already closed");
-		return;
-	}
-
-	if (cds_is_load_or_unload_in_progress()) {
-		hdd_info("Load/unload in progress, ignore SSR shutdown");
-		return;
-	}
-
-	hdd_psoc_shutdown_notify(hdd_ctx);
-	hdd_exit();
-}
-
 static void __hdd_soc_recovery_shutdown(void)
 {
 	struct hdd_context *hdd_ctx;

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

@@ -120,6 +120,7 @@
 #include "wlan_twt_ucfg_api.h"
 #include "wlan_vdev_mgr_ucfg_api.h"
 #include <wlan_psoc_mlme_ucfg_api.h>
+#include "wlan_ll_sap_api.h"
 
 #define ACS_SCAN_EXPIRY_TIMEOUT_S 4
 
@@ -3930,16 +3931,35 @@ QDF_STATUS wlan_hdd_get_channel_for_sap_restart(struct wlan_objmgr_psoc *psoc,
 	else
 		ch_params.ch_width = CH_WIDTH_MAX;
 
-	intf_ch_freq = wlansap_get_chan_band_restrict(sap_context, &csa_reason);
-	if (intf_ch_freq && intf_ch_freq != sap_context->chan_freq) {
-		goto sap_restart;
-	} else if (!intf_ch_freq &&
-		  policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) {
-		schedule_work(&ap_adapter->sap_stop_bss_work);
-		wlansap_context_put(sap_context);
-		hdd_debug("stop ll_lt_sap, no channel found for csa");
-		return QDF_STATUS_E_FAILURE;
+	if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) {
+		/*
+		 * Adding this feature flag temporarily, will remove this once
+		 * feature flag is enabled.
+		 */
+#ifdef WLAN_FEATURE_LL_LT_SAP
+		intf_ch_freq =
+			wlan_get_ll_lt_sap_restart_freq(hdd_ctx->pdev,
+							sap_context->chan_freq,
+							sap_context->vdev_id,
+							&csa_reason);
+#else
+		intf_ch_freq = wlansap_get_chan_band_restrict(sap_context,
+							      &csa_reason);
+#endif
+		if (!intf_ch_freq) {
+			schedule_work(&ap_adapter->sap_stop_bss_work);
+			wlansap_context_put(sap_context);
+			hdd_debug("vdev %d stop ll_lt_sap, no channel found for csa",
+				  vdev_id);
+			return QDF_STATUS_E_FAILURE;
+		}
+	} else {
+		intf_ch_freq = wlansap_get_chan_band_restrict(sap_context,
+							      &csa_reason);
 	}
+	if (intf_ch_freq && intf_ch_freq != sap_context->chan_freq)
+		goto sap_restart;
+
 	/*
 	 * If STA+SAP sessions are on DFS channel and STA+SAP SCC is
 	 * enabled on DFS channel then move the SAP out of DFS channel
@@ -6542,6 +6562,11 @@ int wlan_hdd_cfg80211_start_bss(struct wlan_hdd_link_info *link_info,
 		if (ret < 0)
 			goto error;
 	}
+
+	config->chan_freq = wlan_ll_lt_sap_override_freq(hdd_ctx->psoc,
+							 link_info->vdev_id,
+							 config->chan_freq);
+
 	if (!ret && wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, config->chan_freq))
 		hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE;
 
@@ -7892,7 +7917,7 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 	if (QDF_STATUS_SUCCESS !=
 	    ucfg_policy_mgr_get_sap_mandt_chnl(hdd_ctx->psoc, &mandt_chnl_list))
 		hdd_err("can't get mandatory channel list");
-	if (mandt_chnl_list)
+	if (mandt_chnl_list && adapter->device_mode == QDF_SAP_MODE)
 		policy_mgr_init_sap_mandatory_chan(hdd_ctx->psoc,
 						   chandef->chan->center_freq);
 

+ 28 - 1
core/hdd/src/wlan_hdd_ioctl.c

@@ -3053,6 +3053,14 @@ static int drv_cmd_set_roam_mode(struct wlan_hdd_link_info *link_info,
 
 	hdd_debug("Received Command to Set Roam Mode = %d",
 		  roam_mode);
+
+	if (sme_roaming_in_progress(hdd_ctx->mac_handle,
+				    link_info->vdev_id)) {
+		hdd_err_rl("Roaming in progress for vdev %d",
+			   link_info->vdev_id);
+		return -EAGAIN;
+	}
+
 	/*
 	 * Note that
 	 *     SETROAMMODE 0 is to enable LFR while
@@ -4370,6 +4378,13 @@ static int drv_cmd_set_fast_roam(struct wlan_hdd_link_info *link_info,
 	hdd_debug("Received Command to change lfr mode = %d",
 		  lfr_mode);
 
+	if (sme_roaming_in_progress(hdd_ctx->mac_handle,
+				    link_info->vdev_id)) {
+		hdd_err_rl("Roaming in progress for vdev %d",
+			   link_info->vdev_id);
+		return -EAGAIN;
+	}
+
 	ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode);
 	sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
 						    link_info->vdev_id,
@@ -6560,12 +6575,21 @@ static void disconnect_sta_and_restart_sap(struct hdd_context *hdd_ctx,
 	struct hdd_adapter *adapter, *next = NULL;
 	QDF_STATUS status;
 	struct hdd_ap_ctx *ap_ctx;
+	uint32_t ch_list[NUM_CHANNELS];
+	uint32_t ch_count = 0;
+	bool is_valid_chan_present = true;
 
 	if (!hdd_ctx)
 		return;
 
 	hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx, reason);
 
+	status = policy_mgr_get_valid_chans(hdd_ctx->psoc, ch_list, &ch_count);
+	if (QDF_IS_STATUS_ERROR(status) || !ch_count) {
+		hdd_debug("No valid channels present, stop the SAPs");
+		is_valid_chan_present = false;
+	}
+
 	status = hdd_get_front_adapter(hdd_ctx, &adapter);
 	while (adapter && (status == QDF_STATUS_SUCCESS)) {
 		if (hdd_validate_adapter(adapter) ||
@@ -6574,7 +6598,10 @@ static void disconnect_sta_and_restart_sap(struct hdd_context *hdd_ctx,
 		}
 
 		ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink);
-		if (check_disable_channels(hdd_ctx, ap_ctx->operating_chan_freq))
+		if (!is_valid_chan_present)
+			wlan_hdd_stop_sap(adapter);
+		else if (check_disable_channels(hdd_ctx,
+						ap_ctx->operating_chan_freq))
 			policy_mgr_check_sap_restart(hdd_ctx->psoc,
 						     adapter->deflink->vdev_id);
 next_adapter:

+ 27 - 4
core/hdd/src/wlan_hdd_main.c

@@ -4175,7 +4175,6 @@ static void hdd_check_for_objmgr_peer_leaks(struct wlan_objmgr_psoc *psoc)
 
 	/* get module id which cause the leak and release ref */
 	wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) {
-		wlan_vdev_obj_lock(vdev);
 		wlan_objmgr_for_each_vdev_peer(vdev, peer) {
 			qdf_atomic_t *ref_id_dbg;
 			int ref_id;
@@ -4185,7 +4184,6 @@ static void hdd_check_for_objmgr_peer_leaks(struct wlan_objmgr_psoc *psoc)
 			wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs)
 				wlan_objmgr_peer_release_ref(peer, ref_id);
 		}
-		wlan_vdev_obj_unlock(vdev);
 	}
 }
 
@@ -7098,6 +7096,8 @@ static int hdd_vdev_destroy_event_wait(struct hdd_context *hdd_ctx,
 	QDF_STATUS status;
 	uint8_t vdev_id;
 	struct wlan_hdd_link_info *link_info;
+	struct qdf_mac_addr *mld_addr;
+	struct wlan_objmgr_psoc *psoc = NULL;
 
 	vdev_id = wlan_vdev_get_id(vdev);
 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
@@ -7106,6 +7106,28 @@ static int hdd_vdev_destroy_event_wait(struct hdd_context *hdd_ctx,
 		return -EINVAL;
 	}
 
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		obj_mgr_err("Failed to get psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Detach DP vdev from DP MLO Device Context */
+	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
+
+	if (!qdf_is_macaddr_zero(mld_addr)) {
+		/* only for MLO vdev's */
+
+		if (cdp_mlo_dev_ctxt_detach(wlan_psoc_get_dp_handle(psoc),
+					    wlan_vdev_get_id(vdev),
+					    (uint8_t *)mld_addr)
+					    != QDF_STATUS_SUCCESS) {
+			obj_mgr_err("Failed to detach DP vdev from DP MLO Dev ctxt");
+			QDF_BUG(0);
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
 	/* close sme session (destroy vdev in firmware via legacy API) */
 	INIT_COMPLETION(link_info->vdev_destroy_event);
 	status = sme_vdev_delete(hdd_ctx->mac_handle, vdev);
@@ -16218,8 +16240,9 @@ static void hdd_v2_flow_pool_map(int vdev_id)
 		return;
 	}
 
-	if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev)) {
-		hdd_info("Link switch ongoing, do not invoke flow pool map");
+	if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) ||
+	    policy_mgr_is_set_link_in_progress(wlan_vdev_get_psoc(vdev))) {
+		hdd_info_rl("Link switch/set_link is ongoing, do not invoke flow pool map");
 		goto release_ref;
 	}
 

+ 27 - 1
core/hdd/src/wlan_hdd_mlo.c

@@ -634,9 +634,13 @@ __wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy,
 	if (!vdev)
 		return -EINVAL;
 
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
+		goto release_ref;
+
 	ret = wlan_handle_mlo_link_state_operation(wiphy, vdev, hdd_ctx,
 						   data, data_len);
 
+release_ref:
 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
 
 	return ret;
@@ -764,6 +768,23 @@ hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb,
 	return 0;
 }
 
+static char *link_state_status_id_to_str(uint32_t status)
+{
+	switch (status) {
+	case WLAN_LINK_INFO_EVENT_SUCCESS:
+		return "LINK_INFO_EVENT_SUCCESS";
+	case WLAN_LINK_INFO_EVENT_REJECT_FAILURE:
+		return "LINK_INFO_EVENT_REJECT_FAILURE";
+	case WLAN_LINK_INFO_EVENT_REJECT_VDEV_NOT_UP:
+		return "LINK_INFO_EVENT_REJECT_VDEV_NOT_UP";
+	case WLAN_LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS:
+		return "LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS";
+	case WLAN_LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION:
+		return "LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION";
+	}
+	return "Undefined link state status ID";
+}
+
 static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy,
 					      struct wlan_objmgr_psoc *psoc,
 					      struct wlan_objmgr_vdev *vdev)
@@ -808,7 +829,6 @@ static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy,
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Failed to post scheduler msg");
 		goto free_event;
-		return status;
 	}
 
 	status = osif_request_wait_for_response(request);
@@ -822,6 +842,12 @@ static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy,
 		  link_state_event->num_mlo_vdev_link_info,
 		  QDF_MAC_ADDR_REF(link_state_event->mldaddr.bytes));
 
+	if (QDF_IS_STATUS_ERROR(link_state_event->status)) {
+		hdd_debug("ml_link_state_status failed %s",
+			  link_state_status_id_to_str(link_state_event->status));
+		goto free_event;
+	}
+
 	for (num_info = 0; num_info < link_state_event->num_mlo_vdev_link_info;
 	     num_info++) {
 		hdd_debug("ml_link_state_resp: chan_freq %d vdev_id %d link_id %d link_status %d",

+ 5 - 3
core/hdd/src/wlan_hdd_station_info.c

@@ -954,9 +954,11 @@ hdd_populate_station_info_skb(struct sk_buff *skb,
 		hdd_err("he operation info put fail");
 		return QDF_STATUS_E_FAILURE;
 	}
-	if (hdd_add_eht_oper_info(skb, hdd_sta_ctx)) {
-		hdd_err("eht operation info put fail");
-		return QDF_STATUS_E_FAILURE;
+	if (hdd_sta_ctx->cache_conn_info.conn_flag.eht_op_present) {
+		if (hdd_add_eht_oper_info(skb, hdd_sta_ctx)) {
+			hdd_err("eht operation info put fail");
+			return QDF_STATUS_E_FAILURE;
+		}
 	}
 
 	if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) {

+ 99 - 17
core/hdd/src/wlan_hdd_stats.c

@@ -99,6 +99,8 @@
 
 #define MAX_RSSI_MCS_INDEX 14
 
+#define MAX_HT_MCS_INDEX 7
+
 /* 11B, 11G Rate table include Basic rate and Extended rate
  * The IDX field is the rate index
  * The HI field is the rate when RSSI is strong or being ignored
@@ -5137,6 +5139,8 @@ static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
 		return -EPERM;
 	}
 
+	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
+		return -EINVAL;
 	/**
 	 * HTT_DBG_EXT_STATS_PDEV_RX
 	 */
@@ -5677,6 +5681,63 @@ wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event *roam_stats,
 #define linkspeed_dbg(format, args...)
 #endif /* LINKSPEED_DEBUG_ENABLED */
 
+static void
+wlan_hdd_fill_per_link_summary_stats(tCsrSummaryStatsInfo *stats,
+				     struct station_info *info,
+				     struct wlan_hdd_link_info *link_info)
+{
+	uint8_t i;
+	uint32_t orig_cnt;
+	uint32_t orig_fail_cnt;
+	QDF_STATUS status;
+	uint8_t *peer_mac;
+	ol_txrx_soc_handle soc;
+	struct cdp_peer_stats *peer_stats;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return;
+
+	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx))
+		return;
+
+	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
+	if (!peer_stats)
+		return;
+
+	soc = cds_get_context(QDF_MODULE_ID_SOC);
+	peer_mac = link_info->session.station.conn_info.bssid.bytes;
+	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
+						 peer_mac, peer_stats,
+						 CDP_WILD_PEER_TYPE,
+						 WLAN_MAX_MLD);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Unable to get per link peer stats for the peer: "
+			QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_mac));
+		goto exit;
+	}
+
+	info->tx_retries = 0;
+	info->tx_failed = 0;
+
+	for (i = 0; i < WIFI_MAX_AC; ++i) {
+		info->tx_retries += stats->multiple_retry_cnt[i];
+		info->tx_failed += stats->fail_cnt[i];
+	}
+
+	orig_cnt = info->tx_retries;
+	orig_fail_cnt = info->tx_failed;
+	info->tx_retries = peer_stats->tx.retries_mpdu;
+	info->tx_failed += peer_stats->tx.mpdu_success_with_retries;
+	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx retries adjust from %d to %d",
+		  QDF_MAC_ADDR_REF(peer_mac), orig_cnt, info->tx_retries);
+	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx failed adjust from %d to %d",
+		  QDF_MAC_ADDR_REF(peer_mac), orig_fail_cnt, info->tx_failed);
+exit:
+	qdf_mem_free(peer_stats);
+}
+
 /**
  * wlan_hdd_fill_summary_stats() - populate station_info summary stats
  * @stats: summary stats to use as a source
@@ -5839,16 +5900,19 @@ static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
 	}
 
 	if (!report_max) {
-		for (i = 0; i < mcsidx; i++) {
+		for (i = 0; i < MAX_HT_MCS_INDEX && i < mcsidx; i++) {
 			if (rssi <= rssi_mcs_tbl[mode][i]) {
 				mcsidx = i;
 				break;
 			}
 		}
-		if (mcsidx < stats->tx_rate.mcs)
+		if (mcsidx < stats->tx_rate.mcs &&
+		    stats->tx_rate.mcs <= MAX_HT_MCS_INDEX)
 			mcsidx = stats->tx_rate.mcs;
 	}
 
+	if (mcsidx > MAX_HT_MCS_INDEX)
+		mcsidx = MAX_HT_MCS_INDEX;
 	tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
 
 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
@@ -7596,6 +7660,9 @@ static int wlan_hdd_update_rate_info(struct wlan_hdd_link_info *link_info,
 	wlan_hdd_fill_summary_stats(&hdd_stats->summary_stat,
 				    sinfo, link_info->vdev_id);
 
+	wlan_hdd_fill_per_link_summary_stats(&hdd_stats->summary_stat,
+					     sinfo, link_info);
+
 	ucfg_dp_get_net_dev_stats(vdev, &stats);
 	sinfo->tx_bytes = stats.tx_bytes;
 	sinfo->rx_bytes = stats.rx_bytes;
@@ -8208,8 +8275,17 @@ int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
 	if (errno)
 		return errno;
 
+	errno = wlan_hdd_qmi_get_sync_resume();
+	if (errno) {
+		hdd_err("qmi sync resume failed: %d", errno);
+		goto end;
+	}
+
 	errno = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
 
+	wlan_hdd_qmi_put_suspend();
+
+end:
 	osif_vdev_sync_op_stop(vdev_sync);
 
 	return errno;
@@ -9637,10 +9713,14 @@ static enum qca_wlan_roam_stats_frame_subtype
 hdd_convert_roam_frame_type(enum eroam_frame_subtype type)
 {
 	switch (type) {
-	case WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH:
-		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH;
-	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC:
-		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC;
+	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ:
+		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
+	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP:
+		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP;
+	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ:
+		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ;
+	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP:
+		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP;
 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1:
 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1;
 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2:
@@ -9658,7 +9738,7 @@ hdd_convert_roam_frame_type(enum eroam_frame_subtype type)
 		break;
 	}
 
-	return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH;
+	return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
 };
 
 static enum qca_wlan_roam_stats_frame_status
@@ -9914,7 +9994,7 @@ static uint32_t hdd_get_roam_stats_individual_record_len(struct enhance_roam_inf
 
 	/* ROAM_STATS_FRAME_INFO */
 	len += nla_total_size(0);
-	for (i = 0; i < ROAM_FRAME_NUM; i++) {
+	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
 		/* nest attribute */
 		len += nla_total_size(0);
 		/* ROAM_STATS_FRAME_SUBTYPE */
@@ -10293,7 +10373,7 @@ static int hdd_nla_put_roam_stats_info(struct sk_buff *skb,
 		return -EINVAL;
 	}
 
-	for (i = 0; i < ROAM_FRAME_NUM; i++) {
+	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
 		roam_frame = nla_nest_start(skb, i);
 		if (!roam_frame) {
 			hdd_err("nla_nest_start fail");
@@ -10321,6 +10401,15 @@ static int hdd_nla_put_roam_stats_info(struct sk_buff *skb,
 			hdd_err("frame[%u].timestamp put fail %d", i, ret);
 			return -EINVAL;
 		}
+		ret = nla_put(skb,
+			      QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_BSSID,
+			      QDF_MAC_ADDR_SIZE,
+			      info->timestamp[i].bssid.bytes);
+		if (ret) {
+			hdd_err("roam candidate AP bssid put fail");
+			return -EINVAL;
+		}
+
 		nla_nest_end(skb, roam_frame);
 	}
 	nla_nest_end(skb, roam_frame_info);
@@ -10330,14 +10419,7 @@ static int hdd_nla_put_roam_stats_info(struct sk_buff *skb,
 		hdd_err("roam original AP bssid put fail");
 		return -EINVAL;
 	}
-	if (info->trigger.roam_status) {
-		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CANDIDATE_BSSID,
-			    QDF_MAC_ADDR_SIZE,
-			    info->scan.candidate_bssid.bytes)) {
-			hdd_err("roam candidate AP bssid put fail");
-			return -EINVAL;
-		}
-	} else {
+	if (!info->trigger.roam_status) {
 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAMED_BSSID,
 			    QDF_MAC_ADDR_SIZE, info->scan.roamed_bssid.bytes)) {
 			hdd_err("roam roamed AP bssid put fail");

+ 1 - 1
core/hdd/src/wlan_hdd_stats.h

@@ -43,7 +43,7 @@
 #define WLAN_WAIT_TIME_LL_STATS 800
 #endif
 
-#define WLAN_HDD_TGT_NOISE_FLOOR_DBM     (-96)
+#define WLAN_HDD_TGT_NOISE_FLOOR_DBM     (-128)
 
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
 extern const struct nla_policy qca_wlan_vendor_ll_ext_policy[

+ 0 - 1
core/hdd/src/wlan_hdd_wmm.c

@@ -2599,7 +2599,6 @@ QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter,
 	adapter->hdd_wmm_status.qos_connection = qos_connection;
 
 	for (ac = 0; ac < WLAN_MAX_AC; ac++) {
-		hdd_debug("ac %d off", ac);
 		/* admission is not required so access is allowed */
 		adapter->hdd_wmm_status.ac_status[ac].is_access_required = false;
 		adapter->hdd_wmm_status.ac_status[ac].is_access_allowed = true;

+ 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            "C"
-#define QWLAN_VERSION_BUILD            82
+#define QWLAN_VERSION_EXTRA            "R"
+#define QWLAN_VERSION_BUILD            83
 
-#define QWLAN_VERSIONSTR               "5.2.1.82C"
+#define QWLAN_VERSIONSTR               "5.2.1.83R"
 
 #endif /* QWLAN_VERSION_H */

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

@@ -1347,6 +1347,36 @@ typedef struct sSirMacBeaconReport {
 
 } tSirMacBeaconReport, *tpSirMacBeaconReport;
 
+/**
+ * struct sir_mac_bw_ind_element - Contains info for Bandwidth Indication IE
+ * present in channel load request received from AP
+ * @is_wide_bw_chan_switch: to check Bandwidth Indication optional IE present
+ * @channel_width: channel width
+ * @center_chan_freq0: center freq segment 0 for 320 MHz request
+ * @center_chan_freq1: center freq segment 1 for 320 MHz request
+ */
+struct sir_mac_bw_ind_element {
+	bool is_bw_ind_element;
+	uint8_t channel_width;
+	uint8_t center_freq_seg0;
+	uint8_t center_freq_seg1;
+};
+
+/**
+ * struct sir_mac_wide_bw_chan_switch - Contains info for Wide Bandwidth Channel
+ * Switch IE present in channel load request received from AP
+ * @is_wide_bw_chan_switch: to check Bandwidth Indication optional IE present
+ * @channel_width: channel width
+ * @center_chan_freq0: center freq segment 0 for till 160 MHz request
+ * @center_chan_freq1: center freq segment 1 for till 160 MHz request
+ */
+struct sir_mac_wide_bw_chan_switch {
+	uint8_t is_wide_bw_chan_switch;
+	uint8_t channel_width;
+	uint8_t center_chan_freq0;
+	uint8_t center_chan_freq1;
+};
+
 /**
  * struct chan_load_report - channel load Report Structure
  * @op_class: Regulatory Class
@@ -1354,6 +1384,8 @@ typedef struct sSirMacBeaconReport {
  * @rrm_scan_tsf: RRM scan start time for this report
  * @meas_duration: Scan duration for the current channel
  * @chan_load: channel utilization measurement
+ * @bw_ind: Contains info for Bandwidth Indication IE
+ * @wide_bw: Contains info for Wide Bandwidth Channel IE
  */
 struct chan_load_report {
 	uint8_t op_class;
@@ -1361,6 +1393,8 @@ struct chan_load_report {
 	qdf_time_t rrm_scan_tsf;
 	uint8_t meas_duration;
 	uint8_t chan_load;
+	struct sir_mac_bw_ind_element bw_ind;
+	struct sir_mac_wide_bw_chan_switch wide_bw;
 };
 
 /**

+ 18 - 0
core/mac/src/pe/include/lim_api.h

@@ -151,6 +151,7 @@ typedef enum eMgmtFrmDropReason {
 	eMGMT_DROP_SPURIOUS_FRAME,
 	eMGMT_DROP_DUPLICATE_AUTH_FRAME,
 	eMGMT_DROP_EXCESSIVE_MGMT_FRAME,
+	eMGMT_DROP_DEAUTH_DURING_ROAM_STARTED,
 } tMgmtFrmDropReason;
 
 /**
@@ -603,6 +604,23 @@ void lim_set_twt_ext_capabilities(struct mac_context *mac_ctx,
  */
 void lim_get_basic_rates(tSirMacRateSet *b_rates, uint32_t chan_freq);
 
+#define FW_CTS2SELF_PROFILE 34
+
+/**
+ * lim_enable_cts_to_self_for_exempted_iot_ap() - enable cts to self for iot ap
+ * @mac_ctx: mac context
+ * @session: pe session
+ * @ie_ptr: ie pointer
+ * @ie_len: ie length
+ *
+ * Return: true on success else false
+ */
+bool lim_enable_cts_to_self_for_exempted_iot_ap(
+				       struct mac_context *mac_ctx,
+				       struct pe_session *session,
+				       uint8_t *ie_ptr,
+				       uint16_t ie_len);
+
 /**
  * lim_fill_pe_session() - Lim fill pe session
  * @mac_ctx: Pointer to mac context

+ 16 - 12
core/mac/src/pe/include/lim_ft.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -137,11 +137,12 @@ static inline bool lim_process_ft_pre_auth_req(
 #endif
 
 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
-void lim_fill_ft_session(struct mac_context *mac,
-		struct bss_description *pbssDescription,
-		struct pe_session *ft_session,
-		struct pe_session *pe_session,
-		enum wlan_phymode bss_phymode);
+QDF_STATUS
+lim_fill_ft_session(struct mac_context *mac,
+		    struct bss_description *pbssDescription,
+		    struct pe_session *ft_session,
+		    struct pe_session *pe_session,
+		    enum wlan_phymode bss_phymode);
 
 /**
  * lim_ft_prepare_add_bss_req() - Create Add Bss Req to the new AP
@@ -161,12 +162,15 @@ void lim_ft_prepare_add_bss_req(struct mac_context *mac,
 QDF_STATUS lim_send_preauth_scan_offload(struct mac_context *mac_ctx,
 		struct pe_session *session_entry, tSirFTPreAuthReq *ft_preauth_req);
 #else
-static inline void lim_fill_ft_session(struct mac_context *mac,
-		struct bss_description *pbssDescription,
-		struct pe_session *ft_session,
-		struct pe_session *pe_session,
-		enum wlan_phymode bss_phymode)
-{}
+static inline QDF_STATUS
+lim_fill_ft_session(struct mac_context *mac
+		    struct bss_description *pbssDescription,
+		    struct pe_session *ft_session,
+		    struct pe_session *pe_session,
+		    enum wlan_phymode bss_phymode)
+{
+	return QDF_STATUS_SUCCESS;
+}
 static inline void lim_ft_prepare_add_bss_req(struct mac_context *mac,
 		struct pe_session *ft_session,
 		struct bss_description *bssDescription)

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

@@ -52,6 +52,49 @@ struct sir_channel_info {
 	uint32_t chan_freq;
 };
 
+/**
+ * struct rrm_reporting - Contains info for rrm_ reporting IE present in
+ * channel load request received from AP
+ * @reporting_condition: reporting condition
+ * @threshold: threshold value to report channel load request
+ */
+struct rrm_reporting {
+	uint8_t reporting_condition;
+	uint8_t threshold;
+};
+
+/**
+ * struct bw_ind_element - Contains info for Bandwidth Indication IE
+ * present in channel load request received from AP
+ * @is_bw_ind_element: to check Bandwidth Indication optional IE present
+ * @channel_width: channel width
+ * @ccfi0: center channel frequency index segment 0
+ * @ccfi1: center channel frequency index segment 1
+ * @center_freq: center freq segment  for 320 MHz request
+ */
+struct bw_ind_element {
+	bool is_bw_ind_element;
+	uint8_t channel_width;
+	uint8_t ccfi0;
+	uint8_t ccfi1;
+	qdf_freq_t center_freq;
+};
+
+/**
+ * struct wide_bw_chan_switch - Contains info for Wide Bandwidth Channel
+ * Switch IE present in channel load request received from AP
+ * @is_wide_bw_chan_switch: to check Bandwidth Indication optional IE present
+ * @channel_width: channel width
+ * @center_chan_freq0: center freq segment 0 for till 160 MHz request
+ * @center_chan_freq1: center freq segment 1 for till 160 MHz request
+ */
+struct wide_bw_chan_switch {
+	uint8_t is_wide_bw_chan_switch;
+	uint8_t channel_width;
+	uint8_t center_chan_freq0;
+	uint8_t center_chan_freq1;
+};
+
 /**
  * struct ch_load_ind - Contains info for channel load request received from AP
  * @message_type: message type eWNI_SME_CHAN_LOAD_REQ_IND
@@ -62,8 +105,11 @@ struct sir_channel_info {
  * @msg_source: message source of type enum tRrmMsgReqSource
  * @op_class: regulatory class
  * @channel: channel number
+ * @req_freq: freq as per channel load req
  * @randomization_intv: Random interval in ms
  * @meas_duration: measurement duration in ms
+ * @bw_ind: Info for bandwidth indication IE
+ * @wide_bw: Info for wide bandwidth channel switch IE
  */
 struct ch_load_ind {
 	uint16_t message_type;
@@ -74,13 +120,16 @@ struct ch_load_ind {
 	tRrmMsgReqSource msg_source;
 	uint8_t op_class;
 	uint8_t channel;
+	qdf_freq_t req_freq;
 	uint16_t randomization_intv;
 	uint16_t meas_duration;
+	struct bw_ind_element bw_ind;
+	struct wide_bw_chan_switch wide_bw;
 };
 
 /**
  * struct chan_load_xmit_ind - Contains info for channel load xmit indication
- * @message_type: message type eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND
+ * @messageType: 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
@@ -91,6 +140,8 @@ struct ch_load_ind {
  * @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
+ * @bw_ind: Info for bandwidth indication IE
+ * @wide_bw: Info for wide bandwidth channel switch IE
  */
 struct chan_load_xmit_ind {
 	uint16_t messageType;
@@ -104,6 +155,8 @@ struct chan_load_xmit_ind {
 	uint8_t chan_load;
 	qdf_time_t rrm_scan_tsf;
 	bool is_report_success;
+	struct bw_ind_element bw_ind;
+	struct wide_bw_chan_switch wide_bw;
 };
 
 typedef struct sSirBeaconReportReqInd {

+ 62 - 16
core/mac/src/pe/lim/lim_api.c

@@ -88,6 +88,7 @@
 #include <wlan_twt_api.h>
 #include "wlan_tdls_api.h"
 #include "wlan_mlo_mgr_link_switch.h"
+#include "wlan_cm_api.h"
 
 struct pe_hang_event_fixed_param {
 	uint16_t tlv_header;
@@ -2884,6 +2885,8 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 	struct bss_description *bss_desc = NULL;
 	uint16_t ric_tspec_len;
 	struct qdf_mac_addr bssid;
+	uint8_t *oui_ie_ptr;
+	uint16_t oui_ie_len;
 
 	if (!roam_sync_ind_ptr) {
 		pe_err("LFR3:roam_sync_ind_ptr is NULL");
@@ -2984,8 +2987,15 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 	ft_session_ptr->csaOffloadEnable = session_ptr->csaOffloadEnable;
 
 	/* Next routine will update nss and vdev_nss with AP's capabilities */
-	lim_fill_ft_session(mac_ctx, bss_desc, ft_session_ptr,
-			    session_ptr, roam_sync_ind_ptr->phy_mode);
+	status = lim_fill_ft_session(mac_ctx, bss_desc, ft_session_ptr,
+				     session_ptr, roam_sync_ind_ptr->phy_mode);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to fill ft session for vdev id %d",
+		       ft_session_ptr->vdev_id);
+		qdf_mem_free(bss_desc);
+		goto roam_sync_fail;
+	}
+
 	roam_sync_ind_ptr->ssid.length =
 		qdf_min((qdf_size_t)ft_session_ptr->ssId.length,
 			sizeof(roam_sync_ind_ptr->ssid.ssid));
@@ -2999,7 +3009,7 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 	/* Next routine may update nss based on dot11Mode */
 
 	lim_ft_prepare_add_bss_req(mac_ctx, ft_session_ptr, bss_desc);
-	qdf_mem_free(bss_desc);
+	lim_set_tpc_power(mac_ctx, ft_session_ptr, bss_desc);
 
 	if (session_ptr->is11Rconnection)
 		lim_fill_fils_ft(session_ptr, ft_session_ptr);
@@ -3020,6 +3030,7 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 	if (!sta_ds && !is_multi_link_roam(roam_sync_ind_ptr)) {
 		pe_err("LFR3:failed to lookup hash entry");
 		ft_session_ptr->bRoamSynchInProgress = false;
+		qdf_mem_free(bss_desc);
 		goto roam_sync_fail;
 	}
 
@@ -3034,6 +3045,7 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 		pe_err("LFR3:failed to add hash entry for "QDF_MAC_ADDR_FMT,
 		       QDF_MAC_ADDR_REF(add_bss_params->staContext.staMac));
 		ft_session_ptr->bRoamSynchInProgress = false;
+		qdf_mem_free(bss_desc);
 		goto roam_sync_fail;
 	}
 
@@ -3054,18 +3066,30 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 		if (ft_session_ptr->is_unexpected_peer_error)
 			status = QDF_STATUS_E_FAILURE;
 
-		if (QDF_IS_STATUS_ERROR(status))
+		if (QDF_IS_STATUS_ERROR(status)) {
+			qdf_mem_free(bss_desc);
 			goto roam_sync_fail;
+		}
 	} else {
 		lim_process_assoc_rsp_frame(mac_ctx, reassoc_resp,
 					    roam_sync_ind_ptr->reassoc_resp_length - SIR_MAC_HDR_LEN_3A,
 					    LIM_REASSOC, ft_session_ptr);
 		if (ft_session_ptr->is_unexpected_peer_error) {
 			status = QDF_STATUS_E_FAILURE;
+			qdf_mem_free(bss_desc);
 			goto roam_sync_fail;
 		}
 	}
 
+	oui_ie_ptr = (uint8_t *)&bss_desc->ieFields[0];
+	oui_ie_len = wlan_get_ielen_from_bss_description(bss_desc);
+	lim_enable_cts_to_self_for_exempted_iot_ap(mac_ctx,
+						   ft_session_ptr,
+						   oui_ie_ptr, oui_ie_len);
+	qdf_mem_free(bss_desc);
+	oui_ie_len = 0;
+	oui_ie_ptr = NULL;
+
 	lim_check_ft_initial_im_association(roam_sync_ind_ptr, ft_session_ptr);
 
 	lim_copy_and_free_hlp_data_from_session(ft_session_ptr,
@@ -3140,6 +3164,7 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 		lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, aid,
 					  session_ptr);
 	}
+
 	pe_delete_session(mac_ctx, session_ptr);
 	return QDF_STATUS_SUCCESS;
 
@@ -3197,8 +3222,7 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
 	uint8_t *pBody;
 	tSirMacCapabilityInfo capabilityInfo;
 	tpSirMacMgmtHdr pHdr = NULL;
-	struct pe_session *pe_session = NULL;
-	uint8_t sessionId;
+	struct wlan_objmgr_vdev *vdev;
 
 	/*
 	 *
@@ -3240,10 +3264,12 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
 		struct tLimPreAuthNode *auth_node;
 
 		pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
-		pe_session = pe_find_session_by_bssid(mac, pHdr->bssId,
-							 &sessionId);
-		if (!pe_session)
+		vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(mac->pdev,
+								 pHdr->da,
+								 WLAN_LEGACY_MAC_ID);
+		if (!vdev)
 			return eMGMT_DROP_NO_DROP;
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
 
 		curr_seq_num = ((pHdr->seqControl.seqNumHi << 4) |
 				(pHdr->seqControl.seqNumLo));
@@ -3262,18 +3288,21 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
 		qdf_time_t *timestamp;
 
 		pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
-		pe_session = pe_find_session_by_bssid(mac, pHdr->bssId,
-				&sessionId);
-		if (!pe_session)
+		vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(mac->pdev,
+								 pHdr->da,
+								 WLAN_LEGACY_MAC_ID);
+		if (!vdev)
 			return eMGMT_DROP_SPURIOUS_FRAME;
 
 		peer = wlan_objmgr_get_peer_by_mac(mac->psoc,
 						   pHdr->sa,
 						   WLAN_LEGACY_MAC_ID);
 		if (!peer) {
-			if (subType == SIR_MAC_MGMT_ASSOC_REQ)
+			if (subType == SIR_MAC_MGMT_ASSOC_REQ) {
+				wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
 				return eMGMT_DROP_NO_DROP;
-
+			}
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
 			return eMGMT_DROP_SPURIOUS_FRAME;
 		}
 
@@ -3281,12 +3310,23 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac,
 							WLAN_UMAC_COMP_MLME);
 		if (!peer_priv) {
 			wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
-			if (subType == SIR_MAC_MGMT_ASSOC_REQ)
+			if (subType == SIR_MAC_MGMT_ASSOC_REQ) {
+				wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
 				return eMGMT_DROP_NO_DROP;
-
+			}
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
 			return eMGMT_DROP_SPURIOUS_FRAME;
 		}
 
+		if (QDF_STA_MODE == wlan_vdev_mlme_get_opmode(vdev) &&
+		    wlan_cm_is_vdev_roam_started(vdev) &&
+		    (subType == SIR_MAC_MGMT_DISASSOC ||
+		     subType == SIR_MAC_MGMT_DEAUTH)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
+			return eMGMT_DROP_DEAUTH_DURING_ROAM_STARTED;
+		}
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
+
 		if (subType == SIR_MAC_MGMT_ASSOC_REQ)
 			timestamp =
 			   &peer_priv->last_assoc_received_time;
@@ -3496,6 +3536,8 @@ static const struct rsn_oui_akm_type_map rsn_oui_akm_type_mapping_table[] = {
 	{ANI_AKM_TYPE_DPP_RSN,              {0x50, 0x6F, 0x9A, 0x02} },
 	{ANI_AKM_TYPE_WPA,                  {0x00, 0x50, 0xF2, 0x01} },
 	{ANI_AKM_TYPE_WPA_PSK,              {0x00, 0x50, 0xF2, 0x02} },
+	{ANI_AKM_TYPE_SAE_EXT_KEY,          {0x00, 0x0F, 0xAC, 0x18} },
+	{ANI_AKM_TYPE_FT_SAE_EXT_KEY,       {0x00, 0x0F, 0xAC, 0x19} },
 	/* Add akm type above here */
 	{ANI_AKM_TYPE_UNKNOWN, {0} },
 };
@@ -3572,6 +3614,10 @@ lim_cm_fill_link_session(struct mac_context *mac_ctx,
 	}
 
 	pe_join_req = pe_session->lim_join_req;
+
+	mlo_roam_copy_partner_info(&pe_join_req->partner_info,
+				   sync_ind, vdev_id, false);
+
 	bss_desc = &pe_session->lim_join_req->bssDescription;
 
 	status = lim_roam_fill_bss_descr(mac_ctx, sync_ind, bss_desc,

+ 108 - 41
core/mac/src/pe/lim/lim_ft.c

@@ -513,30 +513,119 @@ static void lim_fill_dot11mode(struct mac_context *mac_ctx,
 #endif
 
 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
+/**
+ * lim_fill_session_power_info() - to fill power info in session
+ * @mac_ctx: pointer to mac ctx
+ * @pbssDescription: Pointer to pbssDescription
+ * @ft_session: Pointer to FT session
+ * @pe_session: Pointer to PE session
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS lim_fill_session_power_info(
+				struct mac_context *mac,
+				struct bss_description *pbssDescription,
+				struct pe_session *ft_session,
+				struct pe_session *pe_session)
+{
+	uint8_t currentBssUapsd;
+	int8_t localPowerConstraint;
+	int8_t regMax = 0;
+	bool is_pwr_constraint = false;
+	struct vdev_mlme_obj *mlme_obj;
+	enum reg_6g_ap_type power_type_6g;
+	QDF_STATUS status;
+
+	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev);
+	if (!mlme_obj) {
+		pe_err("vdev component object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	lim_extract_ap_capability(mac, (uint8_t *)pbssDescription->ieFields,
+		lim_get_ielen_from_bss_description(pbssDescription),
+		&ft_session->limCurrentBssQosCaps,
+		&currentBssUapsd,
+		&localPowerConstraint, ft_session, &is_pwr_constraint);
+
+	mlme_obj->reg_tpc_obj.is_power_constraint_abs = !is_pwr_constraint;
+
+	if (wlan_reg_is_6ghz_chan_freq(pbssDescription->chan_freq)) {
+		status = wlan_reg_get_best_6g_power_type(
+				mac->psoc, mac->pdev,
+				&power_type_6g,
+				ft_session->ap_defined_power_type_6g,
+				pbssDescription->chan_freq);
+		if (QDF_IS_STATUS_ERROR(status))
+			return status;
+
+		ft_session->best_6g_power_type = power_type_6g;
+		mlme_set_best_6g_power_type(ft_session->vdev, power_type_6g);
+	}
+
+	if (wlan_reg_is_ext_tpc_supported(mac->psoc)) {
+		mlme_obj->reg_tpc_obj.ap_constraint_power =
+						localPowerConstraint;
+	} else {
+		regMax = wlan_reg_get_channel_reg_power_for_freq(
+				mac->pdev, ft_session->curr_op_freq);
+		if (is_pwr_constraint)
+			localPowerConstraint = regMax - localPowerConstraint;
+		if (!localPowerConstraint)
+			localPowerConstraint = regMax;
+
+		mlme_obj->reg_tpc_obj.reg_max[0] = regMax;
+		mlme_obj->reg_tpc_obj.ap_constraint_power =
+						localPowerConstraint;
+		mlme_obj->reg_tpc_obj.frequency[0] = ft_session->curr_op_freq;
+
+#ifdef FEATURE_WLAN_ESE
+		ft_session->maxTxPower = lim_get_max_tx_power(mac, mlme_obj);
+#else
+		ft_session->maxTxPower = QDF_MIN(regMax, localPowerConstraint);
+#endif
+		ft_session->def_max_tx_pwr = ft_session->maxTxPower;
+	}
+
+	/*
+	 * for mdm platform which QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET
+	 * will not call from android framework every 3 seconds, and tx
+	 * power will never update. So we use iw dev get tx power need
+	 * set maxTxPower non-zero value, that firmware can calc a non-zero
+	 * tx power, and update to host driver.
+	 */
+	if (ft_session->maxTxPower == 0)
+		ft_session->maxTxPower =
+			wlan_reg_get_channel_reg_power_for_freq(mac->pdev,
+						ft_session->curr_op_freq);
+
+	pe_debug("Reg max: %d local pwr: %d, max tx pwr: %d", regMax,
+		 localPowerConstraint, ft_session->maxTxPower);
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /*------------------------------------------------------------------
  *
  * Setup the new session for the pre-auth AP.
  * Return the newly created session entry.
  *
  *------------------------------------------------------------------*/
-void lim_fill_ft_session(struct mac_context *mac,
-			 struct bss_description *pbssDescription,
-			 struct pe_session *ft_session,
-			 struct pe_session *pe_session,
-			 enum wlan_phymode bss_phymode)
+QDF_STATUS
+lim_fill_ft_session(struct mac_context *mac,
+		    struct bss_description *pbssDescription,
+		    struct pe_session *ft_session,
+		    struct pe_session *pe_session,
+		    enum wlan_phymode bss_phymode)
 {
-	uint8_t currentBssUapsd;
 	uint8_t bss_chan_id;
-	int8_t localPowerConstraint;
-	int8_t regMax;
 	tSchBeaconStruct *pBeaconStruct;
 	ePhyChanBondState cbEnabledMode;
-	struct vdev_mlme_obj *mlme_obj;
-	bool is_pwr_constraint = false;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct));
 	if (!pBeaconStruct)
-		return;
+		return QDF_STATUS_E_NOMEM;
 
 	/* Retrieve the session that was already created and update the entry */
 	ft_session->limWmeEnabled = pe_session->limWmeEnabled;
@@ -707,47 +796,23 @@ void lim_fill_ft_session(struct mac_context *mac,
 		ft_session->shortSlotTimeSupported = true;
 	}
 
-	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev);
-	if (!mlme_obj) {
-		pe_err("vdev component object is NULL");
-		qdf_mem_free(pBeaconStruct);
-		return;
+	status = lim_fill_session_power_info(mac, pbssDescription, ft_session,
+					     pe_session);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Failed to fill power info in ft session");
+		goto exit;
 	}
 
-	regMax = wlan_reg_get_channel_reg_power_for_freq(
-		mac->pdev, ft_session->curr_op_freq);
-	localPowerConstraint = regMax;
-	lim_extract_ap_capability(mac, (uint8_t *) pbssDescription->ieFields,
-		lim_get_ielen_from_bss_description(pbssDescription),
-		&ft_session->limCurrentBssQosCaps,
-		&currentBssUapsd,
-		&localPowerConstraint, ft_session, &is_pwr_constraint);
-	if (is_pwr_constraint)
-		localPowerConstraint = regMax - localPowerConstraint;
-
-	mlme_obj->reg_tpc_obj.is_power_constraint_abs = !is_pwr_constraint;
-
 	ft_session->limReassocBssQosCaps =
 		ft_session->limCurrentBssQosCaps;
 
 	ft_session->is11Rconnection = pe_session->is11Rconnection;
+
 #ifdef FEATURE_WLAN_ESE
 	ft_session->is_ese_version_ie_present =
 		pBeaconStruct->is_ese_ver_ie_present;
 #endif
 
-	mlme_obj->reg_tpc_obj.reg_max[0] = regMax;
-	mlme_obj->reg_tpc_obj.ap_constraint_power = localPowerConstraint;
-	mlme_obj->reg_tpc_obj.frequency[0] = ft_session->curr_op_freq;
-
-#ifdef FEATURE_WLAN_ESE
-	ft_session->maxTxPower = lim_get_max_tx_power(mac, mlme_obj);
-#else
-	ft_session->maxTxPower = QDF_MIN(regMax, (localPowerConstraint));
-#endif
-
-	pe_debug("Reg max: %d local pwr: %d, max tx pwr: %d", regMax,
-		 localPowerConstraint, ft_session->maxTxPower);
 	if (!lim_is_roam_synch_in_progress(mac->psoc, pe_session)) {
 		ft_session->limPrevSmeState = ft_session->limSmeState;
 		ft_session->limSmeState = eLIM_SME_WT_REASSOC_STATE;
@@ -773,7 +838,9 @@ void lim_fill_ft_session(struct mac_context *mac,
 		mac->mlme_cfg->ht_caps.smps,
 		ft_session->supported_nss_1x1);
 
+exit:
 	qdf_mem_free(pBeaconStruct);
+	return status;
 }
 #endif
 

+ 8 - 3
core/mac/src/pe/lim/lim_ft_preauth.c

@@ -324,6 +324,7 @@ QDF_STATUS lim_ft_setup_auth_session(struct mac_context *mac,
 	struct pe_session *ft_session = NULL;
 	uint8_t sessionId = 0;
 	struct sSirFTPreAuthReq *req;
+	QDF_STATUS status;
 
 	ft_session =
 		pe_find_session_by_bssid(mac, pe_session->limReAssocbssId,
@@ -342,9 +343,13 @@ QDF_STATUS lim_ft_setup_auth_session(struct mac_context *mac,
 
 	req = pe_session->ftPEContext.pFTPreAuthReq;
 	if (req && req->pbssDescription) {
-		lim_fill_ft_session(mac,
-				    req->pbssDescription, ft_session,
-				    pe_session, WLAN_PHYMODE_AUTO);
+		status = lim_fill_ft_session(mac,
+					     req->pbssDescription, ft_session,
+					     pe_session, WLAN_PHYMODE_AUTO);
+		if (QDF_IS_STATUS_ERROR(status))
+			pe_err("Failed to fill ft session for vdev id %d",
+			       ft_session->vdev_id);
+
 		lim_ft_prepare_add_bss_req(mac, ft_session,
 					   req->pbssDescription);
 	}

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

@@ -1129,6 +1129,9 @@ __lim_process_radio_measure_request(struct mac_context *mac, uint8_t *pRxPacketI
 		 QDF_MAC_ADDR_REF(pe_session->bssId),
 		 QDF_MAC_ADDR_REF(pe_session->self_mac_addr));
 
+	pe_debug("RX RRM - type %hu, sub type %hu, seq num[%d]",
+		 pHdr->fc.type, pHdr->fc.subType, curr_seq_num);
+
 	rrm_process_radio_measurement_request(mac, pe_session->bssId, frm,
 					      pe_session);
 err:

Някои файлове не бяха показани, защото твърде много файлове са промени