Browse Source

Merge 7c0df6df9b60c1cc423682c824023146d5d7033b on remote branch

Change-Id: Ifdafa1f343290b59759b5c4c95a4111d89d2032b
Linux Build Service Account 1 year ago
parent
commit
6a7c9475a8
100 changed files with 4704 additions and 1065 deletions
  1. 12 4
      Android.mk
  2. 8 1
      Kbuild
  3. 29 0
      Kconfig
  4. 5 1
      components/action_oui/core/inc/wlan_action_oui_priv.h
  5. 22 0
      components/action_oui/core/src/wlan_action_oui_main.c
  6. 18 2
      components/action_oui/core/src/wlan_action_oui_parse.c
  7. 19 8
      components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h
  8. 4 5
      components/cmn_services/interface_mgr/src/wlan_if_mgr_sta.c
  9. 57 0
      components/cmn_services/logging/inc/wlan_connectivity_logging.h
  10. 194 6
      components/cmn_services/logging/src/wlan_connectivity_logging.c
  11. 91 1
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
  12. 11 1
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h
  13. 58 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h
  14. 153 5
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c
  15. 42 1
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c
  16. 197 13
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  17. 3 1
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h
  18. 2 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c
  19. 25 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c
  20. 3 1
      components/dp/core/inc/wlan_dp_main.h
  21. 17 1
      components/dp/core/src/wlan_dp_fisa_rx.c
  22. 1 0
      components/dp/core/src/wlan_dp_fisa_rx.h
  23. 12 3
      components/dp/core/src/wlan_dp_main.c
  24. 92 0
      components/mlme/core/inc/wlan_mlme_main.h
  25. 217 44
      components/mlme/core/src/wlan_mlme_main.c
  26. 1 0
      components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c
  27. 1 22
      components/mlme/dispatcher/inc/cfg_mlme_power.h
  28. 127 10
      components/mlme/dispatcher/inc/wlan_mlme_api.h
  29. 31 2
      components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
  30. 41 0
      components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
  31. 239 23
      components/mlme/dispatcher/src/wlan_mlme_api.c
  32. 13 0
      components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
  33. 5 1
      components/p2p/dispatcher/inc/wlan_p2p_public_struct.h
  34. 6 5
      components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c
  35. 3 2
      components/target_if/connection_mgr/src/target_if_cm_roam_event.c
  36. 1 0
      components/target_if/p2p/src/target_if_p2p.c
  37. 24 4
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c
  38. 24 9
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c
  39. 7 5
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h
  40. 7 5
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c
  41. 11 1
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c
  42. 10 3
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c
  43. 7 1
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h
  44. 91 10
      components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c
  45. 4 0
      components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h
  46. 27 0
      components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h
  47. 37 0
      components/umac/mlme/mlo_mgr/inc/wlan_t2lm_api.h
  48. 78 11
      components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c
  49. 74 1
      components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c
  50. 212 0
      components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c
  51. 21 0
      components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c
  52. 10 0
      components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h
  53. 16 0
      components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_ucfg_api.h
  54. 7 0
      components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c
  55. 5 1
      components/umac/twt/core/src/wlan_twt_main.c
  56. 2 0
      components/umac/twt/core/src/wlan_twt_main.h
  57. 3 0
      components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h
  58. 2 1
      components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c
  59. 57 4
      components/wmi/src/wmi_unified_roam_tlv.c
  60. 14 4
      configs/config_to_feature.h
  61. 34 0
      configs/pineapple_consolidate_peach_defconfig
  62. 2 0
      configs/pineapple_gki_kiwi-v2_defconfig
  63. 387 0
      configs/pineapple_gki_peach_defconfig
  64. 0 13
      core/hdd/inc/wlan_hdd_cfg.h
  65. 72 0
      core/hdd/inc/wlan_hdd_ll_lt_sap.h
  66. 35 0
      core/hdd/inc/wlan_hdd_main.h
  67. 49 3
      core/hdd/inc/wlan_hdd_tsf.h
  68. 153 125
      core/hdd/src/wlan_hdd_cfg.c
  69. 62 61
      core/hdd/src/wlan_hdd_cfg80211.c
  70. 12 4
      core/hdd/src/wlan_hdd_cm_connect.c
  71. 2 0
      core/hdd/src/wlan_hdd_cm_disconnect.c
  72. 2 2
      core/hdd/src/wlan_hdd_green_ap.c
  73. 10 2
      core/hdd/src/wlan_hdd_hostapd.c
  74. 179 0
      core/hdd/src/wlan_hdd_ll_lt_sap.c
  75. 20 12
      core/hdd/src/wlan_hdd_main.c
  76. 8 5
      core/hdd/src/wlan_hdd_mlo.c
  77. 23 1
      core/hdd/src/wlan_hdd_nan_datapath.c
  78. 26 17
      core/hdd/src/wlan_hdd_p2p.c
  79. 4 6
      core/hdd/src/wlan_hdd_power.c
  80. 5 0
      core/hdd/src/wlan_hdd_regulatory.c
  81. 5 2
      core/hdd/src/wlan_hdd_son.c
  82. 323 406
      core/hdd/src/wlan_hdd_stats.c
  83. 170 0
      core/hdd/src/wlan_hdd_sysfs_connect_info.c
  84. 109 69
      core/hdd/src/wlan_hdd_tsf.c
  85. 0 1
      core/mac/inc/ani_global.h
  86. 3 3
      core/mac/inc/qwlan_version.h
  87. 15 0
      core/mac/inc/sir_api.h
  88. 3 1
      core/mac/inc/wni_api.h
  89. 26 0
      core/mac/src/cfg/cfgUtil/dot11f.frms
  90. 92 2
      core/mac/src/include/dot11f.h
  91. 20 0
      core/mac/src/include/parser_api.h
  92. 1 2
      core/mac/src/pe/include/lim_global.h
  93. 17 0
      core/mac/src/pe/include/lim_session.h
  94. 7 0
      core/mac/src/pe/include/rrm_global.h
  95. 1 2
      core/mac/src/pe/lim/lim_api.c
  96. 8 1
      core/mac/src/pe/lim/lim_process_action_frame.c
  97. 7 17
      core/mac/src/pe/lim/lim_process_beacon_frame.c
  98. 5 0
      core/mac/src/pe/lim/lim_process_message_queue.c
  99. 2 1
      core/mac/src/pe/lim/lim_process_probe_req_frame.c
  100. 295 84
      core/mac/src/pe/lim/lim_process_sme_req_messages.c

+ 12 - 4
Android.mk

@@ -79,8 +79,15 @@ ifeq ($(LOCAL_MULTI_KO), true)
 LOCAL_ANDROID_ROOT := $(shell pwd)
 LOCAL_WLAN_BLD_DIR := $(LOCAL_ANDROID_ROOT)/$(WLAN_BLD_DIR)
 $(shell `find $(LOCAL_WLAN_BLD_DIR)/qcacld-3.0/ -maxdepth 1 -name '.*' ! -name '.git' -delete`)
+
 ifeq ($(LOCAL_MODULE_DDK_BUILD), true)
+ifeq ($(CHIPSET),)
+$(foreach chip, $(TARGET_WLAN_CHIP),\
+	$(eval CHIPSET := $(chip))\
+	$(eval include $(LOCAL_PATH)/Android.mk))
+else
 # DLKM_DIR was moved for JELLY_BEAN (PLATFORM_SDK 16)
+BAZEL_CHIPSET_NAME := $(subst _,-,$(CHIPSET))
 ifeq ($(call is-platform-sdk-version-at-least,16),true)
         DLKM_DIR := $(TOP)/$(BOARD_COMMON_DIR)/dlkm
 else
@@ -89,9 +96,10 @@ endif # platform-sdk-version
 
 include $(CLEAR_VARS)
 LOCAL_MOD_NAME := wlan
-LOCAL_MODULE              := qca_cld3_kiwi_v2.ko
-LOCAL_MODULE_KBUILD_NAME  := qca_cld3_kiwi_v2.ko
+LOCAL_MODULE              := qca_cld3_$(CHIPSET).ko
+LOCAL_MODULE_KBUILD_NAME  := qca_cld3_$(CHIPSET).ko
 LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_DDK_SUBTARGET_REGEX := "all.*"
 ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true)
     ifeq ($(WIFI_DRIVER_INSTALL_TO_KERNEL_OUT),true)
         LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
@@ -103,7 +111,7 @@ else
 endif
 
 
-LOCAL_DEV_NAME := kiwi_v2
+LOCAL_DEV_NAME := $(CHIPSET)
 LOCAL_CHIP_NAME := $(LOCAL_DEV_NAME)
 TARGET_MAC_BIN_PATH := /mnt/vendor/persist/$(LOCAL_CHIP_NAME)
 TARGET_FW_DIR := firmware/wlan/qca_cld/$(LOCAL_CHIP_NAME)
@@ -158,7 +166,7 @@ ifeq ($(TARGET_USES_KERNEL_PLATFORM),true)
 else
     include $(DLKM_DIR)/AndroidKernelModule.mk
 endif
-
+endif
 else
 $(foreach chip, $(TARGET_WLAN_CHIP), \
 	$(shell ln -sf . $(LOCAL_WLAN_BLD_DIR)/qcacld-3.0/.$(chip)))

+ 8 - 1
Kbuild

@@ -139,6 +139,7 @@ HDD_OBJS := 	$(HDD_SRC_DIR)/wlan_hdd_assoc.o \
 		$(HDD_SRC_DIR)/wlan_hdd_tx_rx.o \
 		$(HDD_SRC_DIR)/wlan_hdd_wmm.o \
 		$(HDD_SRC_DIR)/wlan_hdd_wowl.o\
+		$(HDD_SRC_DIR)/wlan_hdd_ll_lt_sap.o\
 
 ifeq ($(CONFIG_UNIT_TEST), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_unit_test.o
@@ -4118,8 +4119,14 @@ endif
 # Enable feature sync tsf for chips based on Adrastea arch
 ccflags-$(CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ) += -DWLAN_FEATURE_TSF_PLUS_NOIRQ
 
+ifeq ($(CONFIG_WLAN_TSF_UPLINK_DELAY), y)
 # Enable uplink delay report feature
-ccflags-$(CONFIG_WLAN_TSF_UPLINK_DELAY) += -DWLAN_FEATURE_TSF_UPLINK_DELAY
+ccflags-y += -DWLAN_FEATURE_TSF_UPLINK_DELAY
+CONFIG_WLAN_TSF_AUTO_REPORT := y
+endif
+
+# Enable TSF auto report feature
+ccflags-$(CONFIG_WLAN_TSF_AUTO_REPORT) += -DWLAN_FEATURE_TSF_AUTO_REPORT
 
 ccflags-$(CONFIG_ATH_PROCFS_DIAG_SUPPORT) += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT
 

+ 29 - 0
Kconfig

@@ -107,6 +107,10 @@ config CNSS_KIWI_V2
 	bool "Enable CNSS_KIWI_V2"
 	default n
 
+config CNSS_PEACH
+	bool "Enable CNSS_PEACH"
+	default n
+
 config CNSS_UTILS_MODULE
 	bool "Enable CNSS_UTILS_MODULE"
 	default n
@@ -1619,8 +1623,13 @@ config WLAN_TRACEPOINTS
 	bool "Enable WLAN_TRACEPOINTS"
 	default n
 
+config WLAN_TSF_AUTO_REPORT
+	bool "Enable WLAN_TSF_AUTO_REPORT"
+	default n
+
 config WLAN_TSF_UPLINK_DELAY
 	bool "Enable WLAN_TSF_UPLINK_DELAY"
+	depends on WLAN_TSF_AUTO_REPORT
 	default n
 
 config WLAN_TWT_CONVERGED
@@ -1864,6 +1873,26 @@ config FEATURE_WLAN_CH_AVOID_EXT
 
 config WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE
 	bool "enable CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE"
+config 4_BYTES_TLV_TAG
+	bool "enable 4_BYTES_TLV_TAG"
+	default n
+
+config QCA_WIFI_EMULATION
+	bool "enable CONFIG_QCA_WIFI_EMULATION"
 	default n
 
+config QDF_TIMER_MULTIPLIER_FRAC
+	int "set QDF_TIMER_MULTIPLIER_FRAC"
+
+config QDF_TIMER_MULTIPLIER_FRAC_ENABLE
+	bool "enable QDF_TIMER_MULTIPLIER_FRAC_ENABLE"
+	default n
+
+config QCA_WIFI_PEACH
+	bool "enable QCA_WIFI_PEACH"
+	default n
+
+config BCN_RATECODE_ENABLE
+	bool "enable CONFIG_BCN_RATECODE_ENABLE"
+	default n
 endif # QCA_CLD_WLAN

+ 5 - 1
components/action_oui/core/inc/wlan_action_oui_priv.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2018 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
@@ -91,6 +91,8 @@ struct action_oui_priv {
  * @action_oui_enable: action oui enable
  * @action_oui_str: oui configuration strings
  * @total_extensions: total count of extensions from all actions
+ * @host_only_extensions: total host only only extensions from all actions
+ * @max_extensions: Max no. of extensions that can be configured to the firmware
  * @oui_priv: array of pointers used to refer each action info
  * @tx_ops: call-back functions to send OUIs to firmware
  */
@@ -99,6 +101,8 @@ struct action_oui_psoc_priv {
 	bool action_oui_enable;
 	uint8_t action_oui_str[ACTION_OUI_MAXIMUM_ID][ACTION_OUI_MAX_STR_LEN];
 	uint32_t total_extensions;
+	uint32_t host_only_extensions;
+	uint32_t max_extensions;
 	struct action_oui_priv *oui_priv[ACTION_OUI_MAXIMUM_ID];
 	struct action_oui_tx_ops tx_ops;
 };

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

@@ -95,6 +95,9 @@ action_oui_destroy(struct action_oui_psoc_priv *psoc_priv)
 	uint32_t i;
 
 	psoc_priv->total_extensions = 0;
+	psoc_priv->max_extensions = 0;
+	psoc_priv->host_only_extensions = 0;
+
 	for (i = 0; i < ACTION_OUI_MAXIMUM_ID; i++) {
 		oui_priv = psoc_priv->oui_priv[i];
 		psoc_priv->oui_priv[i] = NULL;
@@ -233,6 +236,18 @@ static void action_oui_parse_config(struct wlan_objmgr_psoc *psoc)
 			action_oui_err("Failed to parse action_oui str: %u",
 				       id);
 	}
+
+	/* FW allocates memory for the extensions only during init time.
+	 * Therefore, send additional legspace for configuring new
+	 * extensions during runtime.
+	 * The current max value is default extensions count + 10.
+	 */
+	psoc_priv->max_extensions = psoc_priv->total_extensions -
+					psoc_priv->host_only_extensions +
+					ACTION_OUI_MAX_ADDNL_EXTENSIONS;
+	action_oui_debug("Extensions - Max: %d Total: %d host_only %d",
+			 psoc_priv->max_extensions, psoc_priv->total_extensions,
+			 psoc_priv->host_only_extensions);
 }
 
 static QDF_STATUS action_oui_send_config(struct wlan_objmgr_psoc *psoc)
@@ -436,6 +451,13 @@ wlan_action_oui_cleanup(struct action_oui_psoc_priv *psoc_priv,
 			psoc_priv->total_extensions--;
 		else
 			action_oui_err("unexpected total_extensions 0");
+
+		if (action_id >= ACTION_OUI_HOST_ONLY) {
+			if (!psoc_priv->host_only_extensions)
+				action_oui_err("unexpected total host extensions");
+			else
+				psoc_priv->host_only_extensions--;
+		}
 	}
 	qdf_mutex_release(&oui_priv->extension_lock);
 

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

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -630,6 +630,12 @@ action_oui_parse(struct action_oui_psoc_priv *psoc_priv,
 			break;
 		}
 
+		if (action_id >= ACTION_OUI_HOST_ONLY) {
+			qdf_mutex_acquire(&oui_priv->extension_lock);
+			psoc_priv->host_only_extensions++;
+			qdf_mutex_release(&oui_priv->extension_lock);
+		}
+
 		oui_index++;
 		if (oui_index == ACTION_OUI_MAX_EXTENSIONS) {
 			if (str1)
@@ -754,6 +760,16 @@ QDF_STATUS action_oui_send(struct action_oui_psoc_priv *psoc_priv,
 	extension_list = &oui_priv->extension_list;
 	qdf_mutex_acquire(&oui_priv->extension_lock);
 
+	if (psoc_priv->max_extensions -
+	    (psoc_priv->total_extensions - psoc_priv->host_only_extensions) < 0) {
+		action_oui_err("total_extensions: %d exceeds max_extensions: %d, do not update",
+			       psoc_priv->max_extensions,
+			       (psoc_priv->total_extensions -
+				psoc_priv->host_only_extensions));
+		qdf_mutex_release(&oui_priv->extension_lock);
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	no_oui_extensions = qdf_list_size(extension_list);
 	len = sizeof(*req) + no_oui_extensions * sizeof(*extension);
 	req = qdf_mem_malloc(len);
@@ -764,7 +780,7 @@ QDF_STATUS action_oui_send(struct action_oui_psoc_priv *psoc_priv,
 
 	req->action_id = oui_priv->id;
 	req->no_oui_extensions = no_oui_extensions;
-	req->total_no_oui_extensions = psoc_priv->total_extensions;
+	req->total_no_oui_extensions = psoc_priv->max_extensions;
 
 	extension = req->extension;
 	qdf_list_peek_front(extension_list, &node);

+ 19 - 8
components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h

@@ -43,6 +43,17 @@
  */
 #define ACTION_OUI_MAX_EXTENSIONS 10
 
+/*
+ * Firmware allocates memory for the extensions only during init time.
+ * Therefore, inaddition to the total extensions configured during
+ * init time, driver has to add extra space to allow runtime extensions.
+ *
+ * Example: ACTION_OUI_11BE_OUI_ALLOW
+ *
+ * Max. value should be increased with the addition of new runtime extensions.
+ */
+#define ACTION_OUI_MAX_ADDNL_EXTENSIONS 10
+
 #define ACTION_OUI_MAX_OUI_LENGTH 5
 #define ACTION_OUI_MAX_DATA_LENGTH 20
 #define ACTION_OUI_MAX_DATA_MASK_LENGTH 3
@@ -124,14 +135,12 @@ enum action_oui_id {
 	ACTION_OUI_SWITCH_TO_11N_MODE = 4,
 	ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN = 5,
 	ACTION_OUI_DISABLE_AGGRESSIVE_TX = 6,
-	ACTION_OUI_FORCE_MAX_NSS = 7,
-	ACTION_OUI_DISABLE_AGGRESSIVE_EDCA = 8,
-	ACTION_OUI_DISABLE_TWT = 9,
-	ACTION_OUI_EXTEND_WOW_ITO = 10,
-	ACTION_OUI_11BE_OUI_ALLOW = 11,
-	ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE = 12,
-	ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL = 13,
-	ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN = 14,
+	ACTION_OUI_DISABLE_TWT = 7,
+	ACTION_OUI_EXTEND_WOW_ITO = 8,
+	ACTION_OUI_11BE_OUI_ALLOW = 9,
+	ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE = 10,
+	ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL = 11,
+	ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN = 12,
 	/* host&fw interface add above here */
 
 	ACTION_OUI_HOST_ONLY,
@@ -139,6 +148,8 @@ enum action_oui_id {
 	ACTION_OUI_TAKE_ALL_BAND_INFO,
 	ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ,
 	ACTION_OUI_DISABLE_BFORMEE,
+	ACTION_OUI_FORCE_MAX_NSS,
+	ACTION_OUI_DISABLE_AGGRESSIVE_EDCA,
 	ACTION_OUI_MAXIMUM_ID
 };
 

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

@@ -35,11 +35,10 @@
 #include <wlan_cm_roam_api.h>
 #include "wlan_nan_api.h"
 #include "wlan_mlme_vdev_mgr_interface.h"
-#ifdef WLAN_FEATURE_11BE_MLO
 #include <wlan_mlo_mgr_sta.h>
-#endif
 #include "wlan_vdev_mgr_utils_api.h"
 #include "wlan_tdls_api.h"
+#include "wlan_mlo_mgr_link_switch.h"
 
 QDF_STATUS if_mgr_connect_start(struct wlan_objmgr_vdev *vdev,
 				struct if_mgr_event_data *event_data)
@@ -249,9 +248,9 @@ QDF_STATUS if_mgr_disconnect_complete(struct wlan_objmgr_vdev *vdev,
 		ifmgr_err("Failed to enable roaming after p2p disconnect");
 		return status;
 	}
-
-	policy_mgr_check_concurrent_intf_and_restart_sap(psoc,
-				wlan_util_vdev_mgr_get_acs_mode_for_vdev(vdev));
+	if (!mlo_is_mld_sta(vdev) || !mlo_mgr_is_link_switch_in_progress(vdev))
+		policy_mgr_check_concurrent_intf_and_restart_sap(
+			psoc, wlan_util_vdev_mgr_get_acs_mode_for_vdev(vdev));
 
 	status = if_mgr_enable_roaming_on_connected_sta(pdev, vdev);
 	if (status) {

+ 57 - 0
components/cmn_services/logging/inc/wlan_connectivity_logging.h

@@ -530,6 +530,7 @@ struct wlan_diag_bcn_rpt {
 } qdf_packed;
 
 #define DIAG_ROAM_CAND_VERSION 1
+#define DIAG_ROAM_CAND_VERSION_V2 2
 
 /**
  * struct wlan_diag_roam_candidate_info  - Roam candidate information for
@@ -1184,6 +1185,43 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     uint8_t auth_seq, uint16_t aid,
 			     enum wlan_main_tag tag);
 
+/**
+ * wlan_populate_vsie() - Populate VSIE field for logging
+ * @vdev: vdev pointer
+ * @data: Diag packet info data
+ * @is_tx: flag to indicate whether packet transmitted or received
+ *
+ * Return: None
+ */
+void
+wlan_populate_vsie(struct wlan_objmgr_vdev *vdev,
+		   struct wlan_diag_packet_info *data, bool is_tx);
+
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * wlan_connectivity_mlo_setup_event() - Fill and send MLO setup data
+ * @vdev: vdev pointer
+ *
+ * Return: None
+ */
+void wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * wlan_convert_freq_to_diag_band() - API to convert frequency to band value
+ * mentioned in enum wlan_diag_wifi_band
+ * @ch_freq: Frequency(in MHz)
+ *
+ * Return: Band specified in enum wlan_diag_wifi_band
+ */
+enum wlan_diag_wifi_band
+wlan_convert_freq_to_diag_band(uint16_t ch_freq);
+
+#else
+static inline
+void wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev)
+{
+}
+#endif
 static inline void wlan_connectivity_logging_stop(void)
 {}
 
@@ -1265,6 +1303,18 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     uint8_t auth_seq, uint16_t aid,
 			     enum wlan_main_tag tag);
 
+/**
+ * wlan_populate_vsie() - Populate VSIE field for logging
+ * @vdev: vdev pointer
+ * @data: Diag packet info data
+ * @is_tx: Flag to indicate whether the packet is transmitted or received
+ *
+ * Return: None
+ */
+void
+wlan_populate_vsie(struct wlan_objmgr_vdev *vdev,
+		   struct wlan_diag_packet_info *data, bool is_tx);
+
 /**
  * wlan_connectivity_sta_info_event() - APi to send STA info event
  * @psoc: Pointer to global psoc object
@@ -1304,6 +1354,13 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     uint8_t auth_seq, uint16_t aid,
 			     enum wlan_main_tag tag)
 {}
+
+static inline void
+wlan_populate_vsie(struct wlan_objmgr_vdev *vdev,
+		   struct wlan_diag_packet_info *data, bool is_tx)
+{
+}
+
 static inline void
 wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc,
 				 uint8_t vdev_id)

+ 194 - 6
components/cmn_services/logging/src/wlan_connectivity_logging.c

@@ -336,6 +336,147 @@ wlan_populate_link_addr(struct wlan_objmgr_vdev *vdev,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+static uint8_t
+wlan_populate_band_bitmap(struct mlo_link_switch_context *link_ctx)
+{
+	uint8_t i, band_bitmap = 0, band;
+	struct wlan_channel *link_chan_info;
+
+	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_bitmap |= BIT(band);
+	}
+
+	return band_bitmap;
+}
+
+static QDF_STATUS
+wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_diag_packet_info *data,
+				   enum wlan_main_tag tag)
+{
+	struct mlo_link_switch_context *link_ctx;
+	struct qdf_mac_addr peer_mac;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!mlo_is_mld_sta(vdev))
+		return status;
+
+	if (wlan_vdev_mlme_is_mlo_link_vdev(vdev))
+		return QDF_STATUS_E_INVAL;
+
+	status = wlan_vdev_get_bss_peer_mac(vdev, &peer_mac);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		logging_err("vdev: %d bss peer not found",
+			    wlan_vdev_get_id(vdev));
+		return status;
+	}
+
+	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);
+
+	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;
+		}
+
+		data->supported_links =
+			wlan_populate_band_bitmap(link_ctx);
+	}
+
+	return status;
+}
+
+enum wlan_diag_wifi_band
+wlan_convert_freq_to_diag_band(uint16_t ch_freq)
+{
+	enum reg_wifi_band band;
+
+	band = wlan_reg_freq_to_band((qdf_freq_t)ch_freq);
+
+	switch (band) {
+	case REG_BAND_2G:
+		return WLAN_24GHZ_BAND;
+	case REG_BAND_5G:
+		return WLAN_5GHZ_BAND;
+	case REG_BAND_6G:
+		return WLAN_6GHZ_BAND;
+	default:
+		return WLAN_INVALID_BAND;
+	}
+}
+
+#define REJECTED_LINK_STATUS 1
+
+void
+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;
+
+	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
+				 struct wlan_diag_mlo_setup);
+
+	if (!mlo_is_mld_sta(vdev))
+		return;
+
+	qdf_mem_zero(&wlan_diag_event, sizeof(struct wlan_diag_mlo_setup));
+
+	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;
+
+	if (!vdev->mlo_dev_ctx) {
+		logging_err("vdev: %d MLO dev ctx not found",
+			    wlan_vdev_get_id(vdev));
+		return;
+	}
+
+	link_ctx = vdev->mlo_dev_ctx->link_ctx;
+	if (!link_ctx) {
+		logging_err("vdev: %d mlo link ctx not found",
+			    wlan_vdev_get_id(vdev));
+		return;
+	}
+
+	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
+		wlan_diag_event.mlo_cmn_info[i].link_id =
+				link_ctx->links_info[i].link_id;
+		wlan_diag_event.mlo_cmn_info[i].vdev_id =
+				link_ctx->links_info[i].vdev_id;
+
+		qdf_mem_copy(wlan_diag_event.mlo_cmn_info[i].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_convert_freq_to_diag_band(chan_info->ch_freq);
+
+		if (wlan_diag_event.mlo_cmn_info[i].band == WLAN_INVALID_BAND)
+			wlan_diag_event.mlo_cmn_info[i].status =
+							REJECTED_LINK_STATUS;
+	}
+
+	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MLO_SETUP);
+}
+
 #else
 static QDF_STATUS
 wlan_populate_link_addr(struct wlan_objmgr_vdev *vdev,
@@ -343,6 +484,14 @@ wlan_populate_link_addr(struct wlan_objmgr_vdev *vdev,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static QDF_STATUS
+wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_diag_packet_info *data,
+				   enum wlan_main_tag tag)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 void
@@ -389,6 +538,28 @@ out:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
 }
 
+void
+wlan_populate_vsie(struct wlan_objmgr_vdev *vdev,
+		   struct wlan_diag_packet_info *data,
+		   bool is_tx)
+{
+	struct element_info *vsie_info = NULL;
+
+	if (is_tx)
+		vsie_info = mlme_get_self_disconnect_ies(vdev);
+	else
+		vsie_info = mlme_get_peer_disconnect_ies(vdev);
+
+	if (!vsie_info)
+		return;
+
+	data->vsie_len = vsie_info->len;
+	if (data->vsie_len > MAX_VSIE_LEN)
+		data->vsie_len = MAX_VSIE_LEN;
+
+	qdf_mem_copy(data->vsie, vsie_info->ptr, data->vsie_len);
+}
+
 void
 wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 			     struct wlan_frame_hdr *mac_hdr,
@@ -402,6 +573,7 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 	enum QDF_OPMODE opmode;
 	bool is_auth_frame_caching_required, is_initial_connection;
 	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
 
 	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_packet_info);
 
@@ -413,13 +585,14 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 	}
 
 	opmode = wlan_vdev_mlme_get_opmode(vdev);
-	if (opmode != QDF_STA_MODE) {
-		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
-		return;
-	}
+	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);
-	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
 
 	qdf_mem_zero(&wlan_diag_event, sizeof(struct wlan_diag_packet_info));
 
@@ -431,7 +604,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);
 
-	wlan_diag_event.version = DIAG_MGMT_VERSION;
+	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;
 	wlan_diag_event.tx_status = wlan_get_diag_tx_status(tx_status);
 	wlan_diag_event.rssi = peer_rssi;
 	wlan_diag_event.sn =
@@ -442,6 +621,9 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 	wlan_diag_event.auth_seq_num = auth_seq;
 	wlan_diag_event.assoc_id = aid;
 
+	if (tag == WLAN_DEAUTH_TX || tag == WLAN_DISASSOC_TX)
+		wlan_populate_vsie(vdev, &wlan_diag_event, true);
+
 	if (wlan_diag_event.subtype > WLAN_CONN_DIAG_REASSOC_RESP_EVENT &&
 	    wlan_diag_event.subtype < WLAN_CONN_DIAG_BMISS_EVENT)
 		wlan_diag_event.reason = status_code;
@@ -458,5 +640,11 @@ wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc,
 		wlan_cache_connectivity_log(psoc, vdev_id, &wlan_diag_event);
 	else
 		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);
+
 }
 #endif

+ 91 - 1
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -2129,6 +2129,8 @@ typedef void (*policy_mgr_nss_update_cback)(struct wlan_objmgr_psoc *psoc,
  * @sme_rso_stop_cb: Disable roaming offload callback
  * @sme_change_sap_csa_count: Change CSA count for SAP/GO, only one
  *			      time, needs to set again if used once.
+ * @sme_sap_update_ch_width: Update sap ch_width to fw to handle SAP 320MHz
+ *                           concurrencies
  */
 struct policy_mgr_sme_cbacks {
 	void (*sme_get_nss_for_vdev)(enum QDF_OPMODE,
@@ -2150,6 +2152,11 @@ struct policy_mgr_sme_cbacks {
 		mac_handle_t mac_handle, uint8_t vdev_id,
 		uint8_t reason, enum wlan_cm_rso_control_requestor requestor);
 	QDF_STATUS (*sme_change_sap_csa_count)(uint8_t count);
+	QDF_STATUS (*sme_sap_update_ch_width)(struct wlan_objmgr_psoc *psoc,
+			uint8_t vdev_id,
+			enum phy_ch_width ch_width,
+			enum policy_mgr_conn_update_reason reason,
+			uint8_t conc_vdev_id, uint32_t request_id);
 };
 
 /**
@@ -5087,9 +5094,23 @@ QDF_STATUS
 policy_mgr_clear_ml_links_settings_in_fw(struct wlan_objmgr_psoc *psoc,
 					 uint8_t vdev_id);
 
+/**
+ * policy_mgr_activate_mlo_links_nlink() - Force active ML links based on user
+ * requested link mac address with link bitmap
+ * @psoc: objmgr psoc
+ * @session_id: session id
+ * @num_links: number of links to be forced active
+ * @active_link_addr: link mac address of links to be forced active
+ *
+ * Return: void
+ */
+void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc,
+					 uint8_t session_id, uint8_t num_links,
+					 struct qdf_mac_addr *active_link_addr);
+
 /**
  * policy_mgr_activate_mlo_links() - Force active ML links based on user
- * requested link mac address
+ * requested link mac address with vdev bitmap
  * @psoc: objmgr psoc
  * @session_id: session id
  * @num_links: number of links to be forced active
@@ -5530,4 +5551,73 @@ uint32_t policy_mgr_get_beaconing_mode_info(struct wlan_objmgr_psoc *psoc,
 bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range,
 				  qdf_freq_t freq, uint8_t mac_id);
 
+/**
+ * policy_mgr_is_conn_lead_to_dbs_sbs() - New freq leads to DBS/SBS
+ * @psoc: PSOC object information
+ * @freq: New connection frequency
+ *
+ * This API loops through existing connections from policy_mgr connection table
+ *
+ * Return: True if new frequency causes DBS/SBS with existing connections
+ */
+bool
+policy_mgr_is_conn_lead_to_dbs_sbs(struct wlan_objmgr_psoc *psoc,
+				   uint32_t freq);
+
+/**
+ * policy_mgr_sap_ch_width_update() - Update SAP ch_width
+ * @psoc: PSOC object information
+ * @next_action: next action to happen in order to update bandwidth
+ * @reason: reason for ch_width update
+ * @conc_vdev_id: Concurrent connection vdev_id that is causing ch_width update
+ * @request_id: request id for connection manager
+ *
+ * Update ch_width as per next_action
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+policy_mgr_sap_ch_width_update(struct wlan_objmgr_psoc *psoc,
+			       enum policy_mgr_conc_next_action next_action,
+			       enum policy_mgr_conn_update_reason reason,
+			       uint8_t conc_vdev_id, uint32_t request_id);
+
+/*
+ * policy_mgr_get_vdev_same_freq_new_conn() - Get vdev_id of the first
+ *					      connection that has same
+ *					      channel frequency as new_freq
+ * @psoc: psoc object pointer
+ * @new_freq: channel frequency for the new connection
+ * @vdev_id: Output parameter to return vdev id of the first existing connection
+ *	     that has same channel frequency as @new_freq
+ *
+ * This function is to return the first connection that has same
+ * channel frequency as @new_freq.
+ *
+ * Return: true if connection that has same channel frequency as
+ *	   @new_freq exists. Otherwise false.
+ */
+bool policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+					    uint32_t new_freq,
+					    uint8_t *vdev_id);
+
+/*
+ * policy_mgr_get_vdev_diff_freq_new_conn() - Get vdev id of the first
+ *					      connection that has different
+ *					      channel freq from new_freq
+ * @psoc: psoc object pointer
+ * @new_freq: channel frequency for the new connection
+ * @vdev_id: Output parameter to return vdev id of the first existing connection
+ *	     that has different channel frequency from @new_freq
+ *
+ * This function is to return the first connection that has different
+ * channel frequency from @new_freq.
+ *
+ * Return: true if connection that has different channel frequency from
+ *	   @new_freq exists. Otherwise false.
+ */
+bool policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+					    uint32_t new_freq,
+					    uint8_t *vdev_id);
+
 #endif /* __WLAN_POLICY_MGR_API_H */

+ 11 - 1
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h

@@ -1163,6 +1163,8 @@ enum policy_mgr_three_connection_mode {
  * @PM_DBS2_DOWNGRADE: downgrade 5G beaconing entity to 1x1 and switch to DBS2.
  * @PM_UPGRADE_5G: upgrade 5g beaconing entity to 2x2.
  * @PM_UPGRADE_2G: upgrade 2g beaconing entity to 2x2.
+ * @PM_DOWNGRADE_BW: Downgrade SAP bandwidth.
+ * @PM_UPGRADE_BW: Upgrade SAP bandwidth.
  * @PM_MAX_CONC_NEXT_ACTION: Max place holder
  *
  * These are generic IDs that identify the various roles
@@ -1185,6 +1187,8 @@ enum policy_mgr_conc_next_action {
 	PM_DBS2_DOWNGRADE,
 	PM_UPGRADE_5G,
 	PM_UPGRADE_2G,
+	PM_DOWNGRADE_BW,
+	PM_UPGRADE_BW,
 
 	PM_MAX_CONC_NEXT_ACTION
 };
@@ -1224,8 +1228,9 @@ enum policy_mgr_band {
  *        to the other DBS mode. This reason code indicates such condition.
  * @POLICY_MGR_UPDATE_REASON_NAN_DISCOVERY: NAN Discovery related
  * @POLICY_MGR_UPDATE_REASON_NDP_UPDATE: NAN Datapath related update
- * @POLICY_MGR_UPDATE_REASON_LFR2_ROAM: Roaming
+ * @POLICY_MGR_UPDATE_REASON_LFR2_ROAM: LFR2 Roaming
  * @POLICY_MGR_UPDATE_REASON_STA_CONNECT: STA/CLI connection to peer
+ * @POLICY_MGR_UPDATE_REASON_LFR3_ROAM: LFR3 Roaming
  */
 enum policy_mgr_conn_update_reason {
 	POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN,
@@ -1242,6 +1247,7 @@ enum policy_mgr_conn_update_reason {
 	POLICY_MGR_UPDATE_REASON_NDP_UPDATE,
 	POLICY_MGR_UPDATE_REASON_LFR2_ROAM,
 	POLICY_MGR_UPDATE_REASON_STA_CONNECT,
+	POLICY_MGR_UPDATE_REASON_LFR3_ROAM,
 };
 
 /**
@@ -1560,6 +1566,8 @@ struct policy_mgr_freq_range {
  * @MODE_SBS_UPPER_SHARE:   Higher 5Ghz shared with 2.4Ghz
  * @MODE_SBS_LOWER_SHARE:   LOWER 5Ghz shared with 2.4Ghz
  * @MODE_EMLSR:             eMLSR mode
+ * @MODE_EMLSR_SINGLE:	    eMLSR split mode
+ * @MODE_EMLSR_SPLIT:	    eMLSR split mode
  * @MODE_HW_MAX: MAX
  */
 enum policy_mgr_mode {
@@ -1569,6 +1577,8 @@ enum policy_mgr_mode {
 	MODE_SBS_UPPER_SHARE,
 	MODE_SBS_LOWER_SHARE,
 	MODE_EMLSR,
+	MODE_EMLSR_SINGLE,
+	MODE_EMLSR_SPLIT,
 	MODE_HW_MAX,
 };
 

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

@@ -396,4 +396,62 @@ ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl(struct wlan_objmgr_psoc *psoc);
  * Return: true if DBS is supported else false
  */
 bool ucfg_policy_mgr_is_fw_supports_dbs(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_policy_mgr_get_connection_count() - Get number of connections
+ * @psoc: pointer to psoc
+ *
+ * This API is used to get the count of current connections.
+ *
+ * Return: connection count
+ */
+uint32_t ucfg_policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_policy_mgr_is_hw_sbs_capable() - Check if HW is SBS capable
+ * @psoc: pointer to psoc
+ *
+ * This API is to check if the HW is SBS capable.
+ *
+ * Return: true if the HW is SBS capable
+ */
+bool ucfg_policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc);
+
+/*
+ * ucfg_policy_mgr_get_vdev_same_freq_new_conn() - Get vdev_id of the first
+ *					           connection that has same
+ *					           channel frequency as new_freq
+ * @psoc: psoc object pointer
+ * @new_freq: channel frequency for the new connection
+ * @vdev_id: Output parameter to return vdev id of the first existing connection
+ *	     that has same channel frequency as @new_freq
+ *
+ * This function is to return the first connection that has same
+ * channel frequency as @new_freq.
+ *
+ * Return: true if connection that has same channel frequency as
+ *	   @new_freq exists. Otherwise false.
+ */
+bool ucfg_policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+						 uint32_t new_freq,
+						 uint8_t *vdev_id);
+/*
+ * ucfg_policy_mgr_get_vdev_diff_freq_new_conn() - Get vdev id of the first
+ *						   connection that has different
+ *						   channel freq from new_freq
+ * @psoc: psoc object pointer
+ * @new_freq: channel frequency for the new connection
+ * @vdev_id: Output parameter to return vdev id of the first existing connection
+ *	     that has different channel frequency from @new_freq
+ *
+ * This function is to return the first connection that has different
+ * channel frequency from @new_freq.
+ *
+ * Return: true if connection that has different channel frequency from
+ *	   @new_freq exists. Otherwise false.
+ */
+bool ucfg_policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+						 uint32_t new_freq,
+						 uint8_t *vdev_id);
+
 #endif //__WLAN_POLICY_MGR_UCFG

+ 153 - 5
components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c

@@ -41,6 +41,9 @@
 #include "target_if.h"
 #include "wlan_cm_api.h"
 #include "wlan_mlo_link_force.h"
+#include "wlan_mlo_mgr_sta.h"
+#include "wlan_mlo_mgr_link_switch.h"
+#include "wlan_psoc_mlme_api.h"
 
 enum policy_mgr_conc_next_action (*policy_mgr_get_current_pref_hw_mode_ptr)
 	(struct wlan_objmgr_psoc *psoc);
@@ -220,6 +223,64 @@ QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * policy_mgr_get_sap_ch_width_update_action() - get SAP ch_width update action
+ * @psoc: Pointer to psoc
+ * @ch_freq: channel frequency of new connection
+ * @next_action: next action to happen in order to update bandwidth
+ *
+ * Check if current operating SAP needs a downgrade to 160MHz or an upgrade
+ * to 320MHz based on the new connection.
+ *
+ * return : None
+ */
+static void
+policy_mgr_get_sap_ch_width_update_action(struct wlan_objmgr_psoc *psoc,
+				uint32_t ch_freq,
+				enum policy_mgr_conc_next_action *next_action)
+{
+	struct wlan_objmgr_vdev *vdev;
+	enum phy_ch_width cur_bw;
+	uint32_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1];
+	uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1];
+	bool eht_capab = false;
+
+	if (QDF_IS_STATUS_ERROR(wlan_psoc_mlme_get_11be_capab(psoc,
+							      &eht_capab)) ||
+	    !eht_capab ||
+	    policy_mgr_get_mode_specific_conn_info(psoc, &freq_list[0],
+						   &vdev_id_list[0],
+						   PM_SAP_MODE) != 1)
+		return;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id_list[0],
+						    WLAN_POLICY_MGR_ID);
+	if (!vdev) {
+		policy_mgr_err("vdev %d is NULL", vdev_id_list[0]);
+		return;
+	}
+
+	cur_bw = wlan_mlme_get_ap_oper_ch_width(vdev);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+
+	if (cur_bw < CH_WIDTH_160MHZ)
+		return;
+
+	if (!ch_freq) {
+		if (policy_mgr_get_connection_count(psoc) == 1 ||
+		    (!policy_mgr_is_current_hwmode_dbs(psoc) &&
+		     !policy_mgr_is_current_hwmode_sbs(psoc)))
+			*next_action = PM_UPGRADE_BW;
+		return;
+	}
+
+	if (cur_bw == CH_WIDTH_320MHZ &&
+	    policy_mgr_is_conn_lead_to_dbs_sbs(psoc, ch_freq))
+		*next_action = PM_DOWNGRADE_BW;
+	else
+		*next_action = PM_UPGRADE_BW;
+}
+
 enum policy_mgr_conc_next_action policy_mgr_need_opportunistic_upgrade(
 		struct wlan_objmgr_psoc *psoc,
 		enum policy_mgr_conn_update_reason *reason)
@@ -234,6 +295,7 @@ enum policy_mgr_conc_next_action policy_mgr_need_opportunistic_upgrade(
 
 	if (policy_mgr_is_hwmode_offload_enabled(psoc)) {
 		policy_mgr_debug("HW mode selection offload is enabled");
+		policy_mgr_get_sap_ch_width_update_action(psoc, 0, &upgrade);
 		return upgrade;
 	}
 
@@ -843,6 +905,27 @@ policy_mgr_get_third_conn_action_table(
 	}
 }
 
+bool
+policy_mgr_is_conn_lead_to_dbs_sbs(struct wlan_objmgr_psoc *psoc,
+				   uint32_t freq)
+{
+	struct connection_info info[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
+	uint32_t connection_count, i;
+
+	if (policy_mgr_is_current_hwmode_dbs(psoc) ||
+	    policy_mgr_is_current_hwmode_sbs(psoc))
+		return true;
+
+	connection_count = policy_mgr_get_connection_info(psoc, info);
+
+	for (i = 0; i < connection_count; i++)
+		if (!policy_mgr_2_freq_always_on_same_mac(psoc, freq,
+							  info[i].ch_freq))
+			return true;
+
+	return false;
+}
+
 static QDF_STATUS
 policy_mgr_get_next_action(struct wlan_objmgr_psoc *psoc,
 			   uint32_t session_id,
@@ -867,6 +950,8 @@ policy_mgr_get_next_action(struct wlan_objmgr_psoc *psoc,
 	if (policy_mgr_is_hwmode_offload_enabled(psoc)) {
 		policy_mgr_debug("HW mode selection offload is enabled");
 		*next_action = PM_NOP;
+		policy_mgr_get_sap_ch_width_update_action(psoc, ch_freq,
+							  next_action);
 		return QDF_STATUS_SUCCESS;
 	}
 
@@ -982,6 +1067,20 @@ policy_mgr_is_hw_mode_change_required(struct wlan_objmgr_psoc *psoc,
 	return false;
 }
 
+static bool
+policy_mgr_is_ch_width_downgrade_required(struct wlan_objmgr_psoc *psoc,
+					  struct scan_cache_entry *entry,
+					  qdf_list_t *scan_list)
+
+{
+	if (policy_mgr_is_conn_lead_to_dbs_sbs(psoc,
+					       entry->channel.chan_freq) ||
+	    wlan_cm_bss_mlo_type(psoc, entry, scan_list))
+		return true;
+
+	return false;
+}
+
 static uint32_t
 policy_mgr_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 				    qdf_list_t *scan_list, uint8_t vdev_id)
@@ -991,10 +1090,18 @@ policy_mgr_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
 	uint32_t ch_freq = 0;
 	struct scan_cache_entry *entry;
+	bool eht_capab =  false, check_sap_bw_downgrade = false;
 
 	if (policy_mgr_is_hwmode_offload_enabled(psoc)) {
 		policy_mgr_debug("HW mode selection offload is enabled");
-		goto end;
+		wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab);
+		if (eht_capab &&
+		    policy_mgr_mode_specific_connection_count(psoc,
+							      PM_SAP_MODE,
+							      NULL) == 1)
+			check_sap_bw_downgrade = true;
+		else
+			goto end;
 	}
 
 	if (!scan_list || !qdf_list_size(scan_list)) {
@@ -1007,6 +1114,9 @@ policy_mgr_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 		goto end;
 	}
 
+	if (check_sap_bw_downgrade)
+		goto ch_width_update;
+
 	if (!policy_mgr_is_dbs_allowed_for_concurrency(psoc, QDF_STA_MODE)) {
 		policy_mgr_debug("DBS not allowed for concurrency combo");
 		goto end;
@@ -1020,6 +1130,7 @@ policy_mgr_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 		goto end;
 	}
 
+ch_width_update:
 	qdf_list_peek_front(scan_list, &cur_node);
 
 	while (cur_node) {
@@ -1031,8 +1142,10 @@ policy_mgr_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 		ch_freq = entry->channel.chan_freq;
 
 		if (policy_mgr_is_hw_mode_change_required(psoc, ch_freq,
-							  vdev_id)) {
-			policy_mgr_debug("Scan list has BSS of freq %d hw mode required",
+							  vdev_id) ||
+		    policy_mgr_is_ch_width_downgrade_required(psoc, entry,
+							      scan_list)) {
+			policy_mgr_debug("Scan list has BSS of freq %d hw mode/ch_width update required",
 					 ch_freq);
 			break;
 		}
@@ -1446,6 +1559,17 @@ QDF_STATUS policy_mgr_next_actions(
 					PM_NOP, POLICY_MGR_BAND_24, reason,
 					session_id, request_id);
 		break;
+	case PM_DOWNGRADE_BW:
+		policy_mgr_sap_ch_width_update(psoc, action, reason,
+					       session_id, request_id);
+		break;
+	case PM_UPGRADE_BW:
+		if (reason == POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC)
+			policy_mgr_sap_ch_width_update(psoc, action, reason,
+						       session_id, request_id);
+		else
+			policy_mgr_restart_opportunistic_timer(psoc, false);
+		break;
 	default:
 		policy_mgr_err("unexpected action value %d", action);
 		status = QDF_STATUS_E_FAILURE;
@@ -2479,7 +2603,7 @@ policy_mgr_check_sap_go_force_scc(struct wlan_objmgr_psoc *psoc,
  * @psoc: PSOC object information
  *
  * This function will check connection table and find any STA/CLI
- * in transition state such as disconnecting, or roaming.
+ * in transition state such as disconnecting, link switch or roaming.
  *
  * Return: true if there is one STA/CLI in transition state.
  */
@@ -2491,6 +2615,7 @@ policy_mgr_is_any_conn_in_transition(struct wlan_objmgr_psoc *psoc)
 	struct policy_mgr_conc_connection_info *conn_info;
 	struct wlan_objmgr_vdev *vdev;
 	bool non_connected = false;
+	bool in_link_switch = false;
 	uint8_t vdev_id;
 
 	pm_ctx = policy_mgr_get_context(psoc);
@@ -2515,16 +2640,26 @@ policy_mgr_is_any_conn_in_transition(struct wlan_objmgr_psoc *psoc)
 		}
 
 		non_connected = !wlan_cm_is_vdev_connected(vdev);
+
+		if (mlo_is_mld_sta(vdev) &&
+		    mlo_mgr_is_link_switch_in_progress(vdev))
+			in_link_switch = true;
+
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
 		if (non_connected) {
 			policy_mgr_debug("vdev %d: is in transition state",
 					 vdev_id);
 			break;
 		}
+		if (in_link_switch) {
+			policy_mgr_debug("vdev %d: sta mld is in link switch state",
+					 vdev_id);
+			break;
+		}
 	}
 	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 
-	return non_connected;
+	return non_connected || in_link_switch;
 }
 
 static void __policy_mgr_check_sta_ap_concurrent_ch_intf(
@@ -2604,6 +2739,8 @@ static void __policy_mgr_check_sta_ap_concurrent_ch_intf(
 	 */
 	if (policy_mgr_is_any_conn_in_transition(pm_ctx->psoc)) {
 		policy_mgr_debug("defer sap conc check to a later time due to another sta/cli dicon/roam pending");
+		qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work,
+				       SAP_CONC_CHECK_DEFER_TIMEOUT_MS);
 		goto end;
 	}
 
@@ -3705,6 +3842,7 @@ QDF_STATUS policy_mgr_check_and_set_hw_mode_for_channel_switch(
 	uint8_t num_cxn_del = 0;
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
 	enum policy_mgr_conc_next_action next_action = PM_NOP;
+	bool eht_capab =  false;
 
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {
@@ -3712,6 +3850,15 @@ QDF_STATUS policy_mgr_check_and_set_hw_mode_for_channel_switch(
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab);
+	if (eht_capab &&
+	    policy_mgr_mode_specific_connection_count(psoc,
+						      PM_SAP_MODE,
+						      NULL) == 1) {
+		policy_mgr_stop_opportunistic_timer(psoc);
+		goto ch_width_update;
+	}
+
 	if (!policy_mgr_is_hw_dbs_capable(psoc) ||
 	    (!policy_mgr_is_hw_dbs_2x2_capable(psoc) &&
 	    !policy_mgr_is_hw_dbs_required_for_band(
@@ -3728,6 +3875,7 @@ QDF_STATUS policy_mgr_check_and_set_hw_mode_for_channel_switch(
 	if (wlan_reg_freq_to_band(ch_freq) != REG_BAND_2G)
 		return QDF_STATUS_E_NOSUPPORT;
 
+ch_width_update:
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	/*
 	 * Store the connection's parameter and temporarily delete it

+ 42 - 1
components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c

@@ -2057,7 +2057,8 @@ void pm_dbs_opportunistic_timer_handler(void *data)
 	enum policy_mgr_conc_next_action action = PM_NOP;
 	uint32_t session_id;
 	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)data;
-	enum policy_mgr_conn_update_reason reason;
+	enum policy_mgr_conn_update_reason reason =
+				POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC;
 	struct policy_mgr_psoc_priv_obj *pm_ctx = policy_mgr_get_context(psoc);
 
 	if (!psoc) {
@@ -4365,6 +4366,46 @@ static void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc,
 	return;
 }
 
+QDF_STATUS
+policy_mgr_sap_ch_width_update(struct wlan_objmgr_psoc *psoc,
+			       enum policy_mgr_conc_next_action next_action,
+			       enum policy_mgr_conn_update_reason reason,
+			       uint8_t conc_vdev_id, uint32_t request_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t freq;
+	uint8_t sap_vdev_id;
+	enum phy_ch_width target_bw;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	policy_mgr_debug("action: %d reason: %d", next_action, reason);
+
+	policy_mgr_get_mode_specific_conn_info(psoc, &freq,
+					       &sap_vdev_id,
+					       PM_SAP_MODE);
+	if (next_action == PM_DOWNGRADE_BW)
+		target_bw = CH_WIDTH_160MHZ;
+	else
+		target_bw = CH_WIDTH_320MHZ;
+
+	status = pm_ctx->sme_cbacks.sme_sap_update_ch_width(psoc,
+							    sap_vdev_id,
+							    target_bw, reason,
+							    conc_vdev_id,
+							    request_id);
+	if (QDF_IS_STATUS_ERROR(status))
+		policy_mgr_err("vdev %d failed to set BW to %d",
+			       sap_vdev_id, target_bw);
+
+	return status;
+}
+
 QDF_STATUS policy_mgr_nss_update(struct wlan_objmgr_psoc *psoc,
 		uint8_t  new_nss, uint8_t next_action,
 		enum policy_mgr_band band,

+ 197 - 13
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -1369,6 +1369,8 @@ policy_mgr_update_mac_freq_info(struct wlan_objmgr_psoc *psoc,
 
 		break;
 	case WMI_HW_MODE_EMLSR:
+	case WMI_HW_MODE_AUX_EMLSR_SINGLE:
+	case WMI_HW_MODE_AUX_EMLSR_SPLIT:
 		policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_EMLSR,
 					    phy_id);
 		break;
@@ -6083,22 +6085,24 @@ policy_mgr_mlo_sta_set_link_by_linkid(struct wlan_objmgr_psoc *psoc,
 	uint32_t vdev_bitmap2[MLO_VDEV_BITMAP_SZ];
 	uint8_t i, idx;
 	uint32_t link_control_flags = 0;
+	uint8_t vdev_per_bitmap = MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT;
 
 	qdf_mem_zero(vdev_bitmap, sizeof(vdev_bitmap));
 	qdf_mem_zero(vdev_bitmap2, sizeof(vdev_bitmap2));
 
 	for (i = 0; i < num_mlo_vdev; i++) {
-		idx = mlo_vdev_lst[i] / 32;
+		idx = mlo_vdev_lst[i] / vdev_per_bitmap;
 		if (idx >= MLO_VDEV_BITMAP_SZ)
 			return QDF_STATUS_E_INVAL;
-		vdev_bitmap[idx] |= 1 << (mlo_vdev_lst[i] % 32);
+		vdev_bitmap[idx] |= 1 << (mlo_vdev_lst[i] % vdev_per_bitmap);
 	}
 
 	for (i = 0; i < num_mlo_inactive_vdev; i++) {
-		idx = mlo_inactive_vdev_lst[i] / 32;
+		idx = mlo_inactive_vdev_lst[i] / vdev_per_bitmap;
 		if (idx >= MLO_VDEV_BITMAP_SZ)
 			return QDF_STATUS_E_INVAL;
-		vdev_bitmap2[idx] |= 1 << (mlo_inactive_vdev_lst[i] % 32);
+		vdev_bitmap2[idx] |=
+			1 << (mlo_inactive_vdev_lst[i] % vdev_per_bitmap);
 	}
 
 	ml_nlink_convert_vdev_bitmap_to_linkid_bitmap(
@@ -6534,7 +6538,8 @@ policy_mgr_is_mlo_sap_concurrency_allowed(struct wlan_objmgr_psoc *psoc,
 
 QDF_STATUS
 policy_mgr_link_switch_notifier_cb(struct wlan_objmgr_vdev *vdev,
-				   struct wlan_mlo_link_switch_req *req)
+				   struct wlan_mlo_link_switch_req *req,
+				   enum wlan_mlo_link_switch_notify_reason notify_reason)
 {
 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
@@ -6549,19 +6554,24 @@ policy_mgr_link_switch_notifier_cb(struct wlan_objmgr_vdev *vdev,
 	uint8_t num_del = 0;
 	struct ml_nlink_change_event data;
 
+	if (notify_reason > MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER)
+		return QDF_STATUS_SUCCESS;
+
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {
 		policy_mgr_err("Invalid Context");
 		return QDF_STATUS_E_INVAL;
 	}
 
-	policy_mgr_debug("target link %d freq %d curr link %d vdev %d",
+	policy_mgr_debug("target link %d freq %d curr link %d notify reason %d link switch reason %d vdev %d",
 			 new_ieee_link_id, new_primary_freq,
-			 curr_ieee_link_id, vdev_id);
+			 curr_ieee_link_id, notify_reason, req->reason,
+			 vdev_id);
 	qdf_mem_zero(&data, sizeof(data));
 	data.evt.link_switch.curr_ieee_link_id = curr_ieee_link_id;
 	data.evt.link_switch.new_ieee_link_id = new_ieee_link_id;
 	data.evt.link_switch.new_primary_freq = new_primary_freq;
+	data.evt.link_switch.reason = req->reason;
 	status = ml_nlink_conn_change_notify(psoc, vdev_id,
 					     ml_nlink_link_switch_start_evt,
 					     &data);
@@ -6836,22 +6846,36 @@ void policy_mgr_handle_emlsr_sta_concurrency(struct wlan_objmgr_psoc *psoc,
 	uint8_t num_mlo = 0;
 	uint8_t mlo_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
 	bool is_mlo_emlsr = false;
+	uint8_t num_disabled_ml_sta = 0;
+	qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
 
-	is_mlo_emlsr = policy_mgr_is_mlo_in_mode_emlsr(psoc, mlo_vdev_lst,
-						       &num_mlo);
-
-	if (num_mlo < 2) {
-		policy_mgr_debug("conc_con_coming_up %d num mlo sta links %d",
-				 conc_con_coming_up, num_mlo);
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
 		return;
 	}
 
+	is_mlo_emlsr = policy_mgr_is_mlo_in_mode_emlsr(psoc, mlo_vdev_lst,
+						       &num_mlo);
 	policy_mgr_debug("num_mlo %d is_mlo_emlsr %d conc_con_coming_up: %d",
 			 num_mlo, is_mlo_emlsr, conc_con_coming_up);
 
 	if (!is_mlo_emlsr)
 		return;
 
+	if (num_mlo < 2) {
+		policy_mgr_debug("conc_con_coming_up %d num mlo sta links %d",
+				 conc_con_coming_up, num_mlo);
+		policy_mgr_get_ml_sta_info(pm_ctx, &num_mlo,
+					   &num_disabled_ml_sta,
+					   mlo_vdev_lst, ml_freq_lst,
+					   NULL, NULL, NULL);
+		if (policy_mgr_get_connection_count(psoc) != 1 ||
+		    !num_disabled_ml_sta)
+			return;
+	}
+
 	if (conc_con_coming_up ||
 	    (emlsr_sta_coming_up &&
 	     policy_mgr_get_connection_count(psoc) > 2)) {
@@ -8200,6 +8224,105 @@ policy_mgr_is_restart_sap_required_with_mlo_sta(struct wlan_objmgr_psoc *psoc,
 	return restart_required;
 }
 
+void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc,
+					 uint8_t session_id, uint8_t num_links,
+					 struct qdf_mac_addr active_link_addr[2])
+{
+	uint8_t *link_mac_addr;
+	uint32_t link_ctrl_flags;
+	enum mlo_link_force_reason reason;
+	enum mlo_link_force_mode mode;
+	struct wlan_objmgr_vdev *vdev;
+	struct mlo_link_info *link_info;
+	bool active_link_present = false;
+	uint8_t iter, link, active_link_cnt = 0, inactive_link_cnt = 0;
+	uint32_t active_link_bitmap = 0;
+	uint32_t inactive_link_bitmap = 0;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, session_id,
+						    WLAN_POLICY_MGR_ID);
+	if (!vdev) {
+		policy_mgr_err("vdev_id: %d vdev not found", session_id);
+		return;
+	}
+
+	if (!wlan_cm_is_vdev_connected(vdev)) {
+		policy_mgr_err("vdev is not in connected state");
+		goto done;
+	}
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		policy_mgr_err("vdev is not mlo vdev");
+		goto done;
+	}
+
+	policy_mgr_debug("Num active links: %d", num_links);
+	link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0];
+	for (iter = 0; iter < WLAN_MAX_ML_BSS_LINKS; iter++) {
+		if (link_info->link_id == WLAN_INVALID_LINK_ID) {
+			link_info++;
+			continue;
+		}
+
+		link_mac_addr = &link_info->link_addr.bytes[0];
+		policy_mgr_debug("link addr: " QDF_MAC_ADDR_FMT,
+				 QDF_MAC_ADDR_REF(link_mac_addr));
+
+		for (link = 0; link < num_links; link++) {
+			policy_mgr_debug("active addr: " QDF_MAC_ADDR_FMT,
+			   QDF_MAC_ADDR_REF(&active_link_addr[link].bytes[0]));
+			if (!qdf_mem_cmp(link_mac_addr,
+					 &active_link_addr[link].bytes[0],
+					 QDF_MAC_ADDR_SIZE)) {
+				active_link_bitmap |= 1 << link_info->link_id;
+				active_link_cnt++;
+				active_link_present = true;
+				policy_mgr_debug("Link address match");
+			}
+		}
+		if (!active_link_present) {
+			inactive_link_bitmap |= 1 << link_info->link_id;
+			inactive_link_cnt++;
+			policy_mgr_err("No link address match");
+		}
+		active_link_present = false;
+		link_info++;
+	}
+
+	policy_mgr_debug("active link cnt: %d, inactive link cnt: %d",
+			 active_link_cnt, inactive_link_cnt);
+
+	if (!active_link_cnt) {
+		goto done;
+	} else if (policy_mgr_is_emlsr_sta_concurrency_present(psoc)) {
+		policy_mgr_debug("Concurrency exists, cannot enter EMLSR mode");
+		goto done;
+	}
+
+	/*
+	 * If there are both active and inactive vdev count, then issue a
+	 * single WMI with force mode MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE,
+	 * 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) {
+		reason = MLO_LINK_FORCE_REASON_CONNECT;
+		mode = MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE;
+		link_ctrl_flags = link_ctrl_f_overwrite_active_bitmap |
+					link_ctrl_f_overwrite_inactive_bitmap;
+	} else {
+		reason = MLO_LINK_FORCE_REASON_DISCONNECT;
+		mode = MLO_LINK_FORCE_MODE_ACTIVE;
+		link_ctrl_flags = link_ctrl_f_overwrite_active_bitmap;
+	}
+
+	policy_mgr_mlo_sta_set_nlink(psoc, vdev, reason, mode, 0,
+				     active_link_bitmap, inactive_link_bitmap,
+				     link_ctrl_flags);
+done:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+}
+
 void policy_mgr_activate_mlo_links(struct wlan_objmgr_psoc *psoc,
 				   uint8_t session_id, uint8_t num_links,
 				   struct qdf_mac_addr active_link_addr[2])
@@ -12100,3 +12223,64 @@ bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range,
 {
 	return IS_FREQ_ON_MAC_ID(freq_range, freq, mac_id);
 }
+
+bool policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+					    uint32_t new_freq,
+					    uint8_t *vdev_id)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool match = false;
+	uint32_t i;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (qdf_unlikely(!pm_ctx)) {
+		policy_mgr_err("Invalid pm_ctx");
+		return false;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
+		if (pm_conc_connection_list[i].in_use &&
+		    pm_conc_connection_list[i].freq == new_freq) {
+			match = true;
+			*vdev_id = pm_conc_connection_list[i].vdev_id;
+			policy_mgr_debug("new_freq %d matched with vdev_id %d",
+					 new_freq, *vdev_id);
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return match;
+}
+
+bool policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+					    uint32_t new_freq,
+					    uint8_t *vdev_id)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool match = false;
+	uint32_t i;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (qdf_unlikely(!pm_ctx)) {
+		policy_mgr_err("Invalid pm_ctx");
+		return false;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
+		if (pm_conc_connection_list[i].in_use &&
+		    pm_conc_connection_list[i].freq != new_freq) {
+			match = true;
+			*vdev_id = pm_conc_connection_list[i].vdev_id;
+			policy_mgr_debug("new_freq %d matched with vdev_id %d",
+					 new_freq, *vdev_id);
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return match;
+}
+

+ 3 - 1
components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h

@@ -792,6 +792,7 @@ policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx);
  * policy_mgr_link_switch_notifier_cb() - link switch notifier callback
  * @vdev: vdev object
  * @req: link switch request
+ * @notify_reason: Reason for notification
  *
  * This API will be registered to mlo link switch, to be invoked before
  * do link switch process.
@@ -800,7 +801,8 @@ policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx);
  */
 QDF_STATUS
 policy_mgr_link_switch_notifier_cb(struct wlan_objmgr_vdev *vdev,
-				   struct wlan_mlo_link_switch_req *req);
+				   struct wlan_mlo_link_switch_req *req,
+				   enum wlan_mlo_link_switch_notify_reason notify_reason);
 #else
 static inline void
 policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx) {}

+ 2 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c

@@ -797,6 +797,8 @@ QDF_STATUS policy_mgr_register_sme_cb(struct wlan_objmgr_psoc *psoc,
 		sme_cbacks->sme_rso_stop_cb;
 	pm_ctx->sme_cbacks.sme_change_sap_csa_count =
 		sme_cbacks->sme_change_sap_csa_count;
+	pm_ctx->sme_cbacks.sme_sap_update_ch_width =
+		sme_cbacks->sme_sap_update_ch_width;
 
 	return QDF_STATUS_SUCCESS;
 }

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

@@ -337,3 +337,28 @@ bool ucfg_policy_mgr_is_fw_supports_dbs(struct wlan_objmgr_psoc *psoc)
 {
 	return policy_mgr_find_if_fw_supports_dbs(psoc);
 }
+
+uint32_t ucfg_policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc)
+{
+	return policy_mgr_get_connection_count(psoc);
+}
+
+bool ucfg_policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc)
+{
+	return policy_mgr_is_hw_dbs_capable(psoc);
+}
+
+bool ucfg_policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+						 uint32_t new_freq,
+						 uint8_t *vdev_id)
+{
+	return policy_mgr_get_vdev_same_freq_new_conn(psoc, new_freq, vdev_id);
+}
+
+bool ucfg_policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc,
+						 uint32_t new_freq,
+						 uint8_t *vdev_id)
+{
+	return policy_mgr_get_vdev_diff_freq_new_conn(psoc, new_freq, vdev_id);
+}
+

+ 3 - 1
components/dp/core/inc/wlan_dp_main.h

@@ -333,12 +333,14 @@ QDF_STATUS wlan_dp_txrx_pdev_detach(ol_txrx_soc_handle soc, uint8_t pdev_id,
  * dp_link_switch_notification() - DP notifier for MLO link switch
  * @vdev: Objmgr vdev handle
  * @lswitch_req: Link switch request params
+ * @notify_reason: Reason of notification
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS
 dp_link_switch_notification(struct wlan_objmgr_vdev *vdev,
-			    struct wlan_mlo_link_switch_req *lswitch_req);
+			    struct wlan_mlo_link_switch_req *lswitch_req,
+			    enum wlan_mlo_link_switch_notify_reason notify_reason);
 #endif
 
 /**

+ 17 - 1
components/dp/core/src/wlan_dp_fisa_rx.c

@@ -913,6 +913,7 @@ void dp_fisa_rx_fst_update_work(void *arg)
 	struct dp_rx_fst *fisa_hdl = arg;
 	qdf_list_node_t *node;
 	hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc;
+	struct dp_vdev *vdev;
 
 	if (qdf_atomic_read(&fisa_hdl->pm_suspended)) {
 		dp_err_rl("WQ triggered during suspend stage, deferred update");
@@ -930,7 +931,21 @@ void dp_fisa_rx_fst_update_work(void *arg)
 	while (qdf_list_peek_front(&fisa_hdl->fst_update_list, &node) ==
 	       QDF_STATUS_SUCCESS) {
 		elem = (struct dp_fisa_rx_fst_update_elem *)node;
-		dp_fisa_rx_fst_update(fisa_hdl, elem);
+		vdev = dp_vdev_get_ref_by_id(fisa_hdl->soc_hdl,
+					     elem->vdev_id,
+					     DP_MOD_ID_RX);
+		/*
+		 * Update fst only if current dp_vdev fetched by vdev_id is
+		 * still valid and match with the original dp_vdev when fst
+		 * node is queued.
+		 */
+		if (vdev) {
+			if (vdev == elem->vdev)
+				dp_fisa_rx_fst_update(fisa_hdl, elem);
+
+			dp_vdev_unref_delete(fisa_hdl->soc_hdl, vdev,
+					     DP_MOD_ID_RX);
+		}
 		qdf_list_remove_front(&fisa_hdl->fst_update_list, &node);
 		qdf_mem_free(elem);
 	}
@@ -1043,6 +1058,7 @@ dp_fisa_rx_queue_fst_update_work(struct dp_rx_fst *fisa_hdl, uint32_t flow_idx,
 	elem->reo_id = QDF_NBUF_CB_RX_CTX_ID(nbuf);
 	elem->reo_dest_indication = reo_dest_indication;
 	elem->vdev = vdev;
+	elem->vdev_id = vdev->vdev_id;
 
 	qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock);
 	qdf_list_insert_back(&fisa_hdl->fst_update_list, &elem->node);

+ 1 - 0
components/dp/core/src/wlan_dp_fisa_rx.h

@@ -72,6 +72,7 @@ struct dp_fisa_rx_fst_update_elem {
 	qdf_list_node_t node;
 	struct cdp_rx_flow_tuple_info flow_tuple_info;
 	struct dp_vdev *vdev;
+	uint8_t vdev_id;
 	uint32_t flow_idx;
 	uint32_t reo_dest_indication;
 	bool is_tcp_flow;

+ 12 - 3
components/dp/core/src/wlan_dp_main.c

@@ -1011,7 +1011,8 @@ dp_change_def_link(struct wlan_dp_intf *dp_intf,
 
 QDF_STATUS
 dp_link_switch_notification(struct wlan_objmgr_vdev *vdev,
-			    struct wlan_mlo_link_switch_req *lswitch_req)
+			    struct wlan_mlo_link_switch_req *lswitch_req,
+			    enum wlan_mlo_link_switch_notify_reason notify_reason)
 {
 	/* Add prints to string and print it at last, so we have only 1 print */
 	struct wlan_dp_psoc_context *dp_ctx;
@@ -1019,6 +1020,14 @@ dp_link_switch_notification(struct wlan_objmgr_vdev *vdev,
 	struct wlan_dp_link *dp_link;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
+	/*
+	 * Currently DP handles link switch notification only if the command
+	 * is in serialization's active queue.
+	 * Return success for other notify reasons which are not handled in DP.
+	 */
+	if (notify_reason != MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER)
+		return QDF_STATUS_SUCCESS;
+
 	dp_ctx = dp_get_context();
 
 	dp_link = dp_get_vdev_priv_obj(vdev);
@@ -1979,7 +1988,7 @@ QDF_STATUS __wlan_dp_runtime_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id)
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
-	dp_rx_fst_update_pm_suspend_status(dp_ctx, true);
+	status = wlan_dp_fisa_suspend(dp_ctx);
 
 	return status;
 }
@@ -1994,7 +2003,7 @@ QDF_STATUS __wlan_dp_runtime_resume(ol_txrx_soc_handle soc, uint8_t pdev_id)
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
-	dp_rx_fst_update_pm_suspend_status(dp_ctx, false);
+	status = wlan_dp_fisa_resume(dp_ctx);
 
 	return status;
 }

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

@@ -119,11 +119,22 @@ struct peer_disconnect_stats_param {
 	qdf_mc_timer_t disconn_stats_timer;
 };
 
+/**
+ * struct wlan_mlme_rx_ops  - structure of tx function pointers for
+ * roaming related commands
+ * @peer_oper_mode_eventid : Rx ops function pointer for operating mode event
+ */
+struct wlan_mlme_rx_ops {
+	QDF_STATUS (*peer_oper_mode_eventid)(struct wlan_objmgr_psoc *psoc,
+					     struct peer_oper_mode_event *data);
+};
+
 /**
  * struct wlan_mlme_psoc_ext_obj -MLME ext psoc priv object
  * @cfg:     cfg items
  * @rso_tx_ops: Roam Tx ops to send roam offload commands to firmware
  * @rso_rx_ops: Roam Rx ops to receive roam offload events from firmware
+ * @mlme_rx_ops: mlme Rx ops to receive events from firmware
  * @wfa_testcmd: WFA config tx ops to send to FW
  * @disconnect_stats_param: Peer disconnect stats related params for SAP case
  * @scan_requester_id: mlme scan requester id
@@ -132,6 +143,7 @@ struct wlan_mlme_psoc_ext_obj {
 	struct wlan_mlme_cfg cfg;
 	struct wlan_cm_roam_tx_ops rso_tx_ops;
 	struct wlan_cm_roam_rx_ops rso_rx_ops;
+	struct wlan_mlme_rx_ops mlme_rx_ops;
 	struct wlan_mlme_wfa_cmd wfa_testcmd;
 	struct peer_disconnect_stats_param disconnect_stats_param;
 	wlan_scan_requester scan_requester_id;
@@ -175,6 +187,7 @@ struct sae_auth_retry {
  * @peer_set_key_runtime_wakelock: runtime pm wakelock for set key
  * @is_key_wakelock_set: flag to check if key wakelock is pending to release
  * @assoc_rsp: assoc rsp IE received during connection
+ * @peer_ind_bw: peer indication channel bandwidth
  */
 struct peer_mlme_priv_obj {
 	uint8_t last_pn_valid;
@@ -194,6 +207,7 @@ struct peer_mlme_priv_obj {
 	qdf_runtime_lock_t peer_set_key_runtime_wakelock;
 	bool is_key_wakelock_set;
 	struct element_info assoc_rsp;
+	enum phy_ch_width peer_ind_bw;
 };
 
 /**
@@ -443,6 +457,7 @@ struct wait_for_key_timer {
  * @update_required_scc_sta_power: Change the 6 GHz power type of the
  * concurrent STA
  * @ap_policy: Concurrent ap policy config
+ * @oper_ch_width: SAP current operating ch_width
  */
 struct mlme_ap_config {
 	qdf_freq_t user_config_sap_ch_freq;
@@ -450,6 +465,7 @@ struct mlme_ap_config {
 	bool update_required_scc_sta_power;
 #endif
 	enum host_concurrent_ap_policy ap_policy;
+	enum phy_ch_width oper_ch_width;
 };
 
 /**
@@ -682,11 +698,30 @@ struct roam_scan_chn {
  * @num_channels: total number of channels scanned during roam scan
  * @roam_chn: each roam scan channel information
  * @total_scan_time: total scan time of all roam channel
+ * @original_bssid: connected AP before roam happens, regardless of
+ *  the roam resulting in success or failure.
+ *  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.
+ *  For MLO case, it indicates the new AP BSSID of the link on
+ *  which the reassociation occurred during the roam.
  */
 struct eroam_scan_info {
 	uint8_t num_channels;
 	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;
 };
 
 /**
@@ -1827,4 +1862,61 @@ static inline int mlme_sr_is_enable(struct wlan_objmgr_vdev *vdev)
 	return 0;
 }
 #endif /* WLAN_FEATURE_SR */
+
+/**
+ * mlme_peer_oper_mode_change_event_handler() - Handle peer oper mode event
+ * @scn: handle
+ * @event: Event data received from firmware
+ * @len: Event data length received from firmware
+ */
+int mlme_peer_oper_mode_change_event_handler(ol_scn_t scn, uint8_t *event,
+					     uint32_t len);
+
+/**
+ * wmi_extract_peer_oper_mode_event() - Extract the peer operating
+ * mode change event and update the new bandwidth
+ * @wmi_handle: wmi handle
+ * @event: Event data received from firmware
+ * @len: Event data length received from firmware
+ * @data: Extract the event and fill in data
+ */
+QDF_STATUS
+wmi_extract_peer_oper_mode_event(wmi_unified_t wmi_handle,
+				 uint8_t *event,
+				 uint32_t len,
+				 struct peer_oper_mode_event *data);
+
+/**
+ * wlan_mlme_register_rx_ops - Target IF mlme API to register mlme
+ * related rx op.
+ * @rx_ops: Pointer to rx ops fp struct
+ *
+ * Return: none
+ */
+void wlan_mlme_register_rx_ops(struct wlan_mlme_rx_ops *rx_ops);
+
+/**
+ * mlme_get_rx_ops - Get mlme rx ops from psoc
+ * @psoc: psoc
+ *
+ * Return: Pointer to rx ops fp struct
+ */
+struct wlan_mlme_rx_ops *
+mlme_get_rx_ops(struct wlan_objmgr_psoc *psoc);
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * wlan_mlme_register_common_events - Wrapper to register common events
+ * @psoc: psoc
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc);
+#else
+static inline QDF_STATUS
+wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #endif

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

@@ -37,6 +37,8 @@
 #include "wlan_scan_api.h"
 #include "wlan_mlme_vdev_mgr_interface.h"
 #include "wlan_vdev_mgr_utils_api.h"
+#include <wmi_unified_priv.h>
+#include <target_if.h>
 
 #define NUM_OF_SOUNDING_DIMENSIONS     1 /*Nss - 1, (Nss = 2 for 2x2)*/
 
@@ -44,6 +46,29 @@
 #define MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME 40
 #define MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME 110
 
+struct wlan_mlme_rx_ops *
+mlme_get_rx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_mlme_psoc_ext_obj *psoc_ext_priv;
+
+	if (!psoc) {
+		mlme_err("psoc object is NULL");
+		return NULL;
+	}
+	psoc_ext_priv = wlan_psoc_mlme_get_ext_hdl(psoc);
+	if (!psoc_ext_priv) {
+		mlme_err("psoc legacy private object is NULL");
+		return NULL;
+	}
+
+	return &psoc_ext_priv->mlme_rx_ops;
+}
+
+void wlan_mlme_register_rx_ops(struct wlan_mlme_rx_ops *rx_ops)
+{
+	rx_ops->peer_oper_mode_eventid = wlan_mlme_set_peer_indicated_ch_width;
+}
+
 struct wlan_mlme_psoc_ext_obj *mlme_get_psoc_ext_obj_fl(
 			       struct wlan_objmgr_psoc *psoc,
 			       const char *func, uint32_t line)
@@ -372,22 +397,35 @@ mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev,
 	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;
 
 	vdev_id = vdev->vdev_objmgr.vdev_id;
 
-	if (scan_freq != INVALID_CHANNEL)
+	if (scan_freq != INVALID_CHANNEL) {
 		op_freq = scan_freq;
-	else
-		op_freq = wlan_get_operation_chan_freq(vdev);
+	} 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 = des_chan->ch_cfreq2;
+	}
 
-	mlme_debug("vdev %d : fill ch list for op_freq:%d, scan_ch_width: %d",
-		   vdev_id, op_freq, scan_ch_width);
+	mlme_debug("vdev %d :op_freq:%d, cen320_freq:%d, scan_ch_width: %d",
+		   vdev_id, op_freq, cen320_freq, scan_ch_width);
 
 	if (scan_ch_width == CH_WIDTH_320MHZ) {
+		if (!cen320_freq)
+			return QDF_STATUS_E_FAILURE;
 		range = wlan_reg_get_bonded_chan_entry(op_freq,
-						       scan_ch_width, 0);
+						       scan_ch_width,
+						       cen320_freq);
 		if (!range) {
 			mlme_debug("vdev %d : range is null for freq %d",
 				   vdev_id, op_freq);
@@ -437,6 +475,80 @@ mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev,
 }
 
 #ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * mlme_update_freq_from_link_ctx() - This API updates scan request from
+ * link context
+ * @links_info: pointer to MLO link info
+ * @req: pointer to scan request
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+mlme_update_freq_from_link_ctx(struct mlo_link_info *links_info,
+			       struct scan_start_request *req)
+{
+	const struct bonded_channel_freq *range;
+	uint8_t num_chan;
+	qdf_freq_t op_freq, center_20_freq, start_freq, end_freq;
+	enum scan_phy_mode phymode;
+	enum phy_ch_width scan_ch_width;
+	struct wlan_channel *link_chan_info = links_info->link_chan_info;
+
+	if (!link_chan_info) {
+		mlme_err("link chan info is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	op_freq = link_chan_info->ch_freq;
+	phymode = wlan_scan_get_11be_scan_phy_mode(link_chan_info->ch_phymode);
+	if (phymode == SCAN_PHY_MODE_UNKNOWN) {
+		mlme_err("invalid scan phymode for freq %d", op_freq);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	scan_ch_width = wlan_mlme_get_ch_width_from_phymode(
+						link_chan_info->ch_phymode);
+
+	if (scan_ch_width == CH_WIDTH_320MHZ) {
+		range = wlan_reg_get_bonded_chan_entry(op_freq, scan_ch_width,
+						link_chan_info->ch_cfreq2);
+		if (!range) {
+			mlme_err("range is null for freq %d center freq %d",
+				 op_freq, link_chan_info->ch_cfreq2);
+			return QDF_STATUS_E_NULL_VALUE;
+		}
+
+		start_freq = range->start_freq;
+		end_freq = range->end_freq;
+
+		/* fill connected 6 GHz ML link freq in wide band scan list */
+		center_20_freq = start_freq + (7 * BW_20_MHZ);
+		if (op_freq > center_20_freq)
+			end_freq = op_freq;
+		else
+			start_freq = op_freq;
+
+		mlme_debug("op_freq:%d, c_freq:%d, start_freq:%d, end_freq:%d",
+			   op_freq, center_20_freq, start_freq, end_freq);
+
+		num_chan = req->scan_req.chan_list.num_chan;
+		req->scan_req.chan_list.chan[num_chan].freq = start_freq;
+		req->scan_req.chan_list.chan[num_chan].phymode = phymode;
+		num_chan += 1;
+		req->scan_req.chan_list.chan[num_chan].freq = end_freq;
+		req->scan_req.chan_list.chan[num_chan].phymode = phymode;
+		num_chan += 1;
+		req->scan_req.chan_list.num_chan = num_chan;
+	} else {
+		num_chan = req->scan_req.chan_list.num_chan;
+		req->scan_req.chan_list.chan[num_chan].freq = op_freq;
+		req->scan_req.chan_list.chan[num_chan].phymode = phymode;
+		req->scan_req.chan_list.num_chan += 1;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * mlme_fill_freq_in_mlo_wide_band_scan_start_req() - Fill frequencies in wide
  * band scan req for mlo connection
@@ -450,51 +562,30 @@ mlme_fill_freq_in_mlo_wide_band_scan_start_req(struct wlan_objmgr_vdev *vdev,
 					struct scan_start_request *req)
 {
 	struct wlan_mlo_dev_context *mlo_dev_ctx;
-	struct wlan_mlo_sta *sta_ctx = NULL;
 	uint8_t i;
 	QDF_STATUS status;
-	struct wlan_objmgr_vdev *mlo_vdev;
-	struct mlme_legacy_priv *mlme_priv;
-	enum phy_ch_width associated_ch_width = CH_WIDTH_INVALID;
-	struct assoc_channel_info *assoc_chan_info;
+	struct mlo_link_switch_context *link_ctx;
 
 	mlo_dev_ctx = vdev->mlo_dev_ctx;
 	if (!mlo_dev_ctx) {
 		mlme_err("vdev %d :mlo_dev_ctx is NULL", req->scan_req.vdev_id);
-		return QDF_STATUS_E_FAILURE;
+		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	sta_ctx = mlo_dev_ctx->sta_ctx;
-	if (!sta_ctx) {
-		mlme_err("vdev %d :mlo_dev_ctx is NULL", req->scan_req.vdev_id);
-		return QDF_STATUS_E_FAILURE;
+	link_ctx = mlo_dev_ctx->link_ctx;
+	if (!link_ctx) {
+		mlme_err("vdev %d :mlo_link_ctx is NULL",
+			 req->scan_req.vdev_id);
+		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
-		if (!mlo_dev_ctx->wlan_vdev_list[i])
-			continue;
-		if (qdf_test_bit(i, sta_ctx->wlan_connected_links)) {
-			mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i];
-			mlme_priv = wlan_vdev_mlme_get_ext_hdl(mlo_vdev);
-			if (!mlme_priv) {
-				mlme_legacy_err("vdev legacy priv obj is NULL");
-				return QDF_STATUS_E_FAILURE;
-			}
-
-			assoc_chan_info =
-				&mlme_priv->connect_info.assoc_chan_info;
-			associated_ch_width = assoc_chan_info->assoc_ch_width;
-			if (associated_ch_width == CH_WIDTH_INVALID) {
-				mlme_debug("vdev %d :Invalid assoc ch_width",
-					   req->scan_req.vdev_id);
-				return QDF_STATUS_E_FAILURE;
-			}
-
-			status = mlme_update_freq_in_scan_start_req(mlo_vdev,
-						req, associated_ch_width,
-						INVALID_CHANNEL);
-			if (QDF_IS_STATUS_ERROR(status))
-				return QDF_STATUS_E_FAILURE;
+	for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) {
+		status = mlme_update_freq_from_link_ctx(
+						&link_ctx->links_info[i], req);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			mlme_debug("freq update fails for link id %d",
+				   link_ctx->links_info[i].link_id);
+			return status;
 		}
 	}
 
@@ -898,6 +989,7 @@ mlme_peer_object_created_notification(struct wlan_objmgr_peer *peer,
 	qdf_wake_lock_create(&peer_priv->peer_set_key_wakelock, "peer_set_key");
 	qdf_runtime_lock_init(&peer_priv->peer_set_key_runtime_wakelock);
 	peer_priv->is_key_wakelock_set = false;
+	peer_priv->peer_ind_bw = CH_WIDTH_INVALID;
 
 	return status;
 }
@@ -2419,7 +2511,7 @@ wlan_get_vdev_link_removed_flag(struct wlan_objmgr_vdev *vdev)
 		return false;
 
 	link_id = wlan_vdev_get_link_id(vdev);
-	link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id);
+	link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id);
 	if (link_info)
 		is_mlo_link_removed =
 			!!qdf_atomic_test_bit(LS_F_AP_REMOVAL_BIT,
@@ -2467,7 +2559,7 @@ wlan_set_vdev_link_removed_flag(struct wlan_objmgr_vdev *vdev, bool removed)
 	}
 
 	link_id = wlan_vdev_get_link_id(vdev);
-	link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id);
+	link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id);
 	if (!link_info) {
 		mlme_legacy_err("link info null, id %d", link_id);
 		return QDF_STATUS_E_INVAL;
@@ -3056,7 +3148,6 @@ static void mlme_init_power_cfg(struct wlan_objmgr_psoc *psoc,
 			(uint8_t)cfg_default(CFG_CURRENT_TX_POWER_LEVEL);
 	power->local_power_constraint =
 			(uint8_t)cfg_default(CFG_LOCAL_POWER_CONSTRAINT);
-	power->use_local_tpe = cfg_get(psoc, CFG_USE_LOCAL_TPE);
 	power->skip_tpe = cfg_get(psoc, CFG_SKIP_TPE_CONSIDERATION);
 }
 
@@ -5331,3 +5422,85 @@ QDF_STATUS wlan_mlme_get_sta_rx_nss(struct wlan_objmgr_psoc *psoc,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+QDF_STATUS
+wmi_extract_peer_oper_mode_event(wmi_unified_t wmi_handle,
+				 uint8_t *event,
+				 uint32_t len,
+				 struct peer_oper_mode_event *data)
+{
+	if (wmi_handle->ops->extract_peer_oper_mode_event)
+		return wmi_handle->ops->extract_peer_oper_mode_event(wmi_handle,
+								     event,
+								     len, data);
+	return QDF_STATUS_E_FAILURE;
+}
+
+int mlme_peer_oper_mode_change_event_handler(ol_scn_t scn,
+					      uint8_t *event,
+					      uint32_t len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct peer_oper_mode_event data = {0};
+	struct wlan_mlme_rx_ops *mlme_rx_ops;
+	QDF_STATUS qdf_status;
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		mlme_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	qdf_status = wmi_extract_peer_oper_mode_event(wmi_handle, event,
+						      len, &data);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		mlme_err("parsing of event failed, %d", qdf_status);
+		return -EINVAL;
+	}
+
+	mlme_rx_ops = mlme_get_rx_ops(psoc);
+	if (!mlme_rx_ops || !mlme_rx_ops->peer_oper_mode_eventid) {
+		mlme_err("No valid roam rx ops");
+		return -EINVAL;
+	}
+
+	qdf_status = mlme_rx_ops->peer_oper_mode_eventid(psoc, &data);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		mlme_err("peer_oper_mode_change_event Failed");
+		return -EINVAL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS ret;
+	wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc);
+
+	if (!handle) {
+		mlme_err("handle is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Register for peer operating mode change devent */
+	ret = wmi_unified_register_event_handler(handle,
+				wmi_peer_oper_mode_change_event_id,
+				mlme_peer_oper_mode_change_event_handler,
+				WMI_RX_SERIALIZER_CTX);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		mlme_err("wmi event(%u) registration failed, ret: %d",
+			      wmi_peer_oper_mode_change_event_id, ret);
+		return QDF_STATUS_E_FAILURE;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+#endif

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

@@ -1935,6 +1935,7 @@ QDF_STATUS psoc_mlme_ext_hdl_create(struct psoc_mlme_obj *psoc_mlme)
 			&psoc_mlme->ext_psoc_ptr->wfa_testcmd.tx_ops);
 	target_if_cm_roam_register_rx_ops(
 			&psoc_mlme->ext_psoc_ptr->rso_rx_ops);
+	wlan_mlme_register_rx_ops(&psoc_mlme->ext_psoc_ptr->mlme_rx_ops);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 1 - 22
components/mlme/dispatcher/inc/cfg_mlme_power.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -146,27 +147,6 @@
 		CFG_VALUE_OR_DEFAULT, \
 		"local power constraint")
 
-/*
- * <ini>
- * use_local_tpe - use local or regulatory TPE
- * @Min: 0
- * @Max: 1
- * @Default: 0
- *
- * This ini is used to set the preference of local or regulatory TPE. If the
- * preferred choice is not available, it will fall back on the other choice.
- *
- * Related: None
- *
- * Supported Feature: 6GHz channel transmit power
- *
- * Usage: External
- *
- * </ini>
- */
-#define CFG_USE_LOCAL_TPE CFG_INI_BOOL("use_local_tpe", false, \
-					"use local or regulatory TPE")
-
 /*
  * <ini>
  * skip_tpe_consideration - Skip TPE IE value in tx power calculation for
@@ -200,7 +180,6 @@
 	CFG(CFG_SET_TXPOWER_LIMIT5G) \
 	CFG(CFG_CURRENT_TX_POWER_LEVEL) \
 	CFG(CFG_LOCAL_POWER_CONSTRAINT) \
-	CFG(CFG_USE_LOCAL_TPE) \
 	CFG(CFG_SKIP_TPE_CONSIDERATION)
 
 #endif /* __CFG_MLME_POWER_H */

+ 127 - 10
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -28,6 +28,28 @@
 #include <wlan_cmn.h>
 #include "sme_api.h"
 
+#define ASSEMBLE_RATECODE_V1(_pream, _nss, _rate) \
+		(((1) << 28) | ((_pream) << 8) | ((_nss) << 5) | (_rate))
+
+/* This macro is used to extract the rate from the rate_code as first four bits
+ * in rate_code represents the rate, next 3 bits represents the nss and
+ * next 2 bits represents preamble.
+ */
+#define RATECODE_V1_RIX_MASK    0xf
+
+/* This macro is used to extract preamble from the rate_code as first 4 bits
+ * in rate_code represents the rate, next 3 bits represents the nss and
+ * next 2 bits represents preamble.
+ */
+#define RATECODE_V1_PREAMBLE_OFFSET (4 + 3)
+
+/* This macro is used to extract NSS from the rate_code as first 4 bits
+ * in rate_code represents the rate, next 3 bits represents the NSS and
+ * next 2 bits represents preamble.
+ */
+#define RATECODE_V1_NSS_OFFSET  0x4
+#define RATECODE_V1_NSS_MASK    0x7
+
 #ifdef FEATURE_SET
 /**
  * wlan_mlme_get_feature_info() - Get mlme features
@@ -1220,6 +1242,15 @@ QDF_STATUS mlme_update_tgt_mlo_caps_in_cfg(struct wlan_objmgr_psoc *psoc);
 enum phy_ch_width wlan_mlme_convert_eht_op_bw_to_phy_ch_width(
 						uint8_t channel_width);
 
+/**
+ * wlan_mlme_convert_phy_ch_width_to_eht_op_bw() - convert channel width to eht
+ *                                                 operation IE format
+ * @ch_width: phy_ch_width
+ *
+ * Return: channel width in eht operation IE
+ */
+uint8_t wlan_mlme_convert_phy_ch_width_to_eht_op_bw(enum phy_ch_width ch_width);
+
 /**
  * wlan_mlme_get_epcs_capability() - Get mlme epcs capability flag
  * @psoc: psoc object
@@ -3493,6 +3524,28 @@ wlan_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc,
 }
 #endif
 
+/**
+ * wlan_mlme_set_peer_indicated_ch_width() - Set peer indicated channel width
+ * @psoc: pointer to psoc object
+ * @data: Pointer to peer operating mode change event status
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+wlan_mlme_set_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data);
+
+/**
+ * wlan_mlme_get_peer_indicated_ch_width() - Get peer indicated channel width
+ * @psoc: pointer to psoc object
+ * @data: Pointer to peer operating mode change event status
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+wlan_mlme_get_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data);
+
 /**
  * wlan_mlme_set_ft_over_ds() - Update ft_over_ds
  * @psoc: pointer to psoc object
@@ -4022,16 +4075,6 @@ mlme_is_twt_enabled(struct wlan_objmgr_psoc *psoc)
 }
 #endif /* WLAN_SUPPORT_TWT */
 
-/**
- * wlan_mlme_is_local_tpe_pref() - Get preference to use local TPE or
- * regulatory TPE values
- * @psoc: pointer to psoc object
- *
- * Return: True if there is local preference, false if there is regulatory
- * preference
- */
-bool wlan_mlme_is_local_tpe_pref(struct wlan_objmgr_psoc *psoc);
-
 /**
  * wlan_mlme_skip_tpe() - Get preference to not consider TPE in 2G/5G case
  *
@@ -4093,6 +4136,30 @@ QDF_STATUS wlan_mlme_set_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS wlan_mlme_set_user_set_link_num(struct wlan_objmgr_psoc *psoc,
 					   uint8_t value);
 
+/**
+ * wlan_mlme_set_ml_link_control_mode() - set ml_link_control_mode
+ * @psoc: pointer to psoc object
+ * @vdev_id: vdev id
+ * @value: value to set
+ *
+ * API get call when host receives vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE to configure link control mode.
+ *
+ * Return: none
+ */
+void wlan_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					uint8_t vdev_id, uint8_t value);
+
+/**
+ * wlan_mlme_get_ml_link_control_mode() - get ml_link_control_mode
+ * @psoc: pointer to psoc object
+ * @vdev_id: vdev id
+ *
+ * Return: value of ml_link_control_mode in success
+ */
+uint8_t wlan_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id);
+
 /**
  * wlan_mlme_restore_user_set_link_num() - restore link num when SSR happens
  * @psoc: pointer to psoc object
@@ -4156,6 +4223,19 @@ QDF_STATUS wlan_mlme_set_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc,
  */
 bool wlan_mlme_get_sta_same_link_mld_addr(struct wlan_objmgr_psoc *psoc);
 #else
+static inline
+void wlan_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					uint8_t vdev_id, uint8_t value)
+{
+}
+
+static inline
+uint8_t wlan_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id)
+{
+	return 0;
+}
+
 static inline QDF_STATUS
 wlan_mlme_set_user_set_link_num(struct wlan_objmgr_psoc *psoc,
 				uint8_t value)
@@ -4598,4 +4678,41 @@ QDF_STATUS wlan_mlme_get_sta_ch_width(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS
 wlan_mlme_set_ul_mu_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 			   uint8_t ulmu_disable);
+
+/**
+ * wlan_mlme_assemble_rate_code() - assemble rate code to be sent to FW
+ *
+ * @preamble: rate preamble
+ * @nss: number of spatial streams
+ * @rate: rate index
+ *
+ * Rate code assembling is different for targets which are 11ax capable.
+ * Check for the target support and assemble the rate code accordingly.
+ *
+ * Return: assembled rate code
+ */
+uint32_t
+wlan_mlme_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate);
+
+/**
+ * wlan_mlme_set_ap_oper_ch_width() - set SAP current operating ch_width
+ *
+ * @vdev: SAP VDEV object
+ * @ch_width: ch_width to be cached
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+wlan_mlme_set_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev,
+			       enum phy_ch_width ch_width);
+
+/**
+ * wlan_mlme_get_ap_oper_ch_width() - get SAP current operating ch_width
+ *
+ * @vdev: SAP VDEV object
+ *
+ * Return: Current SAP operating ch_width
+ */
+enum phy_ch_width
+wlan_mlme_get_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev);
 #endif /* _WLAN_MLME_API_H_ */

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

@@ -2461,7 +2461,6 @@ struct mlme_power_usage {
  * @tx_power_5g: limit tx power in 5 ghz
  * @current_tx_power_level: current tx power level
  * @local_power_constraint: local power constraint
- * @use_local_tpe: preference to use local or regulatory TPE
  * @skip_tpe: option to not consider TPE values in 2.4G/5G bands
  */
 struct wlan_mlme_power {
@@ -2474,7 +2473,6 @@ struct wlan_mlme_power {
 	uint8_t tx_power_5g;
 	uint8_t current_tx_power_level;
 	uint8_t local_power_constraint;
-	bool use_local_tpe;
 	bool skip_tpe;
 };
 
@@ -2574,6 +2572,7 @@ struct wlan_mlme_wifi_pos_cfg {
 /* Mask to check if BTM offload is enabled/disabled*/
 #define BTM_OFFLOAD_ENABLED_MASK    0x01
 
+#define BTM_OFFLOAD_CONFIG_BIT_0    0
 #define BTM_OFFLOAD_CONFIG_BIT_8    8
 #define BTM_OFFLOAD_CONFIG_BIT_7    7
 
@@ -3032,4 +3031,34 @@ struct sap_sel_ch_info {
 	struct sap_ch_info *ch_info;
 	uint8_t num_ch;
 };
+
+/**
+ * enum mlme_peer_oper_mode_ind - Peer mode indication type
+ * @mlme_peer_ind_smps: spatial multiplexing power save
+ * @mlme_peer_ind_omn: Operating mode notification
+ * @mlme_peer_ind_omi: Operating mode indication
+ */
+enum mlme_peer_oper_mode_ind {
+	mlme_peer_ind_smps,
+	mlme_peer_ind_omn,
+	mlme_peer_ind_omi,
+};
+
+/**
+ * struct peer_oper_mode_event - structure for peer oper mode indication data
+ * @peer_mac_address: mac address of peer
+ * @ind_type: indication type of type @enum mlme_peer_oper_mode_ind
+ * @new_rxnss: New Rx NSS
+ * @new_bw: New bandwidth
+ * @new_txnss: New Tx NSS, valid only for mlme_peer_ind_omi
+ * @new_disablemu: Disabled MU mode, valid only for mlme_peer_ind_omi
+ */
+struct peer_oper_mode_event {
+	struct qdf_mac_addr peer_mac_address;
+	uint32_t ind_type;
+	uint32_t new_rxnss;
+	uint32_t new_bw;
+	uint32_t new_txnss;
+	uint32_t new_disablemu;
+};
 #endif

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

@@ -80,6 +80,30 @@ void ucfg_mlme_psoc_close(struct wlan_objmgr_psoc *psoc);
  */
 QDF_STATUS ucfg_mlme_pdev_open(struct wlan_objmgr_pdev *pdev);
 
+/**
+ * ucfg_mlme_set_ml_link_control_mode() - set ml_link_control_mode
+ * @psoc: pointer to psoc object
+ * @vdev_id: vdev id
+ * @value: value to set
+ *
+ * API get call when host receives vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE to configure link control mode.
+ *
+ * Return: none
+ */
+void ucfg_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					uint8_t vdev_id, uint8_t value);
+
+/**
+ * ucfg_mlme_get_ml_link_control_mode() - get ml_link_control_mode
+ * @psoc: pointer to psoc object
+ * @vdev_id: vdev id
+ *
+ * Return: value of ml_link_control_mode in success
+ */
+uint8_t ucfg_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id);
+
 /**
  * ucfg_mlme_pdev_close() - MLME component pdev close
  * @pdev: pointer to pdev object
@@ -5289,4 +5313,21 @@ QDF_STATUS ucfg_mlme_set_ul_mu_config(struct wlan_objmgr_psoc *psoc,
 {
 	return wlan_mlme_set_ul_mu_config(psoc, vdev_id, ulmu_disable);
 }
+
+/**
+ * ucfg_mlme_assemble_rate_code - assemble rate code to be sent to FW
+ * @preamble: rate preamble
+ * @nss: number of spatial streams
+ * @rate: rate index
+ *
+ * Rate code assembling is different for targets which are 11ax capable.
+ * Check for the target support and assemble the rate code accordingly.
+ *
+ * Return: assembled rate code
+ */
+static inline uint32_t
+ucfg_mlme_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate)
+{
+	return wlan_mlme_assemble_rate_code(preamble, nss, rate);
+}
 #endif /* _WLAN_MLME_UCFG_API_H_ */

+ 239 - 23
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -37,6 +37,7 @@
 #include "target_if.h"
 #include "wlan_vdev_mgr_tgt_if_tx_api.h"
 #include "wmi_unified_vdev_api.h"
+#include "wlan_mlme_api.h"
 #include "../../core/src/wlan_cp_stats_defs.h"
 
 /* quota in milliseconds */
@@ -1280,6 +1281,22 @@ QDF_STATUS mlme_update_tgt_mlo_caps_in_cfg(struct wlan_objmgr_psoc *psoc)
 	return status;
 }
 
+uint8_t wlan_mlme_convert_phy_ch_width_to_eht_op_bw(enum phy_ch_width ch_width)
+{
+	switch (ch_width) {
+	case CH_WIDTH_320MHZ:
+		return WLAN_EHT_CHWIDTH_320;
+	case CH_WIDTH_160MHZ:
+		return WLAN_EHT_CHWIDTH_160;
+	case CH_WIDTH_80MHZ:
+		return WLAN_EHT_CHWIDTH_80;
+	case CH_WIDTH_40MHZ:
+		return WLAN_EHT_CHWIDTH_40;
+	default:
+		return WLAN_EHT_CHWIDTH_20;
+	}
+}
+
 enum phy_ch_width wlan_mlme_convert_eht_op_bw_to_phy_ch_width(
 						uint8_t channel_width)
 {
@@ -1403,7 +1420,7 @@ uint8_t wlan_mlme_get_sta_mlo_simultaneous_links(struct wlan_objmgr_psoc *psoc)
 
 	mlme_obj = mlme_get_psoc_ext_obj(psoc);
 	if (!mlme_obj)
-		return false;
+		return 0;
 
 	return mlme_obj->cfg.sta.mlo_max_simultaneous_links;
 }
@@ -1430,7 +1447,7 @@ uint8_t wlan_mlme_get_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc)
 
 	mlme_obj = mlme_get_psoc_ext_obj(psoc);
 	if (!mlme_obj)
-		return false;
+		return 0;
 
 	return mlme_obj->cfg.sta.mlo_support_link_num;
 }
@@ -1470,6 +1487,72 @@ QDF_STATUS wlan_mlme_set_user_set_link_num(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+void wlan_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					uint8_t vdev_id, uint8_t value)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+	struct wlan_objmgr_vdev *vdev;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_SB_ID);
+	if (!vdev)
+		return;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		mlme_legacy_debug("not mlo vdev");
+		goto release_ref;
+	}
+
+	if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx) {
+		mlme_legacy_debug("mlo dev/sta ctx is null");
+		goto release_ref;
+	}
+
+	vdev->mlo_dev_ctx->sta_ctx->ml_link_control_mode = value;
+	mlme_legacy_debug("set ml_link_control_mode %d", value);
+
+release_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
+	return;
+}
+
+uint8_t wlan_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t value = 0;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return 0;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_SB_ID);
+	if (!vdev)
+		return 0;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		mlme_legacy_debug("not mlo vdev");
+		goto release_ref;
+	}
+
+	if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx) {
+		mlme_legacy_debug("mlo dev/sta ctx is null");
+		goto release_ref;
+	}
+
+	value = vdev->mlo_dev_ctx->sta_ctx->ml_link_control_mode;
+	mlme_legacy_debug("get ml_link_control_mode %d", value);
+release_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
+	return value;
+}
+
 void wlan_mlme_restore_user_set_link_num(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_mlme_psoc_ext_obj *mlme_obj;
@@ -1504,7 +1587,7 @@ uint8_t wlan_mlme_get_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc)
 
 	mlme_obj = mlme_get_psoc_ext_obj(psoc);
 	if (!mlme_obj)
-		return false;
+		return 0;
 
 	return mlme_obj->cfg.sta.mlo_support_link_band;
 }
@@ -5441,6 +5524,88 @@ wlan_mlme_get_self_bss_roam(struct wlan_objmgr_psoc *psoc,
 }
 #endif
 
+QDF_STATUS
+wlan_mlme_get_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data)
+{
+	struct wlan_objmgr_peer *peer;
+	struct peer_mlme_priv_obj *peer_priv;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!data) {
+		mlme_err("Data params is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, data->peer_mac_address.bytes,
+					   WLAN_MLME_NB_ID);
+	if (!peer) {
+		mlme_err("peer not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(data->peer_mac_address.bytes));
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_MLME);
+	if (!peer_priv) {
+		mlme_err("peer priv not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(peer->macaddr));
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto done;
+	}
+
+	if (peer_priv->peer_ind_bw == CH_WIDTH_INVALID) {
+		status = QDF_STATUS_E_INVAL;
+		goto done;
+	}
+
+	data->new_bw = peer_priv->peer_ind_bw;
+
+done:
+	wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID);
+
+	return status;
+}
+
+QDF_STATUS
+wlan_mlme_set_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data)
+{
+	struct wlan_objmgr_peer *peer;
+	struct peer_mlme_priv_obj *peer_priv;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!data) {
+		mlme_err("Data params is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, data->peer_mac_address.bytes,
+					   WLAN_MLME_NB_ID);
+	if (!peer) {
+		mlme_err("peer not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(data->peer_mac_address.bytes));
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_MLME);
+	if (!peer_priv) {
+		mlme_err("peer priv not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(peer->macaddr));
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto done;
+	}
+
+	peer_priv->peer_ind_bw =
+			target_if_wmi_chan_width_to_phy_ch_width(data->new_bw);
+
+done:
+	wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID);
+
+	return status;
+}
+
 QDF_STATUS
 wlan_mlme_set_ft_over_ds(struct wlan_objmgr_psoc *psoc,
 			 uint8_t ft_over_ds_enable)
@@ -6197,17 +6362,6 @@ bool wlan_mlme_is_sta_mon_conc_supported(struct wlan_objmgr_psoc *psoc)
 	return false;
 }
 
-bool wlan_mlme_is_local_tpe_pref(struct wlan_objmgr_psoc *psoc)
-{
-	struct wlan_mlme_psoc_ext_obj *mlme_obj;
-
-	mlme_obj = mlme_get_psoc_ext_obj(psoc);
-	if (!mlme_obj)
-		return false;
-
-	return mlme_obj->cfg.power.use_local_tpe;
-}
-
 bool wlan_mlme_skip_tpe(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_mlme_psoc_ext_obj *mlme_obj;
@@ -7048,7 +7202,8 @@ wlan_mlme_update_vdev_chwidth_with_notify(struct wlan_objmgr_psoc *psoc,
 
 static QDF_STATUS wlan_mlme_update_ch_width(struct wlan_objmgr_vdev *vdev,
 					    uint8_t vdev_id,
-					    enum phy_ch_width ch_width)
+					    enum phy_ch_width ch_width,
+					    qdf_freq_t sec_2g_freq)
 {
 	struct wlan_channel *des_chan;
 	struct wlan_channel *bss_chan;
@@ -7075,7 +7230,7 @@ static QDF_STATUS wlan_mlme_update_ch_width(struct wlan_objmgr_vdev *vdev,
 	curr_op_freq = des_chan->ch_freq;
 
 	wlan_reg_set_channel_params_for_pwrmode(pdev, curr_op_freq,
-						0, &ch_params,
+						sec_2g_freq, &ch_params,
 						REG_CURRENT_PWR_MODE);
 
 	des_chan->ch_width = ch_width;
@@ -7297,6 +7452,7 @@ wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 	enum phy_ch_width associated_ch_width;
 	struct wlan_channel *des_chan;
 	struct mlme_legacy_priv *mlme_priv;
+	qdf_freq_t sec_2g_freq = 0;
 
 	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
 	if (!mlme_priv)
@@ -7306,12 +7462,6 @@ wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 	if (!des_chan)
 		return QDF_STATUS_E_INVAL;
 
-	if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq)) {
-		mlme_debug("vdev %d: CW:%d update not supported for freq:%d",
-			   vdev_id, ch_width, des_chan->ch_freq);
-		return QDF_STATUS_E_NOSUPPORT;
-	}
-
 	associated_ch_width =
 		mlme_priv->connect_info.assoc_chan_info.assoc_ch_width;
 	if (associated_ch_width == CH_WIDTH_INVALID ||
@@ -7321,8 +7471,22 @@ wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_INVAL;
 	}
 
+	if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq)) {
+		if (ch_width == CH_WIDTH_40MHZ &&
+		    mlme_priv->connect_info.assoc_chan_info.sec_2g_freq) {
+			sec_2g_freq =
+			mlme_priv->connect_info.assoc_chan_info.sec_2g_freq;
+		} else if (ch_width != CH_WIDTH_20MHZ) {
+			mlme_debug("vdev %d: CW:%d update not supported for freq:%d sec_2g_freq %d",
+				   vdev_id, ch_width, des_chan->ch_freq,
+				   mlme_priv->connect_info.assoc_chan_info.sec_2g_freq);
+			return QDF_STATUS_E_NOSUPPORT;
+		}
+	}
+
 	/* 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,
+					   sec_2g_freq);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_err("vdev %d: Failed to update CW:%d to host, status:%d",
 			 vdev_id, ch_width, status);
@@ -7627,3 +7791,55 @@ err:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
 	return status;
 }
+
+uint32_t
+wlan_mlme_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate)
+{
+	uint32_t set_value;
+
+	if (wma_get_fw_wlan_feat_caps(DOT11AX))
+		set_value = ASSEMBLE_RATECODE_V1(preamble, nss, rate);
+	else
+		set_value = (preamble << 6) | (nss << 4) | rate;
+
+	return set_value;
+}
+
+QDF_STATUS
+wlan_mlme_set_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev,
+			       enum phy_ch_width ch_width)
+
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev %d legacy private object is NULL",
+				wlan_vdev_get_id(vdev));
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv->mlme_ap.oper_ch_width = ch_width;
+	mlme_debug("SAP oper ch_width: %d, vdev %d",
+		   mlme_priv->mlme_ap.oper_ch_width, wlan_vdev_get_id(vdev));
+
+	return QDF_STATUS_SUCCESS;
+}
+
+enum phy_ch_width
+wlan_mlme_get_ap_oper_ch_width(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 %d legacy private object is NULL",
+				wlan_vdev_get_id(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;
+}

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

@@ -128,6 +128,19 @@ QDF_STATUS ucfg_mlme_pdev_close(struct wlan_objmgr_pdev *pdev)
 	return QDF_STATUS_SUCCESS;
 }
 
+void ucfg_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					uint8_t vdev_id, uint8_t value)
+{
+	wlan_mlme_set_ml_link_control_mode(psoc, vdev_id, value);
+}
+
+uint8_t ucfg_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id)
+{
+	return wlan_mlme_get_ml_link_control_mode(psoc, vdev_id);
+}
+
+
 /**
  * ucfg_mlme_convert_power_cfg_chan_to_freq() - converts channel numbers to
  * frequencies and copies the triplets to power_freq_data array

+ 5 - 1
components/p2p/dispatcher/inc/wlan_p2p_public_struct.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-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
@@ -47,6 +47,7 @@
  * @single_noa_duration: single shot noa duration
  * @ps_selection: power save selection
  * @session_id: session id
+ * @start: start time
  */
 struct p2p_ps_params {
 	uint8_t opp_ps;
@@ -57,6 +58,7 @@ struct p2p_ps_params {
 	uint32_t single_noa_duration;
 	uint8_t ps_selection;
 	uint8_t session_id;
+	uint32_t start;
 };
 
 /**
@@ -177,6 +179,7 @@ struct p2p_set_mac_filter_evt {
  * @interval:              Interval
  * @single_noa_duration:   Single shot noa duration
  * @ps_selection:          power save selection
+ * @start:                 Start time
  */
 struct p2p_ps_config {
 	uint32_t vdev_id;
@@ -187,6 +190,7 @@ struct p2p_ps_config {
 	uint32_t interval;
 	uint32_t single_noa_duration;
 	uint32_t ps_selection;
+	uint32_t start;
 };
 
 /**

+ 6 - 5
components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c

@@ -444,11 +444,12 @@ QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc,
 	struct wlan_objmgr_vdev *vdev;
 	struct p2p_ps_config go_ps_config;
 
-	p2p_debug("soc:%pK, vdev_id:%d, opp_ps:%d, ct_window:%d, count:%d, duration:%d, duration:%d, ps_selection:%d",
-		soc, ps_config->vdev_id, ps_config->opp_ps,
-		ps_config->ct_window, ps_config->count,
-		ps_config->duration, ps_config->single_noa_duration,
-		ps_config->ps_selection);
+	p2p_debug("soc:%pK, vdev_id:%d, opp_ps:%d, ct_window:%d, count:%d, interval:%d, duration:%d, start:%d, single noa duration:%d, ps_selection:%d",
+		  soc, ps_config->vdev_id, ps_config->opp_ps,
+		  ps_config->ct_window, ps_config->count,
+		  ps_config->interval, ps_config->duration,
+		  ps_config->start, ps_config->single_noa_duration,
+		  ps_config->ps_selection);
 
 	if (!soc) {
 		p2p_err("psoc context passed is NULL");

+ 3 - 2
components/target_if/connection_mgr/src/target_if_cm_roam_event.c

@@ -817,8 +817,9 @@ target_if_roam_synch_key_event_handler(ol_scn_t scn, uint8_t *event,
 				keys[i].vdev_id = wlan_vdev_get_id(vdev_list);
 				qdf_copy_macaddr((struct qdf_mac_addr *)keys[i].mac_addr.raw,
 						 (struct qdf_mac_addr *)vdev_list->vdev_mlme.linkaddr);
-				link_info = mlo_mgr_get_ap_link_by_link_id(vdev_list,
-									   keys[i].link_id);
+				link_info = mlo_mgr_get_ap_link_by_link_id(
+							vdev_list->mlo_dev_ctx,
+							keys[i].link_id);
 				if (!link_info) {
 					target_if_err("Link info not found for link_id:%d",
 						      keys[i].link_id);

+ 1 - 0
components/target_if/p2p/src/target_if_p2p.c

@@ -340,6 +340,7 @@ QDF_STATUS target_if_p2p_set_ps(struct wlan_objmgr_psoc *psoc,
 	cmd.single_noa_duration = ps_config->single_noa_duration;
 	cmd.ps_selection = ps_config->ps_selection;
 	cmd.session_id =  ps_config->vdev_id;
+	cmd.start = ps_config->start;
 
 	if (ps_config->opp_ps)
 		status = wmi_unified_set_p2pgo_oppps_req(wmi_handle,

+ 24 - 4
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c

@@ -48,6 +48,7 @@
 #include "wlan_mlo_mgr_roam.h"
 #include "wlan_vdev_mgr_utils_api.h"
 #include "wlan_mlo_link_force.h"
+#include <wlan_psoc_mlme_api.h>
 
 QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 			       void *event, uint32_t event_data_len)
@@ -438,16 +439,21 @@ cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev,
 	if (!is_multi_link_roam(roam_synch_data))
 		return;
 
+	mlo_mgr_reset_ap_link_info(vdev);
 	for (i = 0; i < roam_synch_data->num_setup_links; i++) {
 		ml_link = &roam_synch_data->ml_link[i];
 
+		qdf_mem_zero(&channel, sizeof(channel));
+
 		channel.ch_freq = ml_link->channel.mhz;
 		channel.ch_cfreq1 = ml_link->channel.band_center_freq1;
 		channel.ch_cfreq1 = ml_link->channel.band_center_freq2;
 
-		mlo_mgr_roam_update_ap_link_info(vdev, ml_link->link_id,
-						 ml_link->link_addr.bytes,
-						 channel);
+		/*
+		 * Update Link switch context for each vdev with roamed AP link
+		 * address and self link address for each vdev
+		 */
+		mlo_mgr_roam_update_ap_link_info(vdev, ml_link, &channel);
 	}
 }
 
@@ -994,6 +1000,7 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	wlan_cm_id cm_id;
 	struct wlan_objmgr_pdev *pdev;
 	struct wlan_cm_connect_resp *connect_rsp;
+	bool eht_capab = false;
 
 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
 						    WLAN_MLME_SB_ID);
@@ -1110,7 +1117,20 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 		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);
-	status = QDF_STATUS_SUCCESS;
+
+	wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab);
+	if (eht_capab) {
+		status = policy_mgr_current_connections_update(
+				psoc, vdev_id,
+				connect_rsp->freq,
+				POLICY_MGR_UPDATE_REASON_LFR3_ROAM,
+				POLICY_MGR_DEF_REQ_ID);
+		if (status == QDF_STATUS_E_NOSUPPORT)
+			status = QDF_STATUS_SUCCESS;
+		else if (status == QDF_STATUS_E_FAILURE)
+			mlme_err("Failed to take next action LFR3_ROAM");
+	}
+
 error:
 	if (rsp)
 		wlan_cm_free_connect_rsp(rsp);

+ 24 - 9
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -3475,6 +3475,8 @@ cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 		goto rel_vdev_ref;
 
 	stop_req->btm_config.vdev_id = vdev_id;
+	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;
@@ -6201,7 +6203,7 @@ void cm_roam_trigger_info_event(struct wmi_roam_trigger_info *data,
 	wlan_diag_event.trigger_sub_reason =
 		cm_get_diag_roam_sub_reason(data->trigger_sub_reason);
 
-	wlan_diag_event.version = DIAG_ROAM_SCAN_START_VERSION;
+	wlan_diag_event.version = DIAG_ROAM_SCAN_START_VERSION_V2;
 
 	/*
 	 * Get the current AP rssi & CU load from the
@@ -6234,6 +6236,7 @@ void cm_roam_trigger_info_event(struct wmi_roam_trigger_info *data,
 	}
 
 	wlan_diag_event.is_full_scan = is_full_scan;
+	wlan_diag_event.band = scan_data->band;
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event,
 				    EVENT_WLAN_ROAM_SCAN_START);
@@ -6262,7 +6265,7 @@ void cm_roam_candidate_info_event(struct wmi_roam_candidate_info *ap,
 		wlan_diag_event.subtype =
 					WLAN_CONN_DIAG_ROAM_SCORE_CAND_AP_EVENT;
 
-	wlan_diag_event.version = DIAG_ROAM_CAND_VERSION;
+	wlan_diag_event.version = DIAG_ROAM_CAND_VERSION_V2;
 	wlan_diag_event.rssi = (-1) * ap->rssi;
 	wlan_diag_event.cu_load = ap->cu_load;
 	wlan_diag_event.total_score = ap->total_score;
@@ -6276,6 +6279,7 @@ void cm_roam_candidate_info_event(struct wmi_roam_candidate_info *ap,
 
 	wlan_diag_event.idx = cand_ap_idx;
 	wlan_diag_event.freq = ap->freq;
+	wlan_diag_event.is_mlo = ap->is_mlo;
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event,
 				    EVENT_WLAN_ROAM_CAND_INFO);
@@ -6655,9 +6659,10 @@ cm_roam_btm_query_event(struct wmi_neighbor_report_data *btm_data,
 			  (uint64_t)btm_data->timestamp, NULL);
 
 	wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_QUERY_EVENT;
-	wlan_diag_event.version = DIAG_BTM_VERSION;
+	wlan_diag_event.version = DIAG_BTM_VERSION_2;
 	wlan_diag_event.token = btm_data->btm_query_token;
 	wlan_diag_event.reason = btm_data->btm_query_reason;
+	wlan_diag_event.band = btm_data->band;
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM);
 
@@ -6773,11 +6778,12 @@ cm_roam_btm_resp_event(struct wmi_roam_trigger_info *trigger_info,
 			  (uint64_t)trigger_info->timestamp,
 			  &btm_data->target_bssid);
 
-	wlan_diag_event.version = DIAG_BTM_VERSION;
+	wlan_diag_event.version = DIAG_BTM_VERSION_2;
 	wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_RESP_EVENT;
 	wlan_diag_event.token = btm_data->btm_resp_dialog_token;
 	wlan_diag_event.status = btm_data->btm_status;
 	wlan_diag_event.delay = btm_data->btm_delay;
+	wlan_diag_event.band = btm_data->band;
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM);
 
@@ -6833,7 +6839,7 @@ cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
 			  NULL);
 
 	wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_REQ_EVENT;
-	wlan_diag_event.version = DIAG_BTM_VERSION;
+	wlan_diag_event.version = DIAG_BTM_VERSION_2;
 	wlan_diag_event.token = btm_data->token;
 	wlan_diag_event.mode = btm_data->btm_request_mode;
 	/*
@@ -6845,6 +6851,7 @@ cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
 	wlan_diag_event.validity_timer =
 					btm_data->validity_interval / 1000;
 	wlan_diag_event.cand_lst_cnt = btm_data->candidate_list_count;
+	wlan_diag_event.band = btm_data->band;
 
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM);
 
@@ -6858,8 +6865,9 @@ cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
 }
 
 QDF_STATUS
-cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data,
-			 struct wmi_roam_scan_data *scan_data, uint8_t vdev_id)
+cm_roam_mgmt_frame_event(struct wlan_objmgr_vdev *vdev,
+			 struct roam_frame_info *frame_data,
+			 struct wmi_roam_scan_data *scan_data)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	uint8_t i;
@@ -6869,11 +6877,11 @@ cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data,
 
 	qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event));
 
-	populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id,
+	populate_diag_cmn(&wlan_diag_event.diag_cmn, wlan_vdev_get_id(vdev),
 			  (uint64_t)frame_data->timestamp,
 			  &frame_data->bssid);
 
-	wlan_diag_event.version = DIAG_MGMT_VERSION;
+	wlan_diag_event.version = DIAG_MGMT_VERSION_V2;
 	wlan_diag_event.sn = frame_data->seq_num;
 	wlan_diag_event.auth_algo = frame_data->auth_algo;
 	wlan_diag_event.rssi = frame_data->rssi;
@@ -6919,7 +6927,14 @@ cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data,
 	    wlan_diag_event.subtype < WLAN_CONN_DIAG_BMISS_EVENT)
 		wlan_diag_event.reason = frame_data->status_code;
 
+	if (wlan_diag_event.subtype == WLAN_CONN_DIAG_DEAUTH_RX_EVENT ||
+	    wlan_diag_event.subtype == WLAN_CONN_DIAG_DISASSOC_RX_EVENT)
+		wlan_populate_vsie(vdev, &wlan_diag_event, false);
+
 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, diag_event);
+	if (wlan_diag_event.subtype == WLAN_CONN_DIAG_REASSOC_RESP_EVENT ||
+	    wlan_diag_event.subtype == WLAN_CONN_DIAG_ASSOC_RESP_EVENT)
+		wlan_connectivity_mlo_setup_event(vdev);
 
 	return status;
 }

+ 7 - 5
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h

@@ -575,15 +575,16 @@ cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev,
 	defined(WLAN_FEATURE_ROAM_OFFLOAD))
 /**
  * cm_roam_mgmt_frame_event() - Roam management frame event
+ * @vdev: vdev pointer
  * @frame_data: frame_data
  * @scan_data: Roam scan data
- * @vdev_id: vdev_id
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS
-cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data,
-			 struct wmi_roam_scan_data *scan_data, uint8_t vdev_id);
+cm_roam_mgmt_frame_event(struct wlan_objmgr_vdev *vdev,
+			 struct roam_frame_info *frame_data,
+			 struct wmi_roam_scan_data *scan_data);
 
 /**
  * cm_roam_btm_req_event  - Send BTM request related logging event
@@ -659,8 +660,9 @@ cm_roam_neigh_rpt_resp_event(struct wmi_neighbor_report_data *neigh_rpt,
 			     uint8_t vdev_id);
 #else
 static inline QDF_STATUS
-cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data,
-			 struct wmi_roam_scan_data *scan_data, uint8_t vdev_id)
+cm_roam_mgmt_frame_event(struct wlan_objmgr_vdev *vdev,
+			 struct roam_frame_info *frame_data,
+			 struct wmi_roam_scan_data *scan_data)
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }

+ 7 - 5
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c

@@ -533,14 +533,15 @@ QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev,
 
 	if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, sync_ind->roamed_vdev_id) &&
 	    !is_multi_link_roam(sync_ind)) {
-		mlme_err("Ignoring RSI since one is already in progress");
+		mlme_err("vdev:%d Ignoring RSI as its already in progress on roamed vdev:%d",
+			 vdev_id, sync_ind->roamed_vdev_id);
 		status = QDF_STATUS_E_FAILURE;
 		goto err;
 	}
 
 	if (!QDF_IS_STATUS_SUCCESS(cm_fw_roam_sync_start_ind(vdev,
 							     sync_ind))) {
-		mlme_err("LFR3: CSR Roam synch cb failed");
+		mlme_err("LFR3: vdev:%d CSR Roam synch cb failed", vdev_id);
 		wlan_cm_free_roam_synch_frame_ind(rso_cfg);
 		goto err;
 	}
@@ -554,7 +555,8 @@ QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev,
 					(QDF_IEEE80211_3ADDR_HDR_LEN +
 					 MAC_B_PR_SSID_OFFSET);
 		} else {
-			mlme_err("LFR3: MLO: Invalid link Beacon Length");
+			mlme_err("LFR3: MLO: vdev:%d Invalid link Beacon Length",
+				 vdev_id);
 			goto err;
 		}
 	} else if (sync_ind->beacon_probe_resp_length >
@@ -580,14 +582,14 @@ QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev,
 			(QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET);
 
 	} else {
-		mlme_err("LFR3: Invalid Beacon Length");
+		mlme_err("LFR3: vdev:%d Invalid Beacon Length", vdev_id);
 		goto err;
 	}
 
 	if (QDF_IS_STATUS_ERROR(cm_roam_pe_sync_callback(sync_ind,
 							 vdev_id,
 							 ie_len))) {
-		mlme_err("LFR3: PE roam synch cb failed");
+		mlme_err("LFR3: vdev:%d PE roam synch cb failed", vdev_id);
 		status = QDF_STATUS_E_BUSY;
 		goto err;
 	}

+ 11 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c

@@ -1183,6 +1183,13 @@ cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev,
 				continue;
 			}
 
+			/*
+			 * Reject the partner link that doesn’t pass the
+			 * security check and validate the next available
+			 * partner link. If none of the partner link passes
+			 * the security check, proceed connection with
+			 * single link.
+			 */
 			is_security_allowed =
 				wlan_cm_is_eht_allowed_for_current_security(
 							part_scan_entry);
@@ -1618,6 +1625,9 @@ cm_update_tid_mapping(struct wlan_objmgr_vdev *vdev)
 	if (!vdev || !vdev->mlo_dev_ctx)
 		return QDF_STATUS_E_NULL_VALUE;
 
+	if (!wlan_cm_is_vdev_connected(vdev))
+		return QDF_STATUS_E_AGAIN;
+
 	if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) ||
 	    !mlo_check_if_all_links_up(vdev))
 		return QDF_STATUS_E_FAILURE;
@@ -1628,7 +1638,7 @@ cm_update_tid_mapping(struct wlan_objmgr_vdev *vdev)
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	status = wlan_process_bcn_prbrsp_t2lm_ie(vdev, t2lm_ctx, t2lm_ctx->tsf);
+	status = wlan_update_t2lm_mapping(vdev, t2lm_ctx, t2lm_ctx->tsf);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_err("T2LM IE beacon process failed");
 	}

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

@@ -36,6 +36,7 @@
 #include "wlan_mlo_mgr_roam.h"
 #include "wlan_t2lm_api.h"
 #include "wlan_mlo_link_force.h"
+#include <wlan_mlo_mgr_public_api.h>
 
 static void cm_abort_connect_request_timers(struct wlan_objmgr_vdev *vdev)
 {
@@ -326,9 +327,15 @@ QDF_STATUS cm_send_sb_disconnect_req(struct scheduler_msg *msg)
 		return QDF_STATUS_E_INVAL;
 	}
 
-	status = mlo_disconnect(vdev, ind->disconnect_param.source,
-				ind->disconnect_param.reason_code,
-				&ind->disconnect_param.bssid);
+	status = wlan_mlo_mgr_link_switch_defer_disconnect_req(vdev,
+							       ind->disconnect_param.source,
+							       ind->disconnect_param.reason_code);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		status = mlo_disconnect(vdev, ind->disconnect_param.source,
+					ind->disconnect_param.reason_code,
+					&ind->disconnect_param.bssid);
+	}
+
 	qdf_mem_free(ind);
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
 

+ 7 - 1
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -2125,6 +2125,8 @@ enum roam_offload_state {
  *  @timestamp:     This timestamp indicates the time when btm rsp is sent
  *  @btm_resp_dialog_token: Dialog token
  *  @btm_delay: BTM bss termination delay
+ *  @is_mlo: Flag to check if the current connection is a MLO connection
+ *  @band: Band of the link that is involved in frame exchange
  */
 struct roam_btm_response_data {
 	bool present;
@@ -2134,6 +2136,8 @@ struct roam_btm_response_data {
 	uint32_t timestamp;
 	uint16_t btm_resp_dialog_token;
 	uint8_t btm_delay;
+	bool is_mlo;
+	uint8_t band;
 };
 
 /**
@@ -2775,7 +2779,8 @@ struct cm_hw_mode_trans_ind {
  * @link_id: link id of the link
  * @channel: wmi channel
  * @flags: link flags
- * @link_addr: link mac addr
+ * @link_addr: link mac address
+ * @self_link_addr: VDEV link mac address
  */
 struct ml_setup_link_param {
 	uint32_t vdev_id;
@@ -2783,6 +2788,7 @@ struct ml_setup_link_param {
 	wmi_channel channel;
 	uint32_t flags;
 	struct qdf_mac_addr link_addr;
+	struct qdf_mac_addr self_link_addr;
 };
 
 /**

+ 91 - 10
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -3239,7 +3239,7 @@ cm_roam_stats_print_scan_info(struct wlan_objmgr_psoc *psoc,
  * @trigger: roam trigger information
  * @res:     Roam result structure pointer
  * @scan_data: scan data
- * @vdev_id: Vdev id
+ * @vdev_id: vdev id
  *
  * Print roam result and failure reason if roaming failed.
  *
@@ -3403,16 +3403,19 @@ cm_get_frame_subtype_str(enum mgmt_subtype frame_subtype)
 #define WLAN_SAE_AUTH_ALGO 3
 static void
 cm_roam_print_frame_info(struct wlan_objmgr_psoc *psoc,
+			 struct wlan_objmgr_vdev *vdev,
 			 struct roam_frame_stats *frame_data,
-			 struct wmi_roam_scan_data *scan_data, uint8_t vdev_id)
+			 struct wmi_roam_scan_data *scan_data)
 {
 	struct roam_frame_info *frame_info;
 	char time[TIME_STRING_LEN];
-	uint8_t i;
+	uint8_t i, vdev_id;
 
 	if (!frame_data->num_frame)
 		return;
 
+	vdev_id = wlan_vdev_get_id(vdev);
+
 	for (i = 0; i < frame_data->num_frame; i++) {
 		frame_info = &frame_data->frame_info[i];
 		if (frame_info->auth_algo == WLAN_SAE_AUTH_ALGO &&
@@ -3438,7 +3441,7 @@ cm_roam_print_frame_info(struct wlan_objmgr_psoc *psoc,
 				       frame_info->status_code,
 				       frame_info->seq_num);
 
-		cm_roam_mgmt_frame_event(frame_info, scan_data, vdev_id);
+		cm_roam_mgmt_frame_event(vdev, frame_info, scan_data);
 	}
 }
 
@@ -3524,11 +3527,20 @@ cm_roam_handle_btm_stats(struct wlan_objmgr_psoc *psoc,
 			 uint8_t *rem_tlv_len)
 {
 	bool log_btm_frames_only = false;
+	struct wlan_objmgr_vdev *vdev;
 
 	if (stats_info->data_11kv[i].present)
 		cm_roam_stats_print_11kv_info(psoc, &stats_info->data_11kv[i],
 					      stats_info->vdev_id);
 
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						    stats_info->vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev: %d vdev not found", stats_info->vdev_id);
+		return;
+	}
+
 	/*
 	 * If roam trigger is BTM and roam scan type is no scan then
 	 * the roam stats event is for BTM frames logging.
@@ -3562,17 +3574,21 @@ cm_roam_handle_btm_stats(struct wlan_objmgr_psoc *psoc,
 	}
 
 	if (stats_info->result[i].present)
-		cm_roam_stats_print_roam_result(psoc, &stats_info->trigger[i],
+		cm_roam_stats_print_roam_result(psoc,
+						&stats_info->trigger[i],
 						&stats_info->result[i],
 						&stats_info->scan[i],
 						stats_info->vdev_id);
 
 	if (stats_info->frame_stats[i].num_frame)
-		cm_roam_print_frame_info(psoc, &stats_info->frame_stats[i],
-					 &stats_info->scan[i],
-					 stats_info->vdev_id);
+		cm_roam_print_frame_info(psoc, vdev,
+					 &stats_info->frame_stats[i],
+					 &stats_info->scan[i]);
 
 log_btm_frames_only:
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+
 	/*
 	 * Print BTM resp TLV info (wmi_roam_btm_response_info) only
 	 * when trigger reason is BTM or WTC_BTM. As for other roam
@@ -4075,6 +4091,57 @@ wlan_cm_clear_current_roam_stats_info(struct mlme_legacy_priv *mlme_priv)
 		    sizeof(struct enhance_roam_info), 0);
 }
 
+/**
+ * wlan_cm_update_roam_bssid() - API to get roam stats AP BSSID
+ * @mlme_priv: Pointer to Pointer to vdev mlme legacy priv struct
+ * @scan: Scan data from target_if wmi event
+ *
+ * get AP BSSID from roam stats info which keep in scan data.
+ *
+ * Return: void
+ */
+static void
+wlan_cm_update_roam_bssid(struct mlme_legacy_priv *mlme_priv,
+			  struct wmi_roam_scan_data *scan)
+{
+	struct enhance_roam_info *info;
+	int16_t i;
+	uint16_t index, scan_ap_idx;
+	struct wmi_roam_candidate_info *ap = NULL;
+
+	if (scan->num_ap == 0)
+		return;
+
+	scan_ap_idx = scan->num_ap - 1;
+	ap = &scan->ap[scan_ap_idx];
+
+	index = mlme_priv->roam_write_index;
+	info = &mlme_priv->roam_info[index];
+
+	/* For roam failed, we may get candidate ap list, and only
+	 * fetch the last candidate AP bssid.
+	 */
+
+	for (i = scan_ap_idx; i >= 0; i--) {
+		if (ap->type == WLAN_ROAM_SCAN_CURRENT_AP)
+			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,
+				     QDF_MAC_ADDR_SIZE);
+		else
+			mlme_debug("unknown type:%u of AP", ap->type);
+		ap--;
+	}
+}
+
 /**
  * wlan_cm_update_roam_stats_info() - API to update roam stats info
  * @psoc:    Pointer to psoc
@@ -4131,6 +4198,9 @@ wlan_cm_update_roam_stats_info(struct wlan_objmgr_psoc *psoc,
 		if (stats_info->frame_stats[index].num_frame)
 			wlan_cm_update_roam_frame_info(mlme_priv,
 						       &stats_info->frame_stats[index]);
+		if (stats_info->scan[index].present)
+			wlan_cm_update_roam_bssid(mlme_priv,
+						  &stats_info->scan[index]);
 
 		mlme_priv->roam_write_index += 1;
 		if (mlme_priv->roam_write_index == mlme_priv->roam_cache_num)
@@ -4234,10 +4304,18 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 	uint8_t i, rem_tlv = 0;
 	bool is_wtc = false;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_objmgr_vdev *vdev;
 
 	if (!stats_info)
 		return QDF_STATUS_E_FAILURE;
 
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, stats_info->vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
 	for (i = 0; i < stats_info->num_tlv; i++) {
 		if (stats_info->trigger[i].present) {
 			bool is_full_scan =
@@ -4274,9 +4352,9 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 
 		if (stats_info->frame_stats[i].num_frame)
 			cm_roam_print_frame_info(psoc,
+						 vdev,
 						 &stats_info->frame_stats[i],
-						 &stats_info->scan[i],
-						 stats_info->vdev_id);
+						 &stats_info->scan[i]);
 
 		wlan_cm_update_roam_stats_info(psoc, stats_info, i);
 
@@ -4315,6 +4393,8 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 					stats_info, 0, i, 0);
 	}
 
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+
 	if (!stats_info->num_tlv) {
 		/*
 		 * wmi_roam_trigger_reason TLV is sent only for userspace
@@ -4376,6 +4456,7 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 		}
 	}
 
+out:
 	wlan_clear_sae_auth_logs_cache(psoc, stats_info->vdev_id);
 	qdf_mem_free(stats_info->roam_msg_info);
 	qdf_mem_free(stats_info);

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

@@ -22,6 +22,7 @@
 
 #include <wlan_mlo_mgr_cmn.h>
 #include <wlan_mlo_mgr_public_structs.h>
+#include <wlan_mlo_mgr_link_switch.h>
 
 /**
  * enum ml_nlink_change_event_type - Ml link state change trigger event
@@ -62,6 +63,7 @@ struct ml_nlink_change_event {
 			uint8_t curr_ieee_link_id;
 			uint8_t new_ieee_link_id;
 			uint32_t new_primary_freq;
+			enum wlan_mlo_link_switch_reason reason;
 		} link_switch;
 	} evt;
 };
@@ -127,6 +129,8 @@ ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,
 			    enum ml_nlink_change_event_type evt,
 			    struct ml_nlink_change_event *data);
 
+#define MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT (sizeof(uint32_t) * 8)
+
 /**
  * ml_nlink_convert_linkid_bitmap_to_vdev_bitmap() - convert link
  * id bitmap to vdev id bitmap

+ 27 - 0
components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h

@@ -337,6 +337,20 @@ void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev);
 void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev);
 
 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+/**
+ * mlo_mgr_roam_update_ap_link_info() - Update AP links information
+ * @vdev: Object Manager vdev
+ * @src_link_info: Source link setup information
+ * @channel: Channel information
+ *
+ * Update AP link information for each link of AP MLD
+ *
+ * Return: None
+ */
+void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev,
+				      struct ml_setup_link_param *src_link_info,
+				      struct wlan_channel *channel);
+
 /**
  * mlo_cm_roam_sync_cb - Callback function from CM to MLO mgr
  *
@@ -480,6 +494,13 @@ mlo_roam_get_link_id(uint8_t vdev_id,
 }
 
 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+/**
+ * mlo_cm_roam_sync_cb() - MLO callback to handle roam synch event
+ * for MLO vdev
+ * @vdev: Pointer to objmgr vdev
+ * @event: Pointer to event
+ * @event_data_len: event data length
+ */
 QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev,
 			       void *event, uint32_t event_data_len);
 #else
@@ -608,6 +629,12 @@ mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_E_NOSUPPORT;
 }
 
+static inline
+void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev,
+				      struct ml_setup_link_param *src_info,
+				      struct wlan_channel *channel)
+{}
+
 static inline uint32_t
 mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind,
 				     uint8_t *link_mac_addr)

+ 37 - 0
components/umac/mlme/mlo_mgr/inc/wlan_t2lm_api.h

@@ -246,7 +246,44 @@ wlan_t2lm_clear_all_tid_mapping(struct wlan_objmgr_vdev *vdev);
 QDF_STATUS
 wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev,
 				      struct mlo_link_disable_request_evt_params *params);
+
+/**
+ * wlan_update_t2lm_mapping - Update t2lm mapping to fw
+ * @vdev: pointer to vdev
+ * @rx_t2lm: received t2lm mapping from beacon
+ * @tsf: timing sync function value
+ *
+ * Return: qdf status
+ */
+QDF_STATUS wlan_update_t2lm_mapping(
+		struct wlan_objmgr_vdev *vdev,
+		struct wlan_t2lm_context *rx_t2lm,
+		uint64_t tsf);
+
+/**
+ * wlan_t2lm_init_default_mapping - Initialize t2lm to default mapping
+ * @t2lm_ctx: t2lm ctx stored in ml dev ctx
+ *
+ * Return: qdf status
+ */
+QDF_STATUS
+wlan_t2lm_init_default_mapping(struct wlan_t2lm_context *t2lm_ctx);
+
 #else
+static inline QDF_STATUS
+wlan_t2lm_init_default_mapping(struct wlan_t2lm_context *t2lm_ctx)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline QDF_STATUS wlan_update_t2lm_mapping(
+		struct wlan_objmgr_vdev *vdev,
+		struct wlan_t2lm_context *rx_t2lm,
+		uint64_t tsf)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
 static inline QDF_STATUS
 wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev,
 				      struct mlo_link_disable_request_evt_params *params)

+ 78 - 11
components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c

@@ -45,6 +45,7 @@ ml_nlink_convert_linkid_bitmap_to_vdev_bitmap(
 	uint16_t link_id;
 	uint8_t vdev_id;
 	uint32_t associated_link_bitmap = 0;
+	uint8_t vdev_per_bitmap = MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT;
 
 	*vdev_id_bitmap_sz = 0;
 	*vdev_id_num = 0;
@@ -85,10 +86,10 @@ ml_nlink_convert_linkid_bitmap_to_vdev_bitmap(
 		 */
 		if (!(link_bitmap & (1 << link_id)))
 			continue;
-		j = vdev_id / 32;
+		j = vdev_id / vdev_per_bitmap;
 		if (j >= MLO_VDEV_BITMAP_SZ)
 			break;
-		vdev_id_bitmap[j] |= 1 << (vdev_id % 32);
+		vdev_id_bitmap[j] |= 1 << (vdev_id % vdev_per_bitmap);
 		if (j + 1 > bitmap_sz)
 			bitmap_sz = j + 1;
 
@@ -124,6 +125,7 @@ ml_nlink_convert_vdev_bitmap_to_linkid_bitmap(
 	uint16_t link_id;
 	uint8_t vdev_id;
 	uint32_t associated_link_bitmap = 0;
+	uint8_t vdev_per_bitmap = MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT;
 
 	*link_bitmap = 0;
 	if (associated_bitmap)
@@ -157,7 +159,7 @@ ml_nlink_convert_vdev_bitmap_to_linkid_bitmap(
 			continue;
 		}
 		associated_link_bitmap |= 1 << link_id;
-		j = vdev_id / 32;
+		j = vdev_id / vdev_per_bitmap;
 		if (j >= vdev_id_bitmap_sz) {
 			mlo_err("invalid vdev id %d", vdev_id);
 			continue;
@@ -165,7 +167,7 @@ ml_nlink_convert_vdev_bitmap_to_linkid_bitmap(
 		/* If the vdev_id is not interested one which is specified
 		 * in "vdev_id_bitmap", continue the search.
 		 */
-		if (!(vdev_id_bitmap[j] & (1 << (vdev_id % 32))))
+		if (!(vdev_id_bitmap[j] & (1 << (vdev_id % vdev_per_bitmap))))
 			continue;
 
 		*link_bitmap |= 1 << link_id;
@@ -1774,6 +1776,47 @@ ml_nlink_update_force_active_num(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+static bool
+ml_nlink_all_links_ready_for_state_change(struct wlan_objmgr_psoc *psoc,
+					  struct wlan_objmgr_vdev *vdev,
+					  enum ml_nlink_change_event_type evt)
+{
+	uint8_t ml_num_link = 0;
+	uint32_t ml_link_bitmap = 0;
+	uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS];
+
+	if (!mlo_check_if_all_links_up(vdev))
+		return false;
+
+	if (mlo_mgr_is_link_switch_in_progress(vdev) &&
+	    evt != ml_nlink_connect_completion_evt) {
+		mlo_debug("mlo vdev %d link switch in progress!",
+			  wlan_vdev_get_id(vdev));
+		return false;
+	}
+	/* For initial connecting to 2 or 3 links ML ap, assoc link and
+	 * non assoc link connected one by one, avoid changing link state
+	 * before link vdev connect completion, to check connected link count.
+	 * If < 2, means non assoc link connect is not completed, disallow
+	 * link state change.
+	 */
+	if (!mlo_mgr_is_link_switch_in_progress(vdev) &&
+	    evt == ml_nlink_connect_completion_evt) {
+		ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_STANDBY_LINK,
+				       QDF_ARRAY_SIZE(ml_linkid_lst),
+				       ml_link_info, ml_freq_lst, ml_vdev_lst,
+				       ml_linkid_lst, &ml_num_link,
+				       &ml_link_bitmap);
+		if (ml_num_link < 2)
+			return false;
+	}
+
+	return true;
+}
+
 /**
  * ml_nlink_state_change() - Handle ML STA link force
  * with concurrency internal function
@@ -1822,14 +1865,8 @@ static QDF_STATUS ml_nlink_state_change(struct wlan_objmgr_psoc *psoc,
 	vdev = ml_nlink_get_affect_ml_sta(psoc);
 	if (!vdev)
 		goto end;
-	if (!mlo_check_if_all_links_up(vdev))
+	if (!ml_nlink_all_links_ready_for_state_change(psoc, vdev, evt))
 		goto end;
-	if (mlo_mgr_is_link_switch_in_progress(vdev) &&
-	    evt != ml_nlink_connect_completion_evt) {
-		mlo_debug("mlo vdev %d link switch in progress!",
-			  wlan_vdev_get_id(vdev));
-		goto end;
-	}
 
 	ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state);
 
@@ -2011,6 +2048,8 @@ ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,
 	enum QDF_OPMODE mode;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct ml_link_force_state curr_force_state = {0};
+	bool is_set_link_in_progress = policy_mgr_is_set_link_in_progress(psoc);
+	bool is_host_force;
 
 	mlo_debug("vdev %d %s(%d)", vdev_id, link_evt_to_string(evt),
 		  evt);
@@ -2024,6 +2063,34 @@ ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc,
 
 	switch (evt) {
 	case ml_nlink_link_switch_start_evt:
+		if (data->evt.link_switch.reason ==
+		    MLO_LINK_SWITCH_REASON_HOST_FORCE) {
+			is_host_force = true;
+		} else {
+			is_host_force = false;
+		}
+
+		mlo_debug("set_link_in_prog %d reason %d",
+			  is_set_link_in_progress,
+			  data->evt.link_switch.reason);
+
+		if (is_set_link_in_progress) {
+			/* If set active is in progress then only accept host
+			 * force link switch requests from FW
+			 */
+			if (is_host_force)
+				status = QDF_STATUS_SUCCESS;
+			else
+				status = QDF_STATUS_E_INVAL;
+			break;
+		} else if (is_host_force) {
+			/* If set active is not in progress but FW sent host
+			 * force then reject the link switch
+			 */
+			status = QDF_STATUS_E_INVAL;
+			break;
+		}
+
 		ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state);
 		if ((1 << data->evt.link_switch.new_ieee_link_id) &
 		    curr_force_state.force_inactive_bitmap) {

+ 74 - 1
components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c

@@ -212,6 +212,7 @@ mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc,
 #endif
 
 static void mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc *psoc,
+					 struct roam_offload_synch_ind *sync_ind,
 					 uint8_t vdev_id,
 					 bool is_non_ml_connection)
 {
@@ -231,8 +232,25 @@ static void mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc *psoc,
 		if (!qdf_is_macaddr_zero(mld_mac))
 			wlan_vdev_mlme_set_macaddr(vdev, mld_mac->bytes);
 	} else {
+		struct qdf_mac_addr *vdev_link_addr;
+		uint8_t i;
+
 		wlan_vdev_mlme_set_macaddr(vdev,
 					   wlan_vdev_mlme_get_linkaddr(vdev));
+		/* Update the link address received from fw to assoc vdev */
+		for (i = 0; i < sync_ind->num_setup_links; i++) {
+			if (vdev_id != sync_ind->ml_link[i].vdev_id)
+				continue;
+
+			vdev_link_addr = &sync_ind->ml_link[i].self_link_addr;
+			if (qdf_is_macaddr_zero(vdev_link_addr) ||
+			    qdf_is_macaddr_broadcast(vdev_link_addr))
+				continue;
+
+			wlan_vdev_mlme_set_macaddr(vdev, vdev_link_addr->bytes);
+			wlan_vdev_mlme_set_linkaddr(vdev,
+						    vdev_link_addr->bytes);
+		}
 	}
 
 	mlme_debug("vdev_id %d self mac " QDF_MAC_ADDR_FMT,
@@ -271,7 +289,7 @@ QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 		mlo_set_single_link_ml_roaming(psoc, vdev_id, false);
 	}
 
-	mlo_roam_update_vdev_macaddr(psoc, vdev_id, is_non_mlo_ap);
+	mlo_roam_update_vdev_macaddr(psoc, sync_ind, vdev_id, is_non_mlo_ap);
 	ml_nlink_conn_change_notify(
 		psoc, vdev_id, ml_nlink_roam_sync_start_evt, NULL);
 
@@ -284,6 +302,41 @@ QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 }
 
 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev,
+				      struct ml_setup_link_param *src_link_info,
+				      struct wlan_channel *channel)
+{
+	struct mlo_link_info *link_info;
+	uint8_t iter;
+
+	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx ||
+	    !src_link_info)
+		return;
+
+	for (iter = 0; iter < WLAN_MAX_ML_BSS_LINKS; iter++) {
+		link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[iter];
+		if (qdf_is_macaddr_zero(&link_info->ap_link_addr))
+			break;
+	}
+
+	if (iter == WLAN_MAX_ML_BSS_LINKS)
+		return;
+
+	link_info->link_id = src_link_info->link_id;
+	link_info->vdev_id = src_link_info->vdev_id;
+	qdf_mem_copy(&link_info->ap_link_addr, src_link_info->link_addr.bytes,
+		     QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(&link_info->link_addr, src_link_info->self_link_addr.bytes,
+		     QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(link_info->link_chan_info, channel, sizeof(*channel));
+
+	mlo_debug("link_id: %d, vdev_id:%d freq:%d ap_link_addr: "QDF_MAC_ADDR_FMT", self_link_addr: "QDF_MAC_ADDR_FMT,
+		  link_info->link_id, link_info->vdev_id,
+		  link_info->link_chan_info->ch_freq,
+		  QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes),
+		  QDF_MAC_ADDR_REF(link_info->link_addr.bytes));
+}
+
 QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev,
 			       void *event, uint32_t event_data_len)
 {
@@ -335,8 +388,19 @@ QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev,
 		}
 
 		if (mlo_check_connect_req_bmap(link_vdev)) {
+			struct qdf_mac_addr *vdev_link_addr;
+
 			mlo_update_connect_req_links(link_vdev, false);
 
+			vdev_link_addr = &sync_ind->ml_link[i].self_link_addr;
+			if (!qdf_is_macaddr_zero(vdev_link_addr) &&
+			    !qdf_is_macaddr_broadcast(vdev_link_addr)) {
+				wlan_vdev_mlme_set_macaddr(link_vdev,
+							   vdev_link_addr->bytes);
+				wlan_vdev_mlme_set_linkaddr(link_vdev,
+							    vdev_link_addr->bytes);
+			}
+
 			status = cm_fw_roam_sync_req(psoc,
 						     sync_ind->ml_link[i].vdev_id,
 						     event, event_data_len);
@@ -744,6 +808,11 @@ mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev)
 	}
 
 	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	if (!mlo_dev_ctx->sta_ctx) {
+		mlo_err("mlo sta ctx is null");
+		return false;
+	}
+
 	sta_ctx = mlo_dev_ctx->sta_ctx;
 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
 		if (!mlo_dev_ctx->wlan_vdev_list[i])
@@ -784,6 +853,10 @@ mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev)
 	}
 
 	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	if (!mlo_dev_ctx->sta_ctx) {
+		mlo_err("mlo sta ctx is null");
+		return false;
+	}
 	sta_ctx = mlo_dev_ctx->sta_ctx;
 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
 		if (!mlo_dev_ctx->wlan_vdev_list[i])

+ 212 - 0
components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c

@@ -595,6 +595,16 @@ wlan_t2lm_clear_all_tid_mapping(struct wlan_objmgr_vdev *vdev)
 		     sizeof(struct wlan_mlo_t2lm_ie));
 	t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
 
+	t2lm_debug("Clear the T2LM info received in assoc rsp");
+	t2lm_ctx = &vdev->mlo_dev_ctx->sta_ctx->copied_t2lm_ie_assoc_rsp;
+
+	qdf_mem_zero(&t2lm_ctx->established_t2lm,
+		     sizeof(struct wlan_mlo_t2lm_ie));
+	t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
+	qdf_mem_zero(&t2lm_ctx->upcoming_t2lm,
+		     sizeof(struct wlan_mlo_t2lm_ie));
+	t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
+
 	wlan_t2lm_clear_peer_negotiation(peer);
 	wlan_t2lm_clear_ongoing_negotiation(peer);
 	wlan_mlo_t2lm_timer_stop(vdev);
@@ -729,3 +739,205 @@ QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
 	return t2lm_deliver_event(vdev, peer, event, event_data,
 				  frame_len, dialog_token);
 }
+
+QDF_STATUS
+wlan_t2lm_init_default_mapping(struct wlan_t2lm_context *t2lm_ctx)
+{
+	if (!t2lm_ctx)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	qdf_mem_zero(t2lm_ctx, sizeof(struct wlan_t2lm_context));
+
+	t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1;
+	t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION;
+	t2lm_ctx->established_t2lm.t2lm.link_mapping_size = 0;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_update_t2lm_mapping(struct wlan_objmgr_vdev *vdev,
+			 struct wlan_t2lm_context *rx_t2lm, uint64_t tsf)
+{
+	struct wlan_t2lm_context *t2lm_ctx;
+	struct wlan_mlo_dev_context *mlo_dev_ctx;
+	uint64_t mst_start_tsf;
+	uint64_t mst_end_tsf;
+	uint64_t rx_bcn_tsf_exp_dur;
+	uint64_t mst_end_tsf_low;
+	uint64_t mst_end_tsf_high;
+	uint16_t mst;
+	uint32_t exp_dur;
+
+	if (!vdev)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev);
+	if (!mlo_dev_ctx)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	t2lm_ctx = &mlo_dev_ctx->t2lm_ctx;
+	if (rx_t2lm->upcoming_t2lm.t2lm.direction == WLAN_T2LM_INVALID_DIRECTION &&
+	    rx_t2lm->established_t2lm.t2lm.direction == WLAN_T2LM_INVALID_DIRECTION) {
+		if (!t2lm_ctx->established_t2lm.t2lm.default_link_mapping) {
+			wlan_t2lm_init_default_mapping(t2lm_ctx);
+			t2lm_debug("initialize to default T2LM mapping");
+		}
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (rx_t2lm->established_t2lm.t2lm.expected_duration &&
+	    !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present &&
+	    rx_t2lm->upcoming_t2lm.t2lm.expected_duration &&
+	    rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) {
+		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
+				 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid,
+				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
+			t2lm_debug("T2LM mapping is already configured");
+			return QDF_STATUS_E_ALREADY;
+		}
+
+		qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm,
+			     &rx_t2lm->established_t2lm.t2lm,
+			     sizeof(struct wlan_t2lm_info));
+
+		t2lm_ctx->established_t2lm.t2lm.expected_duration = 0;
+		t2lm_ctx->established_t2lm.t2lm.expected_duration_present = 0;
+		t2lm_ctx->established_t2lm.t2lm.mapping_switch_time = 0;
+		t2lm_ctx->established_t2lm.t2lm.mapping_switch_time_present = 0;
+
+		wlan_mlo_dev_t2lm_notify_link_update(vdev,
+					&t2lm_ctx->established_t2lm.t2lm);
+		wlan_clear_peer_level_tid_to_link_mapping(vdev);
+		t2lm_debug("Update T2LM established mapping to FW");
+		wlan_send_tid_to_link_mapping(
+				vdev, &t2lm_ctx->established_t2lm.t2lm);
+
+		if (!qdf_mem_cmp(t2lm_ctx->upcoming_t2lm.t2lm.ieee_link_map_tid,
+				 rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid,
+				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
+			t2lm_debug("Ongoing mapping is already established");
+			return QDF_STATUS_E_ALREADY;
+		}
+		qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm,
+			     &rx_t2lm->upcoming_t2lm.t2lm,
+			     sizeof(struct wlan_t2lm_info));
+		t2lm_debug("Update T2LM upcoming mapping to FW");
+		wlan_send_tid_to_link_mapping(
+				vdev, &t2lm_ctx->upcoming_t2lm.t2lm);
+	}
+
+	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present &&
+	    rx_t2lm->established_t2lm.t2lm.expected_duration_present) {
+		/* Established T2LM is already saved in the T2LM context.
+		 * T2LM IE in the beacon/probe response frame has the updated
+		 * expected duration.
+		 */
+		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
+				 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid,
+				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
+			if (!t2lm_ctx->mst_start_tsf) {
+				t2lm_ctx->mst_end_tsf = tsf + (rx_t2lm->established_t2lm.t2lm.expected_duration << 10);
+				t2lm_ctx->mst_start_tsf = tsf;
+			}
+
+			/* Check if AP has updated expected duration value
+			 * more than expected delta between 2 beacons,
+			 * calculation as following:
+			 * 1.when receive a beacon with mapping switch
+			 * time set, calculate the mapping switch start TSF
+			 * by replacing bit25~bit10 in the bcn TSF
+			 * mst_start_tsf = (bcn_tsf & (~mst_mask)) | (mst << 10);
+			 * 2.based on the expected duration,
+			 * calculate the mapping end time tsf
+			 * mst_end_tsf = mst_start_tsf + expected_duration;
+			 * 3.then after the TSF become established mapping,
+			 *  whenever host receive a beacon,
+			 * check if the new expected duration based
+			 * on current beacon TSF has a big drift to the old one.
+			 * mst_end_tsf - (200 << 10) < rx_bcn_tsf_exp_dur +
+			 *  rx_bcn_tsf_exp_dur < mst_end_tsf + (200 << 10)
+			 */
+			rx_bcn_tsf_exp_dur = tsf + (rx_t2lm->established_t2lm.t2lm.expected_duration << 10);
+			mst_end_tsf_low = t2lm_ctx->mst_end_tsf - (200 << 10);
+			mst_end_tsf_high = t2lm_ctx->mst_end_tsf + (200 << 10);
+			if (t2lm_ctx->mst_end_tsf && (rx_bcn_tsf_exp_dur < mst_end_tsf_low) &&
+			    (rx_bcn_tsf_exp_dur > mst_end_tsf_high)) {
+				t2lm_ctx->established_t2lm.t2lm.expected_duration =
+					rx_t2lm->established_t2lm.t2lm.expected_duration;
+				wlan_send_tid_to_link_mapping(
+					vdev, &t2lm_ctx->established_t2lm.t2lm);
+			} else {
+				t2lm_debug("T2LM exp duration in range");
+			}
+		}
+	} else if (rx_t2lm->established_t2lm.t2lm.expected_duration_present &&
+		   !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present) {
+		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
+				 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid,
+				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
+			t2lm_debug("T2LM mapping is already configured");
+			return QDF_STATUS_E_ALREADY;
+		}
+
+		mst_start_tsf = tsf;
+		t2lm_ctx->mst_start_tsf = mst_start_tsf;
+		mst_end_tsf = mst_start_tsf + (rx_t2lm->established_t2lm.t2lm.expected_duration << 10);
+		t2lm_ctx->mst_end_tsf = mst_end_tsf;
+
+		/* Mapping switch time is already expired when STA receives the
+		 * T2LM IE from beacon/probe response frame.
+		 */
+		qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm,
+			     &rx_t2lm->established_t2lm.t2lm,
+			     sizeof(struct wlan_t2lm_info));
+
+		/* Notify the registered caller about the link update*/
+		wlan_mlo_dev_t2lm_notify_link_update(vdev,
+					&t2lm_ctx->established_t2lm.t2lm);
+		wlan_clear_peer_level_tid_to_link_mapping(vdev);
+		t2lm_debug("MST expired, update established T2LM mapping to FW");
+		wlan_send_tid_to_link_mapping(
+				vdev, &t2lm_ctx->established_t2lm.t2lm);
+	}
+
+	if (rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) {
+		if (!qdf_mem_cmp(t2lm_ctx->upcoming_t2lm.t2lm.ieee_link_map_tid,
+				 rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid,
+				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
+			t2lm_debug("Ongoing mapping is already established");
+			return QDF_STATUS_E_ALREADY;
+		}
+
+		mst = rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time;
+		exp_dur = rx_t2lm->upcoming_t2lm.t2lm.expected_duration;
+		if (mst) {
+			mst_start_tsf = (tsf & (~WLAN_T2LM_MAPPING_SWITCH_TSF_BITS)) | (mst << 10);
+			mst_end_tsf = mst_start_tsf + exp_dur;
+			t2lm_ctx->mst_start_tsf = mst_start_tsf;
+			t2lm_ctx->mst_end_tsf = mst_end_tsf;
+		}
+
+		qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm,
+			     &rx_t2lm->upcoming_t2lm.t2lm,
+			     sizeof(struct wlan_t2lm_info));
+		t2lm_debug("Update T2LM upcoming mapping to FW");
+		wlan_send_tid_to_link_mapping(
+				vdev, &t2lm_ctx->upcoming_t2lm.t2lm);
+	} else {
+		if (t2lm_ctx->established_t2lm.t2lm.direction == WLAN_T2LM_INVALID_DIRECTION &&
+		    t2lm_ctx->upcoming_t2lm.t2lm.direction != WLAN_T2LM_INVALID_DIRECTION) {
+			t2lm_debug("Copy upcoming T2LM mapping to expected T2LM");
+			qdf_mem_copy(&t2lm_ctx->established_t2lm,
+				     &t2lm_ctx->upcoming_t2lm,
+				     sizeof(struct wlan_mlo_t2lm_ie));
+		}
+		/* Upcoming mapping should be cleared as mapping switch time has expired */
+		qdf_mem_zero(&t2lm_ctx->upcoming_t2lm,
+			     sizeof(struct wlan_mlo_t2lm_ie));
+		t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+

+ 21 - 0
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c

@@ -16,6 +16,7 @@
 
 #include "wlan_ll_sap_main.h"
 #include <wlan_objmgr_global_obj.h>
+#include "qca_vendor.h"
 
 static QDF_STATUS ll_sap_psoc_obj_created_notification(struct wlan_objmgr_psoc *psoc, void *arg_list)
 {
@@ -92,3 +93,23 @@ QDF_STATUS ll_sap_deinit(void)
 
 	return ret;
 }
+
+QDF_STATUS ll_lt_sap_request_for_audio_transport_switch(
+						uint8_t transport_switch_type)
+{
+	/*
+	 * return status as QDF_STATUS_SUCCESS or failure based on the current
+	 * pending requests of the transport switch
+	 */
+	if (transport_switch_type ==
+		QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN) {
+		ll_sap_debug("request SWITCH_TYPE_NON_WLAN accepted");
+		return QDF_STATUS_SUCCESS;
+	} else if (transport_switch_type ==
+				QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN) {
+		ll_sap_debug("request SWITCH_TYPE_WLAN accepted");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_RESOURCES;
+}

+ 10 - 0
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h

@@ -48,4 +48,14 @@ QDF_STATUS ll_sap_init(void);
  */
 QDF_STATUS ll_sap_deinit(void);
 
+/**
+ * ll_lt_sap_request_for_audio_transport_switch() - Check if audio transport
+ * switch request can be supported or not
+ * @transport_switch_type: requested transport switch type
+ *
+ * Return: True/False
+ */
+QDF_STATUS ll_lt_sap_request_for_audio_transport_switch(
+						uint8_t transport_switch_type);
+
 #endif /* _WLAN_LL_SAP_MAIN_H_ */

+ 16 - 0
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_ucfg_api.h

@@ -46,6 +46,16 @@ QDF_STATUS ucfg_ll_sap_deinit(void);
  */
 bool ucfg_is_ll_lt_sap_supported(void);
 
+/**
+ * ucfg_ll_lt_sap_request_for_audio_transport_switch() - Request to switch the
+ * audio transport medium
+ * @transport_switch_type: Requested transport switch type
+ *
+ * Return: Accepted/Rejected
+ */
+QDF_STATUS ucfg_ll_lt_sap_request_for_audio_transport_switch(
+						uint8_t transport_switch_type);
+
 #else
 static inline QDF_STATUS ucfg_ll_sap_init(void)
 {
@@ -62,6 +72,12 @@ static inline bool ucfg_is_ll_lt_sap_supported(void)
 	return false;
 }
 
+static inline QDF_STATUS
+ucfg_ll_lt_sap_request_for_audio_transport_switch(uint8_t transport_switch_type)
+{
+	return QDF_STATUS_E_INVAL;
+}
+
 #endif /* WLAN_FEATURE_LL_LT_SAP */
 #endif /* _WLAN_LL_SAP_UCFG_API_H_ */
 

+ 7 - 0
components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c

@@ -38,3 +38,10 @@ bool ucfg_is_ll_lt_sap_supported(void)
 	return ll_lt_sap_is_supported();
 }
 
+QDF_STATUS ucfg_ll_lt_sap_request_for_audio_transport_switch(
+						uint8_t transport_switch_type)
+{
+	return ll_lt_sap_request_for_audio_transport_switch(
+							transport_switch_type);
+}
+

+ 5 - 1
components/umac/twt/core/src/wlan_twt_main.c

@@ -2286,6 +2286,7 @@ void wlan_twt_set_work_params(
 			struct wlan_objmgr_vdev *vdev,
 			struct qdf_mac_addr *peer_mac,
 			uint8_t dialog_id,
+			bool is_ps_disabled,
 			uint32_t twt_next_action)
 {
 	struct twt_vdev_priv_obj *twt_vdev_priv;
@@ -2300,10 +2301,12 @@ void wlan_twt_set_work_params(
 
 	qdf_copy_macaddr(&twt_vdev_priv->peer_macaddr, peer_mac);
 	twt_vdev_priv->dialog_id = dialog_id;
+	twt_vdev_priv->is_ps_disabled = is_ps_disabled;
 	twt_vdev_priv->next_action = twt_next_action;
 
-	twt_debug("renego: twt_terminate: dialog_id:%d next_action:%d peer mac_addr  "
+	twt_debug("TWT terminate: dialog_id:%d is_ps_disabled:%d next_action:%d peer mac_addr  "
 		   QDF_MAC_ADDR_FMT, twt_vdev_priv->dialog_id,
+		   twt_vdev_priv->is_ps_disabled,
 		   twt_vdev_priv->next_action,
 		   QDF_MAC_ADDR_REF(twt_vdev_priv->peer_macaddr.bytes));
 }
@@ -2323,5 +2326,6 @@ void wlan_twt_get_work_params(struct wlan_objmgr_vdev *vdev,
 
 	qdf_copy_macaddr(&params->peer_macaddr, &twt_vdev_priv->peer_macaddr);
 	params->dialog_id = twt_vdev_priv->dialog_id;
+	params->is_ps_disabled = twt_vdev_priv->is_ps_disabled;
 	*next_action = twt_vdev_priv->next_action;
 }

+ 2 - 0
components/umac/twt/core/src/wlan_twt_main.h

@@ -295,6 +295,7 @@ bool wlan_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc,
  * @vdev: vdev pointer
  * @peer_mac: mac address of peer
  * @dialog_id: dialog_id of TWT session
+ * @is_ps_disabled: Whether power save is disabled or not
  * @twt_next_action: Set next action to do before work scheduled
  *
  * Return: None
@@ -303,6 +304,7 @@ void wlan_twt_set_work_params(
 			struct wlan_objmgr_vdev *vdev,
 			struct qdf_mac_addr *peer_mac,
 			uint8_t dialog_id,
+			bool is_ps_disabled,
 			uint32_t twt_next_action);
 
 /**

+ 3 - 0
components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h

@@ -283,6 +283,7 @@ bool ucfg_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc,
  * @vdev: Vdev pointer
  * @peer_mac: peer mac address
  * @dialog_id: dialog_id
+ * @is_ps_disabled: Whether Power saave is disabled or not
  * @twt_next_action: Set TWT next action to do before work schedule
  *
  * Return: None
@@ -291,6 +292,7 @@ void ucfg_twt_set_work_params(
 		struct wlan_objmgr_vdev *vdev,
 		struct qdf_mac_addr *peer_mac,
 		uint8_t dialog_id,
+		bool is_ps_disabled,
 		uint32_t twt_next_action);
 
 /**
@@ -415,6 +417,7 @@ ucfg_twt_set_work_params(
 		struct wlan_objmgr_vdev *vdev,
 		struct qdf_mac_addr *peer_mac,
 		uint8_t dialog_id,
+		bool is_ps_disabled,
 		uint32_t twt_next_action)
 {
 }

+ 2 - 1
components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c

@@ -228,10 +228,11 @@ void ucfg_twt_set_work_params(
 		struct wlan_objmgr_vdev *vdev,
 		struct qdf_mac_addr *peer_mac,
 		uint8_t dialog_id,
+		bool is_ps_disabled,
 		uint32_t twt_next_action)
 {
 	return wlan_twt_set_work_params(vdev, peer_mac, dialog_id,
-					twt_next_action);
+					is_ps_disabled, twt_next_action);
 }
 
 void ucfg_twt_get_work_params(

+ 57 - 4
components/wmi/src/wmi_unified_roam_tlv.c

@@ -1879,6 +1879,9 @@ extract_roam_btm_response_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 	dst->timestamp = src_data->timestamp;
 	dst->btm_resp_dialog_token = src_data->btm_resp_dialog_token;
 	dst->btm_delay = src_data->btm_resp_bss_termination_delay;
+	dst->band = WMI_ROAM_BTM_RESP_MLO_BAND_INFO_GET(src_data->info);
+	if (dst->band != WMI_MLO_BAND_NO_MLO)
+		dst->is_mlo = true;
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -2270,10 +2273,13 @@ wmi_fill_roam_mlo_info(wmi_unified_t wmi_handle,
 
 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&setup_links->link_addr,
 						   link->link_addr.bytes);
-			wmi_debug("link_id: %u vdev_id: %u flags: 0x%x addr:" QDF_MAC_ADDR_FMT,
+			WMI_MAC_ADDR_TO_CHAR_ARRAY(&setup_links->self_link_addr,
+						   link->self_link_addr.bytes);
+			wmi_debug("link_id: %u vdev_id: %u flags: 0x%x addr:" QDF_MAC_ADDR_FMT "self_addr:" QDF_MAC_ADDR_FMT,
 				  link->link_id, link->vdev_id,
 				  link->flags,
-				  QDF_MAC_ADDR_REF(link->link_addr.bytes));
+				  QDF_MAC_ADDR_REF(link->link_addr.bytes),
+				  QDF_MAC_ADDR_REF(link->self_link_addr.bytes));
 			wmi_debug("channel: %u mhz center_freq1: %u center_freq2: %u",
 				  link->channel.mhz,
 				  link->channel.band_center_freq1,
@@ -3007,9 +3013,10 @@ 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 = stats_info->scan[0].band;
 
 	status = wmi_unified_extract_roam_11kv_stats(
-			wmi_handle, evt_buf, &stats_info->data_11kv[0], 0, 0);
+			wmi_handle, evt_buf, &stats_info->data_11kv[0], 0, 0, band);
 	if (QDF_IS_STATUS_ERROR(status))
 		wmi_debug("Roam 11kv stats extract failed vdev %d", vdev_id);
 
@@ -3055,6 +3062,7 @@ extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 	uint8_t num_trigger_reason = 0;
 	uint32_t rem_len;
 	QDF_STATUS status;
+	uint8_t band;
 
 	param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)evt_buf;
 	if (!param_buf) {
@@ -3241,12 +3249,14 @@ 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);
+				      i, num_rpt, band);
 		if (QDF_IS_STATUS_ERROR(status))
 			wmi_debug_rl("Roam 11kv stats extract fail vdev %d iter %d",
 				     vdev_id, i);
@@ -3485,6 +3495,48 @@ extract_roam_candidate_frame_tlv(wmi_unified_t wmi_handle, uint8_t *event,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+static QDF_STATUS
+extract_peer_oper_mode_event_tlv(wmi_unified_t wmi_handle, uint8_t *event,
+				 uint32_t len,
+				 struct peer_oper_mode_event *data)
+{
+	WMI_PEER_OPER_MODE_CHANGE_EVENTID_param_tlvs *param_buf = NULL;
+	wmi_peer_oper_mode_change_event_fixed_param *params = NULL;
+
+	if (!event || !len) {
+		wmi_debug("Empty operating mode change event");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	param_buf = (WMI_PEER_OPER_MODE_CHANGE_EVENTID_param_tlvs *)event;
+	if (!param_buf) {
+		wmi_err("Received null buf from target");
+		return -EINVAL;
+	}
+
+	params =
+		(wmi_peer_oper_mode_change_event_fixed_param *)param_buf->fixed_param;
+
+	WMI_MAC_ADDR_TO_CHAR_ARRAY(&params->peer_mac_address,
+				   data->peer_mac_address.bytes);
+	data->ind_type = params->ind_type;
+	data->new_rxnss = params->new_rxnss;
+	data->new_bw = params->new_bw;
+	data->new_txnss = params->new_txnss;
+	data->new_disablemu = params->new_disablemu;
+
+	wmi_debug("peer_mac_addr: " QDF_MAC_ADDR_FMT " ind_type: %d new_rxnss: %d new_bw: %d new_txnss: %d new_disablemu: %d",
+		  QDF_MAC_ADDR_REF(data->peer_mac_address.bytes),
+		  data->ind_type,
+		  data->new_rxnss,
+		  data->new_bw,
+		  data->new_txnss,
+		  data->new_disablemu);
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #ifdef WLAN_VENDOR_HANDOFF_CONTROL
 /**
  * convert_roam_vendor_control_param() - Function to convert
@@ -4122,6 +4174,7 @@ void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
 	ops->send_vdev_set_pcl_cmd = send_vdev_set_pcl_cmd_tlv;
 	ops->send_set_roam_trigger_cmd = send_set_roam_trigger_cmd_tlv;
 	ops->extract_roam_candidate_frame = extract_roam_candidate_frame_tlv;
+	ops->extract_peer_oper_mode_event = extract_peer_oper_mode_event_tlv;
 	wmi_roam_offload_attach_vendor_handoff_tlv(ops);
 	wmi_roam_offload_attach_mlo_tlv(ops);
 }

+ 14 - 4
configs/config_to_feature.h

@@ -1328,6 +1328,10 @@
 #define WLAN_FEATURE_TSF_PLUS_NOIRQ (1)
 #endif
 
+#ifdef CONFIG_WLAN_TSF_AUTO_REPORT
+#define WLAN_FEATURE_TSF_AUTO_REPORT (1)
+#endif
+
 #ifdef CONFIG_WLAN_TSF_UPLINK_DELAY
 #define WLAN_FEATURE_TSF_UPLINK_DELAY (1)
 #endif
@@ -2273,10 +2277,6 @@
 #define WLAN_SCHED_HISTORY_SIZE (CONFIG_SCHED_HISTORY_SIZE)
 #endif
 
-#ifdef CONFIG_QDF_TIMER_MULTIPLIER_FRAC
-#define QDF_TIMER_MULTIPLIER_FRAC (CONFIG_QDF_TIMER_MULTIPLIER_FRAC)
-#endif
-
 #ifdef CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE
 #define DP_LEGACY_MODE_CSM_DEFAULT_DISABLE (CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE)
 #endif
@@ -2911,4 +2911,14 @@
 #define ENABLE_HAL_REG_WR_HISTORY (1)
 #endif
 
+#ifdef CONFIG_BCN_RATECODE_ENABLE
+#define WLAN_BCN_RATECODE_ENABLE (1)
+#endif
+
+#ifdef CONFIG_QDF_TIMER_MULTIPLIER_FRAC_ENABLE
+#ifdef CONFIG_QDF_TIMER_MULTIPLIER_FRAC
+#define QDF_TIMER_MULTIPLIER_FRAC CONFIG_QDF_TIMER_MULTIPLIER_FRAC
+#endif
+#endif
+
 #endif /* CONFIG_TO_FEATURE_H */

+ 34 - 0
configs/pineapple_consolidate_peach_defconfig

@@ -0,0 +1,34 @@
+CONFIG_ALLOW_PKT_DROPPING=y
+CONFIG_ATH_DIAG_EXT_DIRECT=y
+CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y
+CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y
+CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y
+CONFIG_DP_TX_HW_DESC_HISTORY=y
+CONFIG_DSC_DEBUG=y
+CONFIG_DSC_TEST=y
+CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y
+CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y
+CONFIG_FEATURE_UNIT_TEST_SUSPEND=y
+CONFIG_HAL_DEBUG=y
+CONFIG_HIF_CE_DEBUG_DATA_BUF=y
+CONFIG_HIF_CPU_PERF_AFFINE_MASK=y
+CONFIG_LEAK_DETECTION=y
+CONFIG_MAX_LOGS_PER_SEC=500
+CONFIG_ENABLE_MAX_LOGS_PER_SEC=y
+CONFIG_QDF_NBUF_HISTORY_SIZE=16384
+CONFIG_REGISTER_OP_DEBUG=y
+CONFIG_REO_QDESC_HISTORY=y
+CONFIG_RX_DESC_DEBUG_CHECK=y
+CONFIG_SCHED_HISTORY_SIZE=256
+CONFIG_ENABLE_SCHED_HISTORY_SIZE=y
+CONFIG_TALLOC_DEBUG=y
+CONFIG_UNIT_TEST=y
+CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y
+CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y
+CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y
+CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y
+CONFIG_WLAN_RECORD_RX_PADDR=y
+CONFIG_QDF_TEST=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_FEATURE_WLM_STATS=y
+CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y

+ 2 - 0
configs/pineapple_gki_kiwi-v2_defconfig

@@ -331,6 +331,7 @@ CONFIG_WLAN_SYSFS_BITRATES=y
 CONFIG_WLAN_THERMAL_CFG=y
 CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y
 CONFIG_WLAN_TRACEPOINTS=y
+CONFIG_WLAN_TSF_AUTO_REPORT=y
 CONFIG_WLAN_TSF_UPLINK_DELAY=y
 CONFIG_WLAN_TWT_CONVERGED=y
 CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y
@@ -386,3 +387,4 @@ CONFIG_BUS_AUTO_SUSPEND=y
 CONFIG_CNSS_OUT_OF_TREE=y
 CONFIG_SMP=y
 CONFIG_RPS=y
+CONFIG_BCN_RATECODE_ENABLE=y

+ 387 - 0
configs/pineapple_gki_peach_defconfig

@@ -0,0 +1,387 @@
+CONFIG_QCA_CLD_WLAN=y
+CONFIG_160MHZ_SUPPORT=y
+CONFIG_6G_SCAN_CHAN_SORT_ALGO=y
+CONFIG_ADAPTIVE_11R=y
+CONFIG_ANI_LEVEL_REQUEST=y
+CONFIG_AR900B=y
+CONFIG_ATH_11AC_TXCOMPACT=y
+CONFIG_ATH_BUS_PM=y
+CONFIG_ATH_PERF_PWR_OFFLOAD=y
+CONFIG_BAND_6GHZ=y
+CONFIG_BERYLLIUM=y
+CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y
+CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4
+CONFIG_CFG_MAX_STA_VDEVS=4
+CONFIG_CHECKSUM_OFFLOAD=y
+CONFIG_CHIP_VERSION=1
+CONFIG_CNSS_GENL_MODULE=y
+CONFIG_CNSS_KIWI=y
+CONFIG_CNSS_KIWI_V2=y
+CONFIG_CNSS_PEACH=y
+CONFIG_CNSS_UTILS_MODULE=y
+CONFIG_CNSS_UTILS=y
+CONFIG_CONNECTIVITY_PKTLOG=y
+CONFIG_CONVERGED_P2P_ENABLE=y
+CONFIG_CP_STATS=y
+CONFIG_DCS=y
+CONFIG_DDP_MON_RSSI_IN_DBM=y
+CONFIG_DEBUG_RX_RING_BUFFER=y
+CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y
+CONFIG_DESC_DUP_DETECT_DEBUG=y
+CONFIG_DEVICE_FORCE_WAKE_ENABLE=y
+CONFIG_DIRECT_BUF_RX_ENABLE=y
+CONFIG_DISABLE_CHANNEL_LIST=y
+CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y
+CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y
+CONFIG_DP_BE_WAR=y
+CONFIG_DP_CON_MON_MSI_ENABLED=y
+CONFIG_DP_CON_MON_MSI_SKIP_SET=y
+CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y
+CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y
+CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y
+CONFIG_DP_INTR_POLL_BASED=y
+CONFIG_DP_LFR=y
+CONFIG_DP_MEM_PRE_ALLOC=y
+CONFIG_DP_PKT_ADD_TIMESTAMP=y
+CONFIG_DP_PKT_STATS_PER_LMAC=y
+CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5
+CONFIG_DP_RX_BUFFER_POOL_SIZE=128
+CONFIG_DP_RX_DROP_RAW_FRM=y
+CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y
+CONFIG_DP_RX_SPECIAL_FRAME_NEED=y
+CONFIG_DP_TRACE=y
+CONFIG_DP_TRAFFIC_END_INDICATION=y
+CONFIG_DP_TXRX_SOC_ATTACH=y
+CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y
+CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y
+CONFIG_DUP_RX_DESC_WAR=y
+CONFIG_DYNAMIC_RX_AGGREGATION=y
+CONFIG_EMULATION_2_0=y
+CONFIG_ENABLE_HAL_REG_WR_HISTORY=y
+CONFIG_ENABLE_HAL_SOC_STATS=y
+CONFIG_ENABLE_MTRACE_LOG=y
+CONFIG_ENABLE_SMMU_S1_TRANSLATION=y
+CONFIG_FEATURE_ACTIVE_TOS=y
+CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y
+CONFIG_FEATURE_BECN_STATS=y
+CONFIG_FEATURE_BSS_TRANSITION=y
+CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y
+CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y
+CONFIG_FEATURE_COEX=y
+CONFIG_FEATURE_CONCURRENCY_MATRIX=y
+CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y
+CONFIG_FEATURE_DENYLIST_MGR=y
+CONFIG_FEATURE_EPPING=y
+CONFIG_FEATURE_FORCE_WAKE=y
+CONFIG_FEATURE_FW_LOG_PARSING=y
+CONFIG_FEATURE_GPIO_CFG=y
+CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y
+CONFIG_FEATURE_HTC_CREDIT_HISTORY=y
+CONFIG_FEATURE_INTEROP_ISSUES_AP=y
+CONFIG_FEATURE_MEMDUMP_ENABLE=y
+CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y
+CONFIG_FEATURE_MSCS=y
+CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y
+CONFIG_FEATURE_OEM_DATA=y
+CONFIG_FEATURE_OTA_TEST=y
+CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y
+CONFIG_FEATURE_RADAR_HISTORY=y
+CONFIG_FEATURE_ROAM_DEBUG=y
+CONFIG_FEATURE_RSSI_MONITOR=y
+CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y
+CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y
+CONFIG_FEATURE_SAR_LIMITS=y
+CONFIG_FEATURE_SET=y
+CONFIG_FEATURE_STATION_INFO=y
+CONFIG_FEATURE_STATS_EXT=y
+CONFIG_FEATURE_STATS_EXT_V2=y
+CONFIG_FEATURE_TSO=y
+CONFIG_FEATURE_TSO_STATS=y
+CONFIG_FEATURE_TX_POWER=y
+CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y
+CONFIG_FEATURE_WLAN_LPHB=y
+CONFIG_FEATURE_WLAN_PRE_CAC=y
+CONFIG_FEATURE_WLAN_RA_FILTERING=y
+CONFIG_FEATURE_WLAN_SCAN_PNO=y
+CONFIG_FEATURE_WLAN_WAPI=y
+CONFIG_FIX_TXDMA_LIMITATION=y
+CONFIG_FOURTH_CONNECTION=y
+CONFIG_FW_THERMAL_THROTTLE=y
+CONFIG_GET_DRIVER_MODE=y
+CONFIG_GTK_OFFLOAD=y
+CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y
+CONFIG_HANDLE_BC_EAP_TX_FRM=y
+CONFIG_HANDLE_RX_REROUTE_ERR=y
+CONFIG_HASTINGS_BT_WAR=y
+CONFIG_HDD_INIT_WITH_RTNL_LOCK=y
+CONFIG_HIF_PCI=y
+CONFIG_HIF_REG_WINDOW_SUPPORT=y
+CONFIG_HOST_OPCLASS=y
+CONFIG_HTT_PADDR64=y
+CONFIG_IPA_OFFLOAD=y
+CONFIG_IPA_OPT_WIFI_DP=y
+CONFIG_IPA_SET_RESET_TX_DB_PA=y
+CONFIG_KIWI_HEADERS_DEF=y
+CONFIG_LFR_SUBNET_DETECTION=y
+CONFIG_LINUX_QCMBR=y
+CONFIG_LITTLE_ENDIAN=y
+CONFIG_LL_DP_SUPPORT=y
+CONFIG_LTE_COEX=y
+CONFIG_MARK_ICMP_REQ_TO_FW=y
+CONFIG_MAX_ALLOC_PAGE_SIZE=y
+CONFIG_MCC_TO_SCC_SWITCH=y
+CONFIG_MON_ENABLE_DROP_FOR_MAC=y
+CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y
+CONFIG_MORE_TX_DESC=y
+CONFIG_MULTI_CLIENT_LL_SUPPORT=y
+CONFIG_NO_RX_PKT_HDR_TLV=y
+CONFIG_OBSS_PD=y
+CONFIG_OFDM_SCRAMBLER_SEED=y
+CONFIG_PCI_LINK_STATUS_SANITY=y
+CONFIG_PCIE_GEN_SWITCH=y
+CONFIG_PEER_PROTECTED_ACCESS=y
+CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y
+CONFIG_PLD_PCIE_CNSS_FLAG=y
+CONFIG_PLD_PCIE_INIT_FLAG=y
+CONFIG_POWER_MANAGEMENT_OFFLOAD=y
+CONFIG_PTT_SOCK_SVC_ENABLE=y
+CONFIG_QCA_DFS_BW_PUNCTURE=y
+CONFIG_QCA_GET_TSF_VIA_REG=y
+CONFIG_QCA_MONITOR_PKT_SUPPORT=y
+CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y
+CONFIG_QCA_SUPPORT_TX_THROTTLE=y
+CONFIG_QCA_WIFI_FTM=y
+CONFIG_QCA_WIFI_KIWI=y
+CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y
+CONFIG_QCA_WIFI_QCA8074=y
+CONFIG_QCA_WIFI_QCA8074_VP=y
+CONFIG_QCACLD_FEATURE_APF=y
+CONFIG_QCACLD_FEATURE_FW_STATE=y
+CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y
+CONFIG_QCACLD_FEATURE_GREEN_AP=y
+CONFIG_QCACLD_FEATURE_NAN=y
+CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y
+CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y
+CONFIG_QCACLD_WLAN_LFR3=y
+CONFIG_QCOM_ESE=y
+CONFIG_QCOM_LTE_COEX=y
+CONFIG_QCOM_TDLS=y
+CONFIG_QCOM_VOWIFI_11R=y
+CONFIG_QMI_SUPPORT=y
+CONFIG_REG_CLIENT=y
+CONFIG_REMOVE_PKT_LOG=y
+CONFIG_REO_DESC_DEFER_FREE=y
+CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y
+CONFIG_RX_DESC_SANITY_WAR=y
+CONFIG_RX_FISA=y
+CONFIG_RX_HASH_DEBUG=y
+CONFIG_RX_OL=y
+CONFIG_RXDMA_ERR_PKT_DROP=y
+CONFIG_SAE_SINGLE_PMK=y
+CONFIG_SAP_AVOID_ACS_FREQ_LIST=y
+CONFIG_SAP_DHCP_FW_IND=y
+CONFIG_SAR_SAFETY_FEATURE=y
+CONFIG_SCALE_INCLUDES=y
+CONFIG_SERIALIZE_QUEUE_SETUP=y
+CONFIG_SHADOW_V3=y
+CONFIG_SMMU_S1_UNMAP=y
+CONFIG_SOFTAP_CHANNEL_RANGE=y
+CONFIG_SUPPORT_11AX=y
+CONFIG_SYSTEM_PM_CHECK=y
+CONFIG_TARGET_11D_SCAN=y
+CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y
+CONFIG_THERMAL_STATS_SUPPORT=y
+CONFIG_TRACE_RECORD_FEATURE=y
+CONFIG_TSO_DEBUG_LOG_ENABLE=y
+CONFIG_TX_ADDR_INDEX_SEARCH=y
+CONFIG_TX_MULTI_TCL=y
+CONFIG_TX_MULTIQ_PER_AC=y
+CONFIG_TX_PER_PDEV_DESC_POOL=y
+CONFIG_TX_TID_OVERRIDE=y
+CONFIG_VERBOSE_DEBUG=y
+CONFIG_WAPI_BIG_ENDIAN=y
+CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_WDI_EVENT_ENABLE=y
+CONFIG_WDI3_IPA_OVER_GSI=y
+CONFIG_WIFI_MONITOR_SUPPORT=y
+CONFIG_WIFI_POS_CONVERGED=y
+CONFIG_WIFI_POS_PASN=y
+CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y
+CONFIG_WLAN_BCN_RECV_FEATURE=y
+CONFIG_WLAN_BMISS=y
+CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y
+CONFIG_WLAN_CFR_ENABLE=y
+CONFIG_WLAN_CLD_DEV_PM_QOS=y
+CONFIG_WLAN_CLD_PM_QOS=y
+CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y
+CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y
+CONFIG_WLAN_DEBUG_CRASH_INJECT=y
+CONFIG_WLAN_DEBUG_LINK_VOTE=y
+CONFIG_WLAN_DEBUG_VERSION=y
+CONFIG_WLAN_DEBUGFS=y
+CONFIG_WLAN_DFS_MASTER_ENABLE=y
+CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y
+CONFIG_WLAN_DIAG_VERSION=y
+CONFIG_WLAN_DISABLE_EXPORT_SYMBOL=y
+CONFIG_WLAN_DL_MODES=y
+CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y
+CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y
+CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y
+CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y
+CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y
+CONFIG_WLAN_DYNAMIC_CVM=y
+CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y
+CONFIG_WLAN_ENH_CFR_ENABLE=y
+CONFIG_WLAN_FEATURE_11AX=y
+CONFIG_WLAN_FEATURE_11BE=y
+CONFIG_WLAN_FEATURE_11BE_MLO=y
+CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y
+CONFIG_WLAN_FEATURE_ACTION_OUI=y
+CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y
+CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y
+CONFIG_WLAN_FEATURE_COAP=y
+CONFIG_WLAN_FEATURE_COEX_DBAM=y
+CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y
+CONFIG_WLAN_FEATURE_DISA=y
+CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y
+CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y
+CONFIG_WLAN_FEATURE_DP_RX_THREADS=y
+CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y
+CONFIG_WLAN_FEATURE_ELNA=y
+CONFIG_WLAN_FEATURE_FILS=y
+CONFIG_WLAN_FEATURE_FIPS=y
+CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y
+CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y
+CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y
+CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y
+CONFIG_WLAN_FEATURE_LPSS=y
+CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y
+CONFIG_WLAN_FEATURE_MBSSID=y
+CONFIG_WLAN_FEATURE_MCC_QUOTA=y
+CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y
+CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y
+CONFIG_WLAN_FEATURE_MIB_STATS=y
+CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y
+CONFIG_WLAN_FEATURE_P2P_DEBUG=y
+CONFIG_WLAN_FEATURE_P2P_P2P_STA=y
+CONFIG_WLAN_FEATURE_PACKET_FILTERING=y
+CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y
+CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y
+CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y
+CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y
+CONFIG_WLAN_FEATURE_SAE=y
+CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y
+CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y
+CONFIG_WLAN_FEATURE_SR=y
+CONFIG_WLAN_FEATURE_TWT=y
+CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y
+CONFIG_WLAN_FREQ_LIST=y
+CONFIG_WLAN_FW_OFFLOAD=y
+CONFIG_WLAN_GTX_BW_MASK=y
+CONFIG_WLAN_HANG_EVENT=y
+CONFIG_WLAN_LOG_DEBUG=y
+CONFIG_WLAN_LOG_ENTER=y
+CONFIG_WLAN_LOG_ERROR=y
+CONFIG_WLAN_LOG_EXIT=y
+CONFIG_WLAN_LOG_FATAL=y
+CONFIG_WLAN_LOG_INFO=y
+CONFIG_WLAN_LOG_WARN=y
+CONFIG_WLAN_LOGGING_SOCK_SVC=y
+CONFIG_WLAN_MWS_INFO_DEBUGFS=y
+CONFIG_WLAN_NAPI=y
+CONFIG_WLAN_NS_OFFLOAD=y
+CONFIG_WLAN_NUD_TRACKING=y
+CONFIG_WLAN_OFFLOAD_PACKETS=y
+CONFIG_WLAN_OPEN_P2P_INTERFACE=y
+CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y
+CONFIG_WLAN_PMO_ENABLE=y
+CONFIG_WLAN_POLICY_MGR_ENABLE=y
+CONFIG_WLAN_POWER_DEBUG=y
+CONFIG_WLAN_REASSOC=y
+CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y
+CONFIG_WLAN_SCAN_DISABLE=y
+CONFIG_WLAN_SKIP_BAR_UPDATE=y
+CONFIG_WLAN_SUPPORT_DATA_STALL=y
+CONFIG_WLAN_SYNC_TSF=y
+CONFIG_WLAN_SYNC_TSF_PLUS=y
+CONFIG_WLAN_SYNC_TSF_TIMER=y
+CONFIG_WLAN_SYSFS=y
+CONFIG_WLAN_SYSFS_CHANNEL=y
+CONFIG_WLAN_SYSFS_CONNECT_INFO=y
+CONFIG_WLAN_SYSFS_DCM=y
+CONFIG_WLAN_SYSFS_DFSNOL=y
+CONFIG_WLAN_SYSFS_DP_STATS=y
+CONFIG_WLAN_SYSFS_DP_TRACE=y
+CONFIG_WLAN_SYSFS_EHT_RATE=y
+CONFIG_WLAN_SYSFS_FW_MODE_CFG=y
+CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y
+CONFIG_WLAN_SYSFS_LOG_BUFFER=y
+CONFIG_WLAN_SYSFS_MEM_STATS=y
+CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y
+CONFIG_WLAN_SYSFS_RADAR=y
+CONFIG_WLAN_SYSFS_RANGE_EXT=y
+CONFIG_WLAN_SYSFS_RTS_CTS=y
+CONFIG_WLAN_SYSFS_SCAN_CFG=y
+CONFIG_WLAN_SYSFS_STA_INFO=y
+CONFIG_WLAN_SYSFS_STATS=y
+CONFIG_WLAN_SYSFS_TDLS_PEERS=y
+CONFIG_WLAN_SYSFS_TEMPERATURE=y
+CONFIG_WLAN_SYSFS_TX_STBC=y
+CONFIG_WLAN_SYSFS_WLAN_DBG=y
+CONFIG_WLAN_THERMAL_CFG=y
+CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y
+CONFIG_WLAN_TRACEPOINTS=y
+CONFIG_WLAN_TSF_AUTO_REPORT=y
+CONFIG_WLAN_TSF_UPLINK_DELAY=y
+CONFIG_WLAN_TWT_CONVERGED=y
+CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y
+CONFIG_WLAN_TWT_SAP_STA_COUNT=y
+CONFIG_WLAN_TX_FLOW_CONTROL_V2=y
+CONFIG_WLAN_TXRX_FW_ST_RST=y
+CONFIG_WLAN_TXRX_FW_STATS=y
+CONFIG_WLAN_TXRX_STATS=y
+CONFIG_WLAN_UMAC_MLO_MAX_DEV=3
+CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y
+CONFIG_WLAN_WBUFF=y
+CONFIG_WLAN_WOW_ITO=y
+CONFIG_WLAN_WOWL_ADD_PTRN=y
+CONFIG_WLAN_WOWL_DEL_PTRN=y
+CONFIG_WMI_BCN_OFFLOAD=y
+CONFIG_WMI_CMD_STRINGS=y
+CONFIG_WMI_CONCURRENCY_SUPPORT=y
+CONFIG_WMI_DBR_SUPPORT=y
+CONFIG_WMI_INTERFACE_EVENT_LOGGING=y
+CONFIG_WMI_ROAM_SUPPORT=y
+CONFIG_WMI_SEND_RECV_QMI=y
+CONFIG_WMI_STA_SUPPORT=y
+CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y
+CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y
+CONFIG_WLAN_CTRL_NAME="wlan"
+CONFIG_MULTI_IF_NAME="peach"
+CONFIG_NL80211_TESTMODE=y
+CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y
+CONFIG_WLAN_HOST_ARCH_ARM=y
+CONFIG_ARCH_MSM=y
+CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y
+CONFIG_NUM_SOC_PERF_CLUSTER=2
+CONFIG_WLAN_OPEN_SOURCE=y
+CONFIG_QCA_WIFI_FTM_NL80211=y
+CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y
+CONFIG_DP_MULTIPASS_SUPPORT=y
+CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y
+CONFIG_WLAN_FEATURE_AFFINITY_MGR=y
+CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y
+CONFIG_DP_MLO_LINK_STATS_SUPPORT=y
+CONFIG_HIF_DEBUG=y
+CONFIG_WLAN_OBJMGR_DEBUG=y
+CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y
+CONFIG_WLAN_WARN_ON_ASSERT=y
+CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y
+CONFIG_PANIC_ON_BUG=y
+CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_SMP=y
+CONFIG_RPS=y

+ 0 - 13
core/hdd/inc/wlan_hdd_cfg.h

@@ -268,19 +268,6 @@ void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx);
 QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
 			  uint8_t tx_nss, uint8_t rx_nss);
 
-/**
- * hdd_get_num_chains() - Get the number of chains supported by the adapter
- *
- * @adapter: the pointer to adapter
- * @num_chains: the number of chains supported by the adapter
- *
- * This function is used to get the number of chains supported by
- * the adapter.
- *
- * Return: QDF_STATUS
- */
-QDF_STATUS hdd_get_num_chains(struct hdd_adapter *adapter, uint8_t *num_chains);
-
 /**
  * hdd_get_nss() - Get the number of spatial streams supported by the adapter
  *

+ 72 - 0
core/hdd/inc/wlan_hdd_ll_lt_sap.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: contains ll_lt_sap_declarations specific to the ll_lt_sap module
+ */
+
+#ifndef __WLAN_HDD_LL_LT_SAP_H
+#define __WLAN_HDD_LL_LT_SAP_H
+
+#include "wlan_hdd_main.h"
+#include "qca_vendor.h"
+
+extern const struct nla_policy
+	wlan_hdd_ll_lt_sap_transport_switch_policy
+	[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1];
+
+#define FEATURE_LL_LT_SAP_VENDOR_COMMANDS				      \
+{									      \
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,			      \
+	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH,      \
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |				      \
+			WIPHY_VENDOR_CMD_NEED_NETDEV |			      \
+			WIPHY_VENDOR_CMD_NEED_RUNNING,			      \
+	.doit = wlan_hdd_cfg80211_ll_lt_sap_transport_switch,		      \
+	vendor_command_policy(wlan_hdd_ll_lt_sap_transport_switch_policy,     \
+			      QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX)\
+},
+
+/**
+ * wlan_hdd_cfg80211_ll_lt_sap_transport_switch() - Request to switch the
+ * transport
+ * @wiphy:   pointer to wireless wiphy structure.
+ * @wdev:    pointer to wireless_dev structure.
+ * @data:    Pointer to the data to be passed via vendor interface
+ * @data_len:Length of the data to be passed
+ *
+ * Return:   Return the Success or Failure code.
+ */
+int wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,
+						 struct wireless_dev *wdev,
+						 const void *data,
+						 int data_len);
+
+/**
+ * wlan_hdd_send_audio_transport_switch_req_event() - Audio transport switch
+ * event
+ * @adapter:              pointer to adapter structure.
+ * @audio_switch_mode:    audio switch mode.
+ *
+ * Return:   Return the Success or Failure code.
+ */
+int wlan_hdd_send_audio_transport_switch_req_event(struct hdd_adapter *adapter,
+						   uint8_t audio_switch_mode);
+
+
+#endif /* __WLAN_HDD_LL_LT_SAP_H */

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

@@ -587,6 +587,7 @@ struct hdd_peer_stats {
 	uint32_t fcs_count;
 };
 
+#define HDD_MAX_PER_PEER_RATES 16
 #if defined(WLAN_FEATURE_11BE_MLO)
 /**
  * struct wlan_hdd_station_stats_info - Station stats info
@@ -631,6 +632,30 @@ struct wlan_hdd_mlo_iface_stats_info {
 	uint32_t freq;
 	uint32_t radio_id;
 };
+
+/**
+ * struct wlan_hdd_peer_info - hdd per peer info
+ * @type: peer type (AP, TDLS, GO etc.)
+ * @peer_mac: peer mac address
+ * @capabilities: peer WIFI_CAPABILITY_XXX
+ * @power_saving: peer power saving mode
+ * @num_rate: number of rates
+ * @rate_stats: per rate statistics, num entries = HDD_MAX_PER_PEER_RATES
+ * @stats_cached: whether peer stats cached into link_info struct
+ * @link_id: IEEE link id for the link
+ */
+struct wlan_hdd_peer_info {
+	enum wmi_peer_type type;
+	struct qdf_mac_addr peer_mac;
+	uint32_t capabilities;
+	union {
+		uint32_t power_saving;
+		uint32_t num_rate;
+	};
+	struct wifi_rate_stat rate_stats[HDD_MAX_PER_PEER_RATES];
+	bool stats_cached;
+	uint32_t link_id;
+};
 #endif
 
 #define MAX_SUBTYPES_TRACKED	4
@@ -1079,6 +1104,7 @@ enum udp_qos_upgrade {
  * @big_data_stats: Big data stats
  * @ll_iface_stats: Link Layer interface stats
  * @hdd_sinfo: hdd vdev station stats that will be sent to userspace
+ * @mlo_peer_info: mlo peer stats info
  * @mscs_prev_tx_vo_pkts: count of prev VO AC packets transmitted
  * @mscs_counter: Counter on MSCS action frames sent
  * @link_flags: a bitmap of hdd_link_flags
@@ -1113,6 +1139,7 @@ struct wlan_hdd_link_info {
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 	struct wifi_interface_stats ll_iface_stats;
 	struct wlan_hdd_station_stats_info hdd_sinfo;
+	struct wlan_hdd_peer_info mlo_peer_info;
 #endif
 
 #ifdef WLAN_FEATURE_MSCS
@@ -5218,6 +5245,14 @@ hdd_nl80211_chwidth_to_chwidth(uint8_t nl80211_chwidth);
  */
 uint8_t hdd_chwidth_to_nl80211_chwidth(enum eSirMacHTChannelWidth chwidth);
 
+/**
+ * hdd_phy_chwidth_to_nl80211_chwidth() - Get nl chan width from phy chan width
+ * @chwidth: enum phy_ch_width
+ *
+ * Return: enum nl80211_chan_width or 0xFF for unsupported phy chan width
+ */
+uint8_t hdd_phy_chwidth_to_nl80211_chwidth(enum phy_ch_width chwidth);
+
 /**
  * wlan_hdd_get_channel_bw() - get channel bandwidth
  * @width: input channel width in nl80211_chan_width value

+ 49 - 3
core/hdd/inc/wlan_hdd_tsf.h

@@ -72,6 +72,51 @@ struct hdd_tsf_op_response {
 	uint64_t soc_time;
 };
 
+/**
+ * enum hdd_tsf_auto_rpt_source - trigger source of tsf auto report
+ * @HDD_TSF_AUTO_RPT_SOURCE_UPLINK_DELAY: uplink delay feature
+ * @HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY: transmit latency statistics
+ */
+enum hdd_tsf_auto_rpt_source {
+	HDD_TSF_AUTO_RPT_SOURCE_UPLINK_DELAY,
+	HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY,
+};
+
+#ifdef WLAN_FEATURE_TSF_AUTO_REPORT
+/**
+ * hdd_set_tsf_auto_report() - enable or disable tsf auto report
+ * for an adapter
+ * @adapter: pointer to Adapter context
+ * @ena: requesting state (true or false)
+ * @source: source of the request
+ *
+ * Return: 0 for success or non-zero negative failure code
+ */
+int
+hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena,
+			enum hdd_tsf_auto_rpt_source source);
+
+/**
+ * hdd_tsf_auto_report_init() - initialize tsf auto report related
+ * structures for an adapter
+ * @adapter: pointer to Adapter context
+ *
+ * Return: None
+ */
+void hdd_tsf_auto_report_init(struct hdd_adapter *adapter);
+#else
+static inline int
+hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena,
+			enum hdd_tsf_auto_rpt_source source)
+{
+	return -ENOTSUPP;
+}
+
+static inline void hdd_tsf_auto_report_init(struct hdd_adapter *adapter)
+{
+}
+#endif
+
 /**
  * struct hdd_vdev_tsf - Adapter level tsf params
  * @cur_target_time: tsf value received from firmware.
@@ -97,7 +142,7 @@ struct hdd_tsf_op_response {
  * @continuous_cap_retry_count: to store the count of continuous capture retry.
  * @tsf_sync_ready_flag: to indicate whether tsf_sync has been initialized.
  * @gpio_tsf_sync_work: work to sync send TSF CAP WMI command.
- * @tsf_auto_report: to indicate if TSF auto report is enabled or not.
+ * @auto_rpt_src: bitmap to record trigger sources of TSF auto report
  */
 struct hdd_vdev_tsf {
 	uint64_t cur_target_time;
@@ -130,8 +175,9 @@ struct hdd_vdev_tsf {
 	qdf_work_t gpio_tsf_sync_work;
 #endif
 #endif /* WLAN_FEATURE_TSF_PLUS */
-#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
-qdf_atomic_t tsf_auto_report;
+#ifdef WLAN_FEATURE_TSF_AUTO_REPORT
+	unsigned long auto_rpt_src;
+
 #endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */
 };
 

+ 153 - 125
core/hdd/src/wlan_hdd_cfg.c

@@ -1121,8 +1121,14 @@ static QDF_STATUS hdd_set_nss_params(struct wlan_hdd_link_info *link_info,
 		return QDF_STATUS_E_INVAL;
 	}
 
-	if (tx_nss > wlan_vdev_mlme_get_nss(vdev) ||
-	    rx_nss > wlan_vdev_mlme_get_nss(vdev)) {
+	/* For STA tx/rx nss value is updated at the time of connection,
+	 * for SAP case nss values will not get update, so can skip check
+	 * for SAP/P2P_GO mode.
+	 */
+	if (adapter->device_mode != QDF_SAP_MODE &&
+	    adapter->device_mode != QDF_P2P_GO_MODE &&
+	    (tx_nss > wlan_vdev_mlme_get_nss(vdev) ||
+	    rx_nss > wlan_vdev_mlme_get_nss(vdev))) {
 		hdd_err("Given tx nss/rx nss is greater than intersected nss = %d",
 			wlan_vdev_mlme_get_nss(vdev));
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
@@ -1185,6 +1191,148 @@ static void hdd_set_sap_nss_params(struct wlan_hdd_link_info *link_info,
 	hdd_restart_sap(link_info);
 }
 
+/**
+ * hdd_get_sap_rx_nss() - get the sap rx nss
+ * @link_info: Pointer to link_info
+ * @rx_nss: pointer to rx_nss
+ *
+ * get the sap tx nss
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sap_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	mac_handle_t mac_handle;
+	uint8_t vdev_nss;
+
+	mac_handle = hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_debug("NULL MAC handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
+	if (operating_band == BAND_UNKNOWN)
+		return QDF_STATUS_E_INVAL;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band);
+	if (hdd_ctx->dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+			hdd_debug("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+		switch (operating_band) {
+		case BAND_2G:
+			*rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			hdd_debug("Band %d Not 2G or 5G", operating_band);
+			break;
+		}
+	} else {
+		*rx_nss = vdev_nss;
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return  QDF_STATUS_SUCCESS;
+}
+
+/**
+ * hdd_get_sap_tx_nss() - get the sap tx nss
+ * @link_info: Pointer of link_info
+ * @tx_nss: pointer to tx_nss
+ *
+ * get the sap tx nss
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sap_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	mac_handle_t mac_handle;
+	uint8_t vdev_nss;
+
+	mac_handle = hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_debug("NULL MAC handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
+	if (operating_band == BAND_UNKNOWN)
+		return QDF_STATUS_E_INVAL;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band);
+	if (hdd_ctx->dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+			hdd_debug("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+		switch (operating_band) {
+		case BAND_2G:
+			*tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			hdd_debug("Band %d Not 2G or 5G", operating_band);
+			break;
+		}
+	} else {
+		*tx_nss = vdev_nss;
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return  QDF_STATUS_SUCCESS;
+}
+
+static bool
+hdd_get_sap_restart_required_for_nss(struct wlan_hdd_link_info *link_info,
+				     uint8_t tx_nss, uint8_t rx_nss)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	uint8_t rx_prev, tx_prev;
+	bool restart_sap = 0;
+
+	ucfg_mlme_get_restart_sap_on_dynamic_nss_chains_cfg(hdd_ctx->psoc,
+							    &restart_sap);
+
+	if (!restart_sap)
+		return false;
+
+	hdd_get_sap_rx_nss(link_info, &rx_prev);
+	hdd_get_sap_tx_nss(link_info, &tx_prev);
+
+	if (rx_prev != rx_nss && tx_prev != tx_nss)
+		return true;
+	return false;
+}
+
 QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
 			  uint8_t tx_nss, uint8_t rx_nss)
 {
@@ -1230,9 +1378,9 @@ QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
 	 * and not the global param enable2x2
 	 */
 	if (hdd_ctx->dynamic_nss_chains_support) {
-		ucfg_mlme_get_restart_sap_on_dynamic_nss_chains_cfg(
-								hdd_ctx->psoc,
-								&restart_sap);
+		restart_sap =
+		hdd_get_sap_restart_required_for_nss(link_info, tx_nss, rx_nss);
+
 		if ((adapter->device_mode == QDF_SAP_MODE ||
 		     adapter->device_mode == QDF_P2P_GO_MODE) && restart_sap) {
 			if ((tx_nss == 2 && rx_nss == 2) ||
@@ -1476,66 +1624,6 @@ hdd_get_sap_num_tx_chains(struct wlan_hdd_link_info *link_info,
 	return  QDF_STATUS_SUCCESS;
 }
 
-/**
- * hdd_get_sap_tx_nss() - get the sap tx nss
- * @link_info: Pointer of link_info
- * @tx_nss: pointer to tx_nss
- *
- * get the sap tx nss
- *
- * Return: None
- */
-static QDF_STATUS
-hdd_get_sap_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
-{
-	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
-	struct wlan_objmgr_vdev *vdev;
-	struct wlan_mlme_nss_chains *dynamic_cfg;
-	enum band_info operating_band;
-	mac_handle_t mac_handle;
-	uint8_t vdev_nss;
-
-	mac_handle = hdd_ctx->mac_handle;
-	if (!mac_handle) {
-		hdd_debug("NULL MAC handle");
-		return QDF_STATUS_E_INVAL;
-	}
-
-	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
-	if (operating_band == BAND_UNKNOWN)
-		return QDF_STATUS_E_INVAL;
-
-	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
-	if (!vdev)
-		return QDF_STATUS_E_INVAL;
-
-	sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band);
-	if (hdd_ctx->dynamic_nss_chains_support) {
-		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
-		if (!dynamic_cfg) {
-			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
-			hdd_debug("nss chain dynamic config NULL");
-			return QDF_STATUS_E_INVAL;
-		}
-		switch (operating_band) {
-		case BAND_2G:
-			*tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
-			break;
-		case BAND_5G:
-			*tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
-			break;
-		default:
-			hdd_debug("Band %d Not 2G or 5G", operating_band);
-			break;
-		}
-	} else {
-		*tx_nss = vdev_nss;
-	}
-
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
-	return  QDF_STATUS_SUCCESS;
-}
-
 /**
  * hdd_get_sta_num_tx_chains() - get the sta num tx chains
  * @link_info: Pointer of link_info
@@ -1684,66 +1772,6 @@ hdd_get_sap_num_rx_chains(struct wlan_hdd_link_info *link_info,
 	return  QDF_STATUS_SUCCESS;
 }
 
-/**
- * hdd_get_sap_rx_nss() - get the sap rx nss
- * @link_info: Pointer to link_info
- * @rx_nss: pointer to rx_nss
- *
- * get the sap tx nss
- *
- * Return: None
- */
-static QDF_STATUS
-hdd_get_sap_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
-{
-	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
-	struct wlan_objmgr_vdev *vdev;
-	struct wlan_mlme_nss_chains *dynamic_cfg;
-	enum band_info operating_band;
-	mac_handle_t mac_handle;
-	uint8_t vdev_nss;
-
-	mac_handle = hdd_ctx->mac_handle;
-	if (!mac_handle) {
-		hdd_debug("NULL MAC handle");
-		return QDF_STATUS_E_INVAL;
-	}
-
-	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
-	if (operating_band == BAND_UNKNOWN)
-		return QDF_STATUS_E_INVAL;
-
-	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
-	if (!vdev)
-		return QDF_STATUS_E_INVAL;
-
-	sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band);
-	if (hdd_ctx->dynamic_nss_chains_support) {
-		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
-		if (!dynamic_cfg) {
-			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
-			hdd_debug("nss chain dynamic config NULL");
-			return QDF_STATUS_E_INVAL;
-		}
-		switch (operating_band) {
-		case BAND_2G:
-			*rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
-			break;
-		case BAND_5G:
-			*rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
-			break;
-		default:
-			hdd_debug("Band %d Not 2G or 5G", operating_band);
-			break;
-		}
-	} else {
-		*rx_nss = vdev_nss;
-	}
-
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
-	return  QDF_STATUS_SUCCESS;
-}
-
 /**
  * hdd_get_sta_num_rx_chains() - get the sta num rx chains
  * @link_info: Pointer to link_info in adapter

+ 62 - 61
core/hdd/src/wlan_hdd_cfg80211.c

@@ -210,6 +210,7 @@
 #include "wlan_mlo_epcs_ucfg_api.h"
 #include <wlan_ll_sap_ucfg_api.h>
 #include <wlan_mlo_mgr_link_switch.h>
+#include <wlan_hdd_ll_lt_sap.h>
 /*
  * A value of 100 (milliseconds) can be sent to FW.
  * FW would enable Tx beamforming based on this.
@@ -2129,6 +2130,12 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
 	},
 #endif
 	FEATURE_AFC_VENDOR_EVENTS
+
+	[QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH_INDEX] = {
+		.vendor_id = QCA_NL80211_VENDOR_ID,
+		.subcmd = QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH,
+	},
+
 };
 
 /**
@@ -9147,16 +9154,9 @@ static int hdd_config_mpdu_aggregation(struct wlan_hdd_link_info *link_info,
 		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION];
 	struct nlattr *rx_attr =
 		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION];
-	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
-	mac_handle_t mac_handle = hdd_ctx->mac_handle;
 	uint8_t tx_size, rx_size;
 	QDF_STATUS status;
 
-	if (!mac_handle) {
-		hdd_err("NULL Mac handle");
-		return -EINVAL;
-	}
-
 	/* nothing to do if neither attribute is present */
 	if (!tx_attr && !rx_attr)
 		return 0;
@@ -9178,20 +9178,6 @@ static int hdd_config_mpdu_aggregation(struct wlan_hdd_link_info *link_info,
 		return -EINVAL;
 	}
 
-	if (tx_size > 1)
-		sme_set_amsdu(mac_handle, true);
-	else
-		sme_set_amsdu(mac_handle, false);
-
-	hdd_debug("tx size: %d", tx_size);
-	status = wma_cli_set_command(link_info->vdev_id,
-				     GEN_VDEV_PARAM_AMSDU,
-				     tx_size, GEN_CMD);
-	if (status) {
-		hdd_err("Failed to set AMSDU param to FW, status %d", status);
-		return qdf_status_to_os_return(status);
-	}
-
 	status = wma_set_tx_rx_aggr_size(link_info->vdev_id,
 					 tx_size, rx_size,
 					 WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU);
@@ -9207,8 +9193,15 @@ static int hdd_config_msdu_aggregation(struct wlan_hdd_link_info *link_info,
 	struct nlattr *rx_attr =
 		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION];
 	uint8_t tx_size, rx_size;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	mac_handle_t mac_handle = hdd_ctx->mac_handle;
 	QDF_STATUS status;
 
+	if (!mac_handle) {
+		hdd_err("NULL Mac handle");
+		return -EINVAL;
+	}
+
 	/* nothing to do if neither attribute is present */
 	if (!tx_attr && !rx_attr)
 		return 0;
@@ -9230,10 +9223,19 @@ static int hdd_config_msdu_aggregation(struct wlan_hdd_link_info *link_info,
 		return -EINVAL;
 	}
 
-	status = wma_set_tx_rx_aggr_size(link_info->vdev_id,
-					 tx_size,
-					 rx_size,
-					 WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU);
+	if (tx_size > 1)
+		sme_set_amsdu(mac_handle, true);
+	else
+		sme_set_amsdu(mac_handle, false);
+
+	hdd_debug("tx size: %d", tx_size);
+	status = wma_cli_set_command(link_info->vdev_id,
+				     GEN_VDEV_PARAM_AMSDU,
+				     tx_size, GEN_CMD);
+	if (status) {
+		hdd_err("Failed to set AMSDU param to FW, status %d", status);
+		return qdf_status_to_os_return(status);
+	}
 
 	return qdf_status_to_os_return(status);
 }
@@ -9350,6 +9352,7 @@ static int hdd_config_vdev_chains(struct wlan_hdd_link_info *link_info,
 	tx_chains = nla_get_u8(tx_attr);
 	rx_chains = nla_get_u8(rx_attr);
 
+	hdd_debug("tx_chains %d rx_chains %d", tx_chains, rx_chains);
 	if (hdd_ctx->dynamic_nss_chains_support)
 		return hdd_set_dynamic_antenna_mode(link_info,
 						    rx_chains, tx_chains);
@@ -10907,6 +10910,7 @@ static int hdd_set_channel_width(struct wlan_hdd_link_info *link_info,
 	struct nlattr *curr_attr;
 	struct nlattr *chn_bd = NULL;
 	struct nlattr *mlo_link_id;
+	enum eSirMacHTChannelWidth chwidth;
 
 	if (!tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS])
 		goto skip_mlo;
@@ -10952,15 +10956,17 @@ skip_mlo:
 
 	nl80211_chwidth = nla_get_u8(chn_bd);
 
-	if (nl80211_chwidth < eHT_CHANNEL_WIDTH_20MHZ ||
-	    nl80211_chwidth > eHT_MAX_CHANNEL_WIDTH) {
-		hdd_err("Invalid channel width");
+set_chan_width:
+	chwidth = hdd_nl80211_chwidth_to_chwidth(nl80211_chwidth);
+
+	if (chwidth < eHT_CHANNEL_WIDTH_20MHZ ||
+	    chwidth > eHT_MAX_CHANNEL_WIDTH) {
+		hdd_err("Invalid channel width %u", chwidth);
 		return -EINVAL;
 	}
 
-set_chan_width:
 	return hdd_set_mac_chan_width(link_info->adapter,
-				      nl80211_chwidth, link_id);
+				      chwidth, link_id);
 }
 
 /**
@@ -12216,23 +12222,29 @@ static int hdd_get_rx_amsdu(struct wlan_hdd_link_info *link_info,
 static int hdd_get_channel_width(struct wlan_hdd_link_info *link_info,
 				 struct sk_buff *skb, const struct nlattr *attr)
 {
-	enum eSirMacHTChannelWidth chwidth;
 	uint8_t nl80211_chwidth;
+	struct wlan_channel *bss_chan;
+	struct wlan_objmgr_vdev *vdev;
 
-	chwidth = wma_cli_get_command(link_info->vdev_id,
-				      wmi_vdev_param_chwidth, VDEV_CMD);
-	if (chwidth < 0) {
-		hdd_err("Failed to get chwidth");
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	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);
+		hdd_err("get bss_chan failed");
+		return QDF_STATUS_E_FAILURE;
 	}
 
-	nl80211_chwidth = hdd_chwidth_to_nl80211_chwidth(chwidth);
-	if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH,
-		       nl80211_chwidth)) {
-		hdd_err("nla_put failure");
+	nl80211_chwidth = hdd_phy_chwidth_to_nl80211_chwidth(bss_chan->ch_width);
+	if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH, nl80211_chwidth)) {
+		hdd_err("nla_put chn width failure");
 		return -EINVAL;
 	}
 
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
 	return 0;
 }
 
@@ -12255,6 +12267,7 @@ static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
 	uint32_t link_id = 0;
 	struct wlan_objmgr_vdev *vdev, *link_vdev;
 	struct wlan_channel *bss_chan;
+	uint8_t nl80211_chwidth;
 
 	chwidth = wma_cli_get_command(link_info->vdev_id,
 				      wmi_vdev_param_chwidth, VDEV_CMD);
@@ -12267,14 +12280,7 @@ static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
 	if (!vdev)
 		return -EINVAL;
 
-	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
-		bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
-
-		if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH,
-			       (uint8_t)bss_chan->ch_width)) {
-			hdd_err("nla_put chn width failure");
-		}
-	} else {
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
 		mlo_bd_info = nla_nest_start(skb, CONFIG_MLO_LINKS);
 		for (link_id = 0; link_id < WLAN_MAX_LINK_ID; link_id++) {
 			link_vdev = mlo_get_vdev_by_link_id(vdev, link_id);
@@ -12302,8 +12308,9 @@ static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info,
 				return -EINVAL;
 			}
 
+			nl80211_chwidth = hdd_phy_chwidth_to_nl80211_chwidth(bss_chan->ch_width);
 			if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH,
-				       (uint8_t)bss_chan->ch_width)) {
+				       nl80211_chwidth)) {
 				hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
 				mlo_release_vdev_ref(link_vdev);
 				hdd_err("nla_put failure");
@@ -13237,10 +13244,8 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 		op_mode = wlan_get_opmode_from_vdev_id(
 						hdd_ctx->pdev,
 						link_info->vdev_id);
-		if (op_mode == QDF_STA_MODE)
-			sme_set_ba_opmode(mac_handle,
-					  link_info->vdev_id,
-					  set_val);
+
+		sme_set_per_link_ba_mode(mac_handle, set_val);
 
 		if (!cfg_val) {
 			ret_val = wma_cli_set_command(
@@ -13322,14 +13327,8 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 			/* Configure ADDBA req buffer size to 64 */
 			set_val = HDD_BA_MODE_64;
 
-		sme_set_ba_opmode(mac_handle, link_info->vdev_id,
-				  set_val);
+		sme_set_per_link_ba_mode(mac_handle, set_val);
 
-		ret_val = wma_cli_set_command(link_info->vdev_id,
-					      wmi_vdev_param_set_ba_mode,
-					      set_val, VDEV_CMD);
-		if (ret_val)
-			hdd_err("Failed to set BA operating mode %d", set_val);
 		ret_val = wma_cli_set_command(link_info->vdev_id,
 					      GEN_VDEV_PARAM_AMPDU,
 					      buff_size, GEN_CMD);
@@ -20452,6 +20451,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	FEATURE_COAP_OFFLOAD_COMMANDS
 	FEATURE_ML_LINK_STATE_COMMANDS
 	FEATURE_AFC_VENDOR_COMMANDS
+	FEATURE_LL_LT_SAP_VENDOR_COMMANDS
 };
 
 struct hdd_context *hdd_cfg80211_wiphy_alloc(void)
@@ -23485,7 +23485,8 @@ static int wlan_add_key_standby_link(struct hdd_adapter *adapter,
 
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 
-	mlo_link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id);
+	mlo_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx,
+						       link_id);
 	if (!mlo_link_info)
 		return QDF_STATUS_E_FAILURE;
 
@@ -27954,7 +27955,7 @@ static int __wlan_hdd_cfg80211_get_channel(struct wiphy *wiphy,
 	uint8_t vdev_id;
 	enum phy_ch_width ch_width;
 	enum wlan_phymode peer_phymode;
-	struct hdd_station_ctx *sta_ctx;
+	struct hdd_station_ctx *sta_ctx = NULL;
 	struct ch_params ch_params = {0};
 
 	hdd_enter_dev(wdev->netdev);

+ 12 - 4
core/hdd/src/wlan_hdd_cm_connect.c

@@ -1000,10 +1000,18 @@ hdd_cm_connect_failure_post_user_update(struct wlan_objmgr_vdev *vdev,
 	hdd_clear_roam_profile_ie(adapter);
 	ucfg_cm_reset_key(hdd_ctx->pdev, link_info->vdev_id);
 	hdd_wmm_dscp_initial_state(adapter);
-	hdd_debug("Disabling queues");
-	wlan_hdd_netif_queue_control(adapter,
-				     WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
-				     WLAN_CONTROL_PATH);
+
+	/*
+	 * If connect failure is due to link switch, do not disable the
+	 * netdev queues as it will lead to data stall/NUD failure.
+	 */
+	if (!(rsp->cm_id & CM_ID_LSWITCH_BIT)) {
+		hdd_debug("Disabling queues");
+		wlan_hdd_netif_queue_control(adapter,
+					     WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
+					     WLAN_CONTROL_PATH);
+	}
+
 	ucfg_dp_periodic_sta_stats_start(vdev);
 	wlan_twt_concurrency_update(hdd_ctx);
 }

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

@@ -581,6 +581,8 @@ hdd_cm_disconnect_complete_post_user_update(struct wlan_objmgr_vdev *vdev,
 	__hdd_cm_disconnect_handler_post_user_update(link_info, vdev);
 	wlan_twt_concurrency_update(hdd_ctx);
 	hdd_cm_reset_udp_qos_upgrade_config(adapter);
+	ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc,
+					   vdev->vdev_objmgr.vdev_id, 0);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 2 - 2
core/hdd/src/wlan_hdd_green_ap.c

@@ -257,7 +257,7 @@ __wlan_hdd_enter_sap_low_pwr_mode(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
-	hdd_debug("Cookie id received : %u", cookie_id);
+	hdd_debug("Cookie id received : %llu", cookie_id);
 
 	len = NLMSG_HDRLEN;
 	/*QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE*/
@@ -361,7 +361,7 @@ QDF_STATUS wlan_hdd_send_green_ap_ll_ps_event(
 		goto nla_put_failure;
 	}
 
-	hdd_debug("next_tsf : %llu, cookie: %llu beacon multiplier: %u",
+	hdd_debug("next_tsf : %llu, cookie: %u beacon multiplier: %u",
 		  ll_ps_param->next_tsf, ll_ps_param->dialog_token,
 		  ll_ps_param->bcn_mult);
 

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

@@ -1068,9 +1068,17 @@ QDF_STATUS hdd_chan_change_notify(struct wlan_hdd_link_info *link_info,
 		dev = assoc_adapter->dev;
 	}
 
+	if (adapter->device_mode == QDF_STA_MODE ||
+	    adapter->device_mode == QDF_P2P_CLIENT_MODE)
+		mutex_lock(&dev->ieee80211_ptr->mtx);
+
 	wlan_cfg80211_ch_switch_notify(dev, &chandef, link_id,
 				       puncture_bitmap);
 
+	if (adapter->device_mode == QDF_STA_MODE ||
+	    adapter->device_mode == QDF_P2P_CLIENT_MODE)
+		mutex_unlock(&dev->ieee80211_ptr->mtx);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -4369,6 +4377,7 @@ QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter,
 	/* rcpi info initialization */
 	qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi));
 
+	hdd_tsf_auto_report_init(adapter);
 	hdd_exit();
 
 	return status;
@@ -7316,8 +7325,7 @@ static uint16_t hdd_get_data_rate_from_rate_mask(struct wiphy *wiphy,
 		sband_bitrates = sband->bitrates;
 		sband_n_bitrates = sband->n_bitrates;
 		for (i = 0; i < sband_n_bitrates; i++) {
-			if (bit_rate_mask->control[band].legacy ==
-			    sband_bitrates[i].hw_value)
+			if (bit_rate_mask->control[band].legacy == (1 << i))
 				return sband_bitrates[i].bitrate;
 		}
 	}

+ 179 - 0
core/hdd/src/wlan_hdd_ll_lt_sap.c

@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: contains ll_lt_sap_definitions specific to the ll_lt_sap module
+ */
+
+#include "wlan_hdd_ll_lt_sap.h"
+#include "wlan_ll_sap_ucfg_api.h"
+#include "osif_sync.h"
+#include "wlan_hdd_cfg80211.h"
+
+const struct nla_policy
+	wlan_hdd_ll_lt_sap_transport_switch_policy
+	[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1] = {
+		[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE] = {
+						.type = NLA_U8},
+		[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS] = {
+						.type = NLA_U8},
+};
+
+/**
+ * __wlan_hdd_cfg80211_ll_lt_sap_transport_switch() - Request to switch the
+ * transport
+ * @wiphy:   pointer to wireless wiphy structure.
+ * @wdev:    pointer to wireless_dev structure.
+ * @data:    Pointer to the data to be passed via vendor interface
+ * @data_len:Length of the data to be passed
+ *
+ * Return:   Return the Success or Failure code.
+ */
+static int
+__wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,
+					       struct wireless_dev *wdev,
+					       const void *data,
+					       int data_len)
+{
+	struct net_device *dev = wdev->netdev;
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1];
+	uint8_t transport_switch_type;
+	uint8_t transport_switch_status;
+	QDF_STATUS status;
+
+	hdd_enter_dev(dev);
+
+	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
+		hdd_err("Command not allowed in FTM mode");
+		return -EPERM;
+	}
+
+	if (0 != wlan_hdd_validate_context(hdd_ctx))
+		return -EINVAL;
+
+	if (!adapter)
+		return -EINVAL;
+
+	if (wlan_cfg80211_nla_parse(
+			tb, QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX,
+			data, data_len,
+			wlan_hdd_ll_lt_sap_transport_switch_policy)) {
+		hdd_err("Invalid attribute");
+		return -EINVAL;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]) {
+		hdd_err("attr transport switch type failed");
+		return -EINVAL;
+	}
+	transport_switch_type = nla_get_u8(
+			tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]) {
+		status = ucfg_ll_lt_sap_request_for_audio_transport_switch(
+							transport_switch_type);
+		hdd_debug("Transport switch request type %d status %d",
+			  transport_switch_type, status);
+		return qdf_status_to_os_return(status);
+	}
+
+	transport_switch_status = nla_get_u8(
+			tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]);
+
+	if (transport_switch_status ==
+		QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED) {
+		hdd_debug("Transport switch request completed");
+		return 0;
+	} else if (transport_switch_status ==
+		QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED) {
+		hdd_debug("Transport switch request rejected");
+		return 0;
+	}
+
+	hdd_err("Invalid transport switch status");
+	return -EINVAL;
+}
+
+int wlan_hdd_send_audio_transport_switch_req_event(struct hdd_adapter *adapter,
+						   uint8_t audio_switch_mode)
+{
+	struct sk_buff *vendor_event;
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	uint32_t len;
+
+	hdd_enter();
+
+	if (wlan_hdd_validate_context(hdd_ctx)) {
+		hdd_err("Invalid context");
+		return -EINVAL;
+	}
+	if (hdd_validate_adapter(adapter)) {
+		hdd_err("Invalid adapter");
+		return -EINVAL;
+	}
+
+	len = nla_total_size(sizeof(uint8_t)) + NLMSG_HDRLEN;
+
+	vendor_event = wlan_cfg80211_vendor_event_alloc(
+			hdd_ctx->wiphy,
+			&adapter->wdev,
+			len,
+			QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH_INDEX,
+			GFP_KERNEL);
+
+	if (!vendor_event) {
+		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
+		return -ENOMEM;
+	}
+
+	if (nla_put_u8(vendor_event,
+		       QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE,
+		       audio_switch_mode)) {
+		hdd_err("VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE put fail");
+		wlan_cfg80211_vendor_free_skb(vendor_event);
+		return -EINVAL;
+	}
+
+	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+
+	hdd_debug("transport switch request sent on %s interface",
+		   netdev_name(adapter->dev));
+	return 0;
+}
+
+int wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,
+						 struct wireless_dev *wdev,
+						 const void *data,
+						 int data_len)
+{
+	int errno;
+	struct osif_vdev_sync *vdev_sync;
+
+	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(wiphy, wdev,
+							       data, data_len);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return errno;
+}

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

@@ -3822,14 +3822,7 @@ int hdd_set_11ax_rate(struct hdd_adapter *adapter, int set_value,
 
 int hdd_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate)
 {
-	int set_value;
-
-	if (sme_is_feature_supported_by_fw(DOT11AX))
-		set_value = WMI_ASSEMBLE_RATECODE_V1(rate, nss, preamble);
-	else
-		set_value = (preamble << 6) | (nss << 4) | rate;
-
-	return set_value;
+	return ucfg_mlme_assemble_rate_code(preamble, nss, rate);
 }
 
 #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
@@ -7524,7 +7517,9 @@ QDF_STATUS hdd_init_station_mode(struct wlan_hdd_link_info *link_info)
 			goto error_wmm_init;
 	}
 
+	hdd_tsf_auto_report_init(adapter);
 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID);
+
 	return QDF_STATUS_SUCCESS;
 
 error_wmm_init:
@@ -9689,7 +9684,6 @@ QDF_STATUS hdd_reset_all_adapters(struct hdd_context *hdd_ctx)
 						     WLAN_DATA_FLOW_CONTROL);
 
 			hdd_reset_scan_operation(link_info);
-
 			if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) {
 				hdd_wmm_adapter_close(adapter);
 				clear_bit(WMM_INIT_DONE, &adapter->event_flags);
@@ -10829,7 +10823,7 @@ out:
 static QDF_STATUS
 hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx)
 {
-#define SHUTDOWN_IN_SUSPEND_RETRY 10
+#define SHUTDOWN_IN_SUSPEND_RETRY 30
 
 	int count = 0;
 	enum pmo_suspend_mode mode;
@@ -10842,7 +10836,7 @@ hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx)
 	mode = ucfg_pmo_get_suspend_mode(hdd_ctx->psoc);
 	hdd_debug("suspend mode is %d", mode);
 
-	if (mode == PMO_SUSPEND_NONE || PMO_SUSPEND_LEGENCY) {
+	if (mode == PMO_SUSPEND_NONE || mode == PMO_SUSPEND_LEGENCY) {
 		hdd_debug("needn't shutdown in suspend");
 		return 0;
 	}
@@ -10855,7 +10849,7 @@ hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx)
 			return 0;
 	}
 
-	/*try to wait interfacee down for PMO_SUSPEND_SHUTDOWN mode*/
+	/*try to wait interface down for PMO_SUSPEND_SHUTDOWN mode*/
 	while (hdd_is_any_interface_open(hdd_ctx) &&
 	       count < SHUTDOWN_IN_SUSPEND_RETRY) {
 		count++;
@@ -21395,6 +21389,20 @@ uint8_t hdd_chwidth_to_nl80211_chwidth(enum eSirMacHTChannelWidth chwidth)
 	return 0xFF;
 }
 
+uint8_t hdd_phy_chwidth_to_nl80211_chwidth(enum phy_ch_width chwidth)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chwidth_info); i++) {
+		if (chwidth_info[i].sir_chwidth_valid &&
+		    chwidth_info[i].phy_chwidth == chwidth)
+			return i;
+	}
+
+	hdd_err("Unsupported channel width %d", chwidth);
+	return 0xFF;
+}
+
 enum hw_mode_bandwidth wlan_hdd_get_channel_bw(enum nl80211_chan_width width)
 {
 	if (width >= ARRAY_SIZE(chwidth_info)) {

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

@@ -704,6 +704,7 @@ hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event *event)
 
 static int
 hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb,
+				      struct wlan_objmgr_psoc *psoc,
 				      struct ml_link_state_info_event *params,
 				      uint32_t num_link_info)
 {
@@ -713,9 +714,7 @@ hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb,
 	uint32_t value;
 
 	attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE;
-
-	/* Default control mode is only supported */
-	value = QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT;
+	value = ucfg_mlme_get_ml_link_control_mode(psoc, params->vdev_id);
 	errno = nla_put_u32(skb, attr, value);
 	if (errno)
 		return errno;
@@ -761,6 +760,7 @@ hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb,
 }
 
 static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy,
+					      struct wlan_objmgr_psoc *psoc,
 					      struct wlan_objmgr_vdev *vdev)
 {
 	int errno;
@@ -838,7 +838,7 @@ static QDF_STATUS wlan_hdd_link_state_request(struct wiphy *wiphy,
 	}
 
 	status = hdd_ml_generate_link_state_resp_nlmsg(
-			reply_skb, link_state_event,
+			reply_skb, psoc, link_state_event,
 			link_state_event->num_mlo_vdev_link_info);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Failed to pack nl response");
@@ -894,7 +894,7 @@ int wlan_handle_mlo_link_state_operation(struct wiphy *wiphy,
 	ml_link_op = nla_get_u8(link_oper_attr);
 	switch (ml_link_op) {
 	case QCA_WLAN_VENDOR_LINK_STATE_OP_GET:
-		return wlan_hdd_link_state_request(wiphy, vdev);
+		return wlan_hdd_link_state_request(wiphy, hdd_ctx->psoc, vdev);
 	case QCA_WLAN_VENDOR_LINK_STATE_OP_SET:
 		break;
 	default:
@@ -998,6 +998,9 @@ int wlan_handle_mlo_link_state_operation(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
+	ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, vdev_id,
+					   ml_link_control_mode);
+
 	hdd_debug("vdev: %d, processed link state command successfully",
 		  vdev_id);
 	return 0;

+ 23 - 1
core/hdd/src/wlan_hdd_nan_datapath.c

@@ -68,6 +68,27 @@ void hdd_nan_datapath_target_config(struct hdd_context *hdd_ctx,
 		  tgt_cfg->nan_datapath_enabled);
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
+/**
+ * hdd_close_ndi_adapter() - close the adapter
+ * @hdd_ctx: pointer to HDD context
+ * @adapter: adapter context
+ * @value: true or false
+ *
+ * Returns: void
+ */
+static void hdd_close_ndi_adapter(struct hdd_context *hdd_ctx,
+				  struct hdd_adapter *adapter, bool value)
+{
+}
+#else
+static void hdd_close_ndi_adapter(struct hdd_context *hdd_ctx,
+				  struct hdd_adapter *adapter, bool value)
+{
+	hdd_close_adapter(hdd_ctx, adapter, value);
+}
+#endif
+
 /**
  * hdd_close_ndi() - close NAN Data interface
  * @adapter: adapter context
@@ -101,7 +122,7 @@ static int hdd_close_ndi(struct hdd_adapter *adapter)
 
 	adapter->is_virtual_iface = true;
 	/* We are good to close the adapter */
-	hdd_close_adapter(hdd_ctx, adapter, true);
+	hdd_close_ndi_adapter(hdd_ctx, adapter, true);
 
 	hdd_exit();
 	return 0;
@@ -651,6 +672,7 @@ int hdd_init_nan_data_mode(struct hdd_adapter *adapter)
 
 	hdd_set_netdev_flags(adapter);
 
+	hdd_tsf_auto_report_init(adapter);
 	update_ndi_state(adapter, NAN_DATA_NDI_CREATING_STATE);
 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
 	return ret_val;

+ 26 - 17
core/hdd/src/wlan_hdd_p2p.c

@@ -442,7 +442,7 @@ int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command)
 {
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
 	struct p2p_ps_config noa = {0};
-	int count, duration, interval;
+	int count, duration, interval, start = 0;
 	char *param;
 	int ret;
 
@@ -452,19 +452,25 @@ int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command)
 		return -EINVAL;
 	}
 	param++;
-	ret = sscanf(param, "%d %d %d", &count, &interval, &duration);
-	if (ret != 3) {
+	ret = sscanf(param, "%d %d %d %d", &count, &start, &duration,
+		     &interval);
+	if (ret < 3) {
 		hdd_err("P2P_SET GO noa: fail to read params, ret=%d",
 			ret);
 		return -EINVAL;
 	}
-	if (count < 0 || interval < 0 || duration < 0 ||
-	    interval > MAX_MUS_VAL || duration > MAX_MUS_VAL) {
+
+	if (ret == 3)
+		interval = 100;
+
+	if (start < 0 || count < 0 || interval < 0 || duration < 0 ||
+	    start > MAX_MUS_VAL || interval > MAX_MUS_VAL ||
+	    duration > MAX_MUS_VAL) {
 		hdd_err("Invalid NOA parameters");
 		return -EINVAL;
 	}
-	hdd_debug("P2P_SET GO noa: count=%d interval=%d duration=%d",
-		count, interval, duration);
+	hdd_debug("P2P_SET GO noa: count=%d interval=%d duration=%d start=%d",
+		  count, interval, duration, start);
 	duration = MS_TO_TU_MUS(duration);
 	interval = MS_TO_TU_MUS(interval);
 	/* PS Selection
@@ -488,15 +494,17 @@ int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command)
 		noa.single_noa_duration = 0;
 		noa.ps_selection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
 	}
+
+	noa.start = start;
 	noa.interval = interval;
 	noa.count = count;
 	noa.vdev_id = adapter->deflink->vdev_id;
 
-	hdd_debug("P2P_PS_ATTR:opp ps %d ct window %d duration %d "
-		  "interval %d count %d single noa duration %d "
-		  "ps selection %x", noa.opp_ps,
-		  noa.ct_window, noa.duration, noa.interval,
-		  noa.count, noa.single_noa_duration, noa.ps_selection);
+	hdd_debug("P2P_PS_ATTR:opp ps %d ct window %d count %d interval %d "
+		  "duration %d start %d single noa duration %d "
+		  "ps selection %x", noa.opp_ps, noa.ct_window, noa.count,
+		  noa.interval, noa.duration, noa.start,
+		  noa.single_noa_duration, noa.ps_selection);
 
 	return wlan_hdd_set_power_save(adapter, &noa);
 }
@@ -1239,11 +1247,12 @@ int wlan_hdd_set_power_save(struct hdd_adapter *adapter,
 		return -EINVAL;
 	}
 
-	hdd_debug("opp ps:%d, ct window:%d, duration:%d, interval:%d, count:%d, single noa duration:%d, ps selection:%d, vdev id:%d",
-		ps_config->opp_ps, ps_config->ct_window,
-		ps_config->duration, ps_config->interval,
-		ps_config->count, ps_config->single_noa_duration,
-		ps_config->ps_selection, ps_config->vdev_id);
+	hdd_debug("opp ps:%d, ct window:%d, duration:%d, interval:%d, count:%d start:%d, single noa duration:%d, ps selection:%d, vdev id:%d",
+		  ps_config->opp_ps, ps_config->ct_window,
+		  ps_config->duration, ps_config->interval,
+		  ps_config->count, ps_config->start,
+		  ps_config->single_noa_duration,
+		  ps_config->ps_selection, ps_config->vdev_id);
 
 	status = ucfg_p2p_set_ps(psoc, ps_config);
 	hdd_debug("p2p set power save, status:%d", status);

+ 4 - 6
core/hdd/src/wlan_hdd_power.c

@@ -2225,12 +2225,10 @@ int wlan_hdd_set_powersave(struct wlan_hdd_link_info *link_info,
 				hdd_ctx->mac_handle, link_info->vdev_id,
 				allow_power_save, timeout,
 				sta_ctx->ap_supports_immediate_power_save);
-	if (!allow_power_save) {
-		if (adapter->device_mode == QDF_STA_MODE)
-			hdd_twt_del_dialog_in_ps_disable(hdd_ctx,
-						&sta_ctx->conn_info.bssid,
-						link_info->vdev_id);
-	}
+	if (!allow_power_save && adapter->device_mode == QDF_STA_MODE)
+		hdd_twt_del_dialog_in_ps_disable(hdd_ctx,
+						 &sta_ctx->conn_info.bssid,
+						 link_info->vdev_id);
 
 	return qdf_status_to_os_return(status);
 }

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

@@ -1068,6 +1068,11 @@ void hdd_reg_notifier(struct wiphy *wiphy,
 		return;
 	}
 
+	if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
+		hdd_err_rl("Driver module is closed, dropping request");
+		return;
+	}
+
 	hdd_debug("country: %c%c, initiator %d, dfs_region: %d",
 		  request->alpha2[0],
 		  request->alpha2[1],

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

@@ -1489,7 +1489,7 @@ static void hdd_son_deauth_sta(struct wlan_objmgr_vdev *vdev,
 		  QDF_MAC_ADDR_REF(peer_mac), ignore_frame);
 
 	status = hdd_softap_sta_deauth(link_info->adapter, &param);
-	if (QDF_STATUS_IS_ERROR(status))
+	if (QDF_IS_STATUS_ERROR(status))
 		hdd_err("Error in deauthenticating peer");
 }
 
@@ -2227,6 +2227,7 @@ static int hdd_son_get_acs_report(struct wlan_objmgr_vdev *vdev,
 	struct hdd_context *hdd_ctx;
 	struct ieee80211_acs_dbg *acs_r = NULL;
 	struct sap_context *sap_ctx;
+	qdf_size_t not_copied;
 
 	if (!acs_report) {
 		hdd_err("null acs_report");
@@ -2315,7 +2316,9 @@ static int hdd_son_get_acs_report(struct wlan_objmgr_vdev *vdev,
 				break;
 			}
 		}
-		copy_to_user(acs_report, acs_r, sizeof(*acs_r));
+		not_copied = copy_to_user(acs_report, acs_r, sizeof(*acs_r));
+		if (not_copied)
+			hdd_debug("%ul is not copied", not_copied);
 	} else if (acs_type == ACS_CHAN_NF_STATS) {
 	} else if (acs_type == ACS_NEIGHBOUR_GET_LIST_COUNT ||
 		   acs_type == ACS_NEIGHBOUR_GET_LIST) {

File diff suppressed because it is too large
+ 323 - 406
core/hdd/src/wlan_hdd_stats.c


+ 170 - 0
core/hdd/src/wlan_hdd_sysfs_connect_info.c

@@ -297,6 +297,7 @@ uint8_t *hdd_dot11_mode_str(uint32_t dot11mode)
 	return "UNKNOWN";
 }
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
 /**
  * wlan_hdd_connect_info() - Populate connect info
  * @adapter: pointer to sta adapter for which connect info is required
@@ -305,6 +306,174 @@ uint8_t *hdd_dot11_mode_str(uint32_t dot11mode)
  *
  * Return: No.of bytes populated by this function in buffer
  */
+static ssize_t wlan_hdd_connect_info(struct hdd_adapter *adapter, uint8_t *buf,
+				     ssize_t buf_avail_len)
+{
+	struct wlan_hdd_link_info *link_info;
+	struct hdd_station_ctx *hdd_sta_ctx;
+	uint32_t len = 0;
+	ssize_t length = 0;
+	struct hdd_connection_info *conn_info;
+	uint32_t tx_bit_rate, rx_bit_rate;
+	bool is_legacy = false;
+	bool is_standby = false;
+
+	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
+		len = scnprintf(buf, buf_avail_len,
+				"STA is not connected\n");
+		if (len >= 0)
+			return length;
+	}
+
+	len = scnprintf(buf, buf_avail_len,
+			"CONNECTION DETAILS\n");
+	if (len <= 0)
+		return length;
+
+	length += len;
+	if (length >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
+	if (adapter->deflink == &adapter->link_info[0] &&
+	    hdd_sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID) {
+		len = scnprintf(buf + length, buf_avail_len - length,
+				"CONNECTION DETAILS: Non-ML connection\n");
+		is_legacy = true;
+	} else {
+		len = scnprintf(buf + length, buf_avail_len - length,
+				"CONNECTION DETAILS: ML connection\n");
+	}
+
+	if (len <= 0)
+		return length;
+
+	length += len;
+	if (length >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+
+	len = scnprintf(buf + length, buf_avail_len - length,
+			"ssid: %s\n"
+			"bssid: " QDF_MAC_ADDR_FMT "\n"
+			"connect_time: %s\n"
+			"auth_time: %s\n"
+			"last_auth_type: %s\n"
+			"dot11mode: %s\n",
+			hdd_sta_ctx->conn_info.last_ssid.SSID.ssId,
+			QDF_MAC_ADDR_REF(hdd_sta_ctx->conn_info.bssid.bytes),
+			hdd_sta_ctx->conn_info.connect_time,
+			hdd_sta_ctx->conn_info.auth_time,
+			hdd_auth_type_str(hdd_sta_ctx->conn_info.last_auth_type),
+			hdd_dot11_mode_str(hdd_sta_ctx->conn_info.dot11mode));
+	if (len <= 0)
+		return length;
+	length += len;
+	if (length >= buf_avail_len) {
+		hdd_err("No sufficient buf_avail_len");
+		return buf_avail_len;
+	}
+
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+		conn_info = &hdd_sta_ctx->conn_info;
+
+		if(!is_legacy && conn_info->ieee_link_id == WLAN_INVALID_LINK_ID)
+			continue;
+
+		if (hdd_cm_is_vdev_roaming(link_info)) {
+			len = scnprintf(buf + length, buf_avail_len - length,
+					"Roaming is in progress");
+			if (len <= 0)
+				return length;
+
+			length += len;
+		}
+
+		tx_bit_rate = cfg80211_calculate_bitrate(&conn_info->txrate);
+		rx_bit_rate = cfg80211_calculate_bitrate(&conn_info->rxrate);
+
+		if (!is_legacy) {
+			len = scnprintf(buf + length, buf_avail_len - length,
+					"\nlink_id: %d\n",
+					conn_info->ieee_link_id);
+			if (len <= 0)
+				return length;
+
+			length += len;
+			if (length >= buf_avail_len) {
+				hdd_debug("No sufficient buf_avail_len");
+				return buf_avail_len;
+			}
+
+			if (link_info->vdev_id == WLAN_INVALID_VDEV_ID &&
+			    conn_info->ieee_link_id != WLAN_INVALID_LINK_ID)
+				is_standby = true;
+
+			len = scnprintf(buf + length, buf_avail_len - length,
+					"stand-by link: %d\n",
+					is_standby);
+			if (len <= 0)
+				return length;
+
+			length += len;
+			if (length >= buf_avail_len) {
+				hdd_debug("No sufficient buf_avail_len");
+				return buf_avail_len;
+			}
+		}
+
+		len = scnprintf(buf + length, buf_avail_len - length,
+				"freq: %u\n"
+				"ch_width: %s\n"
+				"signal: %ddBm\n"
+				"tx_bit_rate: %u\n"
+				"rx_bit_rate: %u\n"
+				"last_auth_type: %s\n"
+				"dot11mode: %s\n",
+				conn_info->chan_freq,
+				hdd_ch_width_str(conn_info->ch_width),
+				conn_info->signal,
+				tx_bit_rate,
+				rx_bit_rate,
+				hdd_auth_type_str(conn_info->last_auth_type),
+				hdd_dot11_mode_str(conn_info->dot11mode));
+
+		if (len <= 0)
+			return length;
+
+		length += len;
+		if (length >= buf_avail_len) {
+			hdd_debug("No sufficient buf_avail_len");
+			return buf_avail_len;
+		}
+
+		length += wlan_hdd_add_nss_info(conn_info, buf + length,
+						buf_avail_len - length);
+		if (length >= buf_avail_len) {
+			hdd_debug("No sufficient buf_avail_len");
+			return buf_avail_len;
+		}
+
+		length += wlan_hdd_add_ht_cap_info(conn_info, buf + length,
+						   buf_avail_len - length);
+		if (length >= buf_avail_len) {
+			hdd_debug("No sufficient buf_avail_len");
+			return buf_avail_len;
+		}
+
+		length += wlan_hdd_add_vht_cap_info(conn_info, buf + length,
+						    buf_avail_len - length);
+		if (is_legacy)
+			return length;
+	}
+
+	return length;
+}
+#else
 static ssize_t wlan_hdd_connect_info(struct hdd_adapter *adapter, uint8_t *buf,
 				     ssize_t buf_avail_len)
 {
@@ -401,6 +570,7 @@ static ssize_t wlan_hdd_connect_info(struct hdd_adapter *adapter, uint8_t *buf,
 					    buf_avail_len - length);
 	return length;
 }
+#endif
 
 static ssize_t
 wlan_hdd_current_time_info(uint8_t *buf, ssize_t buf_avail_len)

+ 109 - 69
core/hdd/src/wlan_hdd_tsf.c

@@ -35,7 +35,7 @@
 #endif
 
 #include "ol_txrx_api.h"
-#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
+#ifdef WLAN_FEATURE_TSF_AUTO_REPORT
 #include <cdp_txrx_ctrl.h>
 #endif
 
@@ -3000,18 +3000,23 @@ static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
 }
 #endif /* WLAN_FEATURE_TSF_PTP */
 
-#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
-static int hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena)
+#ifdef WLAN_FEATURE_TSF_AUTO_REPORT
+void hdd_tsf_auto_report_init(struct hdd_adapter *adapter)
 {
-	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
-	int ret;
+	adapter->tsf.auto_rpt_src = 0;
+}
 
-	if (QDF_IS_STATUS_ERROR(cdp_set_tsf_ul_delay_report(
-						soc,
-						adapter->deflink->vdev_id,
-						ena))) {
-		hdd_err_rl("Set tsf report uplink delay failed");
-		return -EPERM;
+int
+hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena,
+			enum hdd_tsf_auto_rpt_source source)
+{
+	int ret = 0;
+	bool enabled;
+
+	enabled = !!adapter->tsf.auto_rpt_src;
+	if (enabled == ena) {
+		hdd_info_rl("current %d and no action is required", enabled);
+		goto set_src;
 	}
 
 	ret = wma_cli_set_command((int)adapter->deflink->vdev_id,
@@ -3019,67 +3024,58 @@ static int hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena)
 				  (int)GEN_PARAM_TSF_AUTO_REPORT_DISABLE,
 				  ena, GEN_CMD);
 	if (ret) {
-		hdd_err_rl("tsf auto report %d failed", ena);
-		return -EINPROGRESS;
+		hdd_err_rl("tsf auto report %d failed: %d", ena, ret);
+		ret = -EINPROGRESS;
+		goto out;
 	}
 
-	qdf_atomic_set(&adapter->tsf.tsf_auto_report, ena);
+set_src:
+	if (ena)
+		qdf_atomic_set_bit(source, &adapter->tsf.auto_rpt_src);
+	else
+		qdf_atomic_clear_bit(source, &adapter->tsf.auto_rpt_src);
 
-	return 0;
+out:
+	return ret;
 }
 
 /**
- * hdd_handle_tsf_auto_report(): Handle TSF auto report enable or disable
- * @adapter: pointer of struct hdd_adapter
- * @tsf_cmd: TSF command from user space
+ * hdd_tsf_auto_report_enabled() - get current state of tsf auto report
+ * for an adapter
+ * @adapter: pointer to Adapter context
  *
- * Return: 0 for success, -EINVAL to continue to handle other TSF commands and
- *	   else errors
+ * Return: true for enabled, false for disabled
  */
-static int hdd_handle_tsf_auto_report(struct hdd_adapter *adapter,
-				      uint32_t tsf_cmd)
+static inline bool hdd_tsf_auto_report_enabled(struct hdd_adapter *adapter)
 {
-	bool ena;
-
-	if (tsf_cmd != QCA_TSF_AUTO_REPORT_ENABLE &&
-	    tsf_cmd != QCA_TSF_AUTO_REPORT_DISABLE) {
-		hdd_debug_rl("tsf_cmd %d not for uplink delay", tsf_cmd);
-		return -EINVAL;
-	}
-
-	/* uplink delay feature is required for STA and P2P-GC mode */
-	if (adapter->device_mode != QDF_STA_MODE &&
-	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
-		hdd_debug_rl("tsf_cmd %d not allowed for device mode %d",
-			     tsf_cmd, adapter->device_mode);
-		return -EPERM;
-	}
-
-	ena = (tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE) ? true : false;
-
-	return hdd_set_tsf_auto_report(adapter, ena);
+	return !!adapter->tsf.auto_rpt_src;
 }
 
+/**
+ * hdd_set_delta_tsf() - calculate and save the time difference between
+ * TQM clock and TSF clock
+ * @adapter: pointer to Adapter context
+ * @ptsf: pointer to tsf information
+ *
+ * Return: QDF_STATUS
+ */
 static QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
 				    struct stsf *ptsf)
 {
 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
 	uint32_t delta_tsf;
 
-	/* If TSF report is for uplink delay, mac_id_valid will be set to
-	 * 1 by target. If not, the report is not for uplink delay feature
-	 * and return failure here so that legacy BSS TSF logic can be
-	 * continued.
+	/* A tsf report event with mac_id_valid equals to 1 represents
+	 * for tsf auto report, that's what we need to handle in this
+	 * function; otherwise, return failure here so that legacy BSS
+	 * TSF logic can be continued.
 	 */
 	if (!ptsf->mac_id_valid) {
-		hdd_debug_rl("TSF report not for uplink delay");
+		hdd_debug_rl("Not TSF auto report");
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	/* For uplink delay feature, TSF auto report needs to be enabled
-	 * first. Otherwise TSF event will not be posted by target.
-	 */
-	if (!qdf_atomic_read(&adapter->tsf.tsf_auto_report)) {
+	if (!hdd_tsf_auto_report_enabled(adapter)) {
 		hdd_debug_rl("adapter %u tsf_auto_report disabled",
 			     adapter->deflink->vdev_id);
 		goto exit_with_success;
@@ -3089,7 +3085,7 @@ static QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
 	hdd_debug("vdev %u tsf_low %u qtimer_low %u delta_tsf %u",
 		  ptsf->vdev_id, ptsf->tsf_low, ptsf->soc_timer_low, delta_tsf);
 
-	/* Pass delta_tsf to DP layer to report uplink delay
+	/* Pass delta_tsf to DP layer to calculate hw delay
 	 * on a per vdev basis
 	 */
 	cdp_set_delta_tsf(soc, adapter->deflink->vdev_id, delta_tsf);
@@ -3097,6 +3093,45 @@ static QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
 exit_with_success:
 	return QDF_STATUS_SUCCESS;
 }
+#else /* !WLAN_FEATURE_TSF_AUTO_REPORT */
+static inline QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
+					   struct stsf *ptsf)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline bool hdd_tsf_auto_report_enabled(struct hdd_adapter *adapter)
+{
+	return false;
+}
+#endif /* WLAN_FEATURE_TSF_AUTO_REPORT */
+
+#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
+/**
+ * hdd_set_tsf_ul_delay_report() - enable or disable tsf uplink delay report
+ * for an adapter
+ * @adapter: pointer to Adapter context
+ * @ena: requesting state (true or false)
+ *
+ * Return: 0 for success or non-zero negative failure code
+ */
+static int
+hdd_set_tsf_ul_delay_report(struct hdd_adapter *adapter, bool ena)
+{
+	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
+	QDF_STATUS status;
+
+	status = cdp_set_tsf_ul_delay_report(soc,
+					     adapter->deflink->vdev_id,
+					     ena);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err_rl("Set tsf report uplink delay failed");
+		return -EPERM;
+	}
+
+	return 0;
+}
 
 uint32_t hdd_get_uplink_delay_len(struct hdd_adapter *adapter)
 {
@@ -3117,7 +3152,7 @@ QDF_STATUS hdd_add_uplink_delay(struct hdd_adapter *adapter,
 	    adapter->device_mode != QDF_P2P_CLIENT_MODE)
 		return QDF_STATUS_SUCCESS;
 
-	if (qdf_atomic_read(&adapter->tsf.tsf_auto_report)) {
+	if (hdd_tsf_auto_report_enabled(adapter)) {
 		status = cdp_get_uplink_delay(soc, adapter->deflink->vdev_id,
 					      &ul_delay);
 		if (QDF_IS_STATUS_ERROR(status))
@@ -3132,18 +3167,11 @@ QDF_STATUS hdd_add_uplink_delay(struct hdd_adapter *adapter,
 
 	return QDF_STATUS_SUCCESS;
 }
-
-#else /* !WLAN_FEATURE_TSF_UPLINK_DELAY */
-static inline int hdd_handle_tsf_auto_report(struct hdd_adapter *adapter,
-					     uint32_t tsf_cmd)
-{
-	return -EINVAL;
-}
-
-static inline QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
-					   struct stsf *ptsf)
+#else
+static inline int
+hdd_set_tsf_ul_delay_report(struct hdd_adapter *adapter, bool ena)
 {
-	return QDF_STATUS_E_FAILURE;
+	return -ENOTSUPP;
 }
 #endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */
 
@@ -3187,7 +3215,7 @@ int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf)
 	}
 
 	adapter = link_info->adapter;
-	/* Intercept tsf report and check if it is for uplink delay.
+	/* Intercept tsf report and check if it is for auto report.
 	 * If yes, return in advance and skip the legacy BSS TSF
 	 * report. Otherwise continue on to the legacy BSS TSF
 	 * report logic.
@@ -3268,6 +3296,9 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 	uint32_t tsf_cmd;
 	enum qca_nl80211_vendor_subcmds_index index =
 		QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX;
+	bool enable_auto_rpt;
+	enum hdd_tsf_auto_rpt_source source =
+		HDD_TSF_AUTO_RPT_SOURCE_UPLINK_DELAY;
 
 	hdd_enter_dev(wdev->netdev);
 
@@ -3292,13 +3323,22 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 	}
 	tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]);
 
-	/* Intercept tsf_cmd for TSF auto report enable or disable subcmds.
-	 * If status is -EINVAL, it means tsf_cmd is not for auto report and
-	 * need to continue to handle other tsf cmds.
+	/* Intercept tsf_cmd for TSF auto report enable or disable subcmds,
+	 * and treat as trigger for uplink delay report.
 	 */
-	status = hdd_handle_tsf_auto_report(adapter, tsf_cmd);
-	if (status != -EINVAL)
+	if (tsf_cmd == QCA_TSF_AUTO_REPORT_DISABLE ||
+	    tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE) {
+		enable_auto_rpt = (tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE);
+		status = hdd_set_tsf_auto_report(adapter,
+						 enable_auto_rpt,
+						 source);
+		if (status)
+			goto end;
+
+		hdd_set_tsf_ul_delay_report(adapter, enable_auto_rpt);
 		goto end;
+	}
+
 	ret = qdf_event_reset(&tsf_sync_get_completion_evt);
 	if (QDF_IS_STATUS_ERROR(ret))
 		hdd_warn("failed to reset tsf_sync_get_completion_evt");

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

@@ -757,7 +757,6 @@ struct mac_context {
 #ifdef WLAN_FEATURE_CAL_FAILURE_TRIGGER
 	void (*cal_failure_event_cb)(uint8_t cal_type, uint8_t reason);
 #endif
-	uint8_t ba_mode;
 };
 
 #ifdef FEATURE_WLAN_TDLS

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

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

@@ -3807,6 +3807,20 @@ struct sir_nss_update_request {
 	uint32_t vdev_id;
 };
 
+/**
+ * struct sir_sap_ch_width_update
+ * @msgType: ch_width update msg type
+ * @msgLen: length of the msg
+ * @ch_width: channel width
+ * @vdev_id: vdev id
+ */
+struct sir_sap_ch_width_update {
+	uint16_t msgType;
+	uint16_t msgLen;
+	enum phy_ch_width ch_width;
+	uint32_t vdev_id;
+};
+
 /**
  * enum sir_bcn_update_reason: bcn update reason
  * @REASON_DEFAULT: reason default
@@ -3827,6 +3841,7 @@ enum sir_bcn_update_reason {
 	REASON_CHANNEL_SWITCH = 5,
 	REASON_MLO_IE_UPDATE = 6,
 	REASON_RNR_UPDATE = 7,
+	REASON_CH_WIDTH_UPDATE = 8,
 };
 
 /**

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

@@ -87,8 +87,10 @@ enum eWniMsgTypes {
 	eWNI_SME_BEACON_REPORT_RESP_XMIT_IND = SIR_SME_MSG_TYPES_BEGIN + 46,
 	eWNI_SME_CHAN_LOAD_REQ_IND = SIR_SME_MSG_TYPES_BEGIN + 47,
 	eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND = SIR_SME_MSG_TYPES_BEGIN + 48,
+	eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ = SIR_SME_MSG_TYPES_BEGIN + 49,
+	eWNI_SME_SAP_CH_WIDTH_UPDATE_RSP = SIR_SME_MSG_TYPES_BEGIN + 50,
 
-	/* unused SIR_SME_MSG_TYPES_BEGIN + 49, */
+	/* unused SIR_SME_MSG_TYPES_BEGIN + 51 */
 	eWNI_SME_FT_AGGR_QOS_REQ = SIR_SME_MSG_TYPES_BEGIN + 52,
 	eWNI_SME_FT_AGGR_QOS_RSP = SIR_SME_MSG_TYPES_BEGIN + 53,
 

+ 26 - 0
core/mac/src/cfg/cfgUtil/dot11f.frms

@@ -1333,6 +1333,13 @@ IE RequestedInfo (EID_REQUEST)            // 7.3.2.12
     requested_eids[0..255];
 }
 
+const EID_BCN_REQ_EXTENDED_INFO = 11;
+IE ExtRequestedInfo (EID_BCN_REQ_EXTENDED_INFO)
+{
+    req_element_id,     1;
+    req_element_id_ext[0..255];
+}
+
 IE Country (EID_COUNTRY)                  // 7.3.2.9
 {
     country[3];
@@ -2554,10 +2561,27 @@ IE transmit_power_env (EID_TRANSMIT_POWER_ENVELOPE)
     tx_power[1..8];
 }
 
+IE bw_ind_element (EID_EXTN_ID_ELEMENT) OUI (0x87)
+{
+   {
+       reserved: 1;
+       disabled_sub_chan_bitmap_present: 1;
+       reserved_1: 6;
+   }
+   {
+       channel_width: 3;
+       reserved_2: 5;
+   }
+   ccfs0, 1;
+   ccfs1, 1;
+   disabled_sub_chan_bitmap[2][0..1] COUNTIS disabled_sub_chan_bitmap_present;
+}
+
 IE ChannelSwitchWrapper (EID_CHANNEL_SWITCH_WRAPPER)
 {
     OPTIE IE  WiderBWChanSwitchAnn;
     OPTIE IE  transmit_power_env;
+    OPTIE IE  bw_ind_element;
 }
 
 IE reduced_neighbor_report (EID_RNR_IE)
@@ -3118,6 +3142,7 @@ IE MeasurementRequest (EID_MEAS_REQUEST)  // 7.3.2.21
           OPTIE rrm_reporting;
           OPTIE BcnReportingDetail;
           OPTIE RequestedInfo;
+          OPTIE ExtRequestedInfo;
           OPTIE APChannelReport[0..2];
           OPTIE last_beacon_report_indication;
           //OPTIONAL vendor_specific[1..239];
@@ -4942,6 +4967,7 @@ FRAME ext_channel_switch_action_frame
     FF     ext_chan_switch_ann_action;
     OPTIE  WiderBWChanSwitchAnn;
     OPTIE  qcn_ie;
+    OPTIE  bw_ind_element;
 }
 
 FRAME p2p_oper_chan_change_confirm

+ 92 - 2
core/mac/src/include/dot11f.h

@@ -27,7 +27,7 @@
  *
  *
  * This file was automatically generated by 'framesc'
- * Wed Aug 16 05:58:15 2023 from the following file(s):
+ * Thu Sep  7 12:02:23 2023 from the following file(s):
  *
  * dot11f.frms
  *
@@ -3315,6 +3315,47 @@ uint32_t dot11f_get_packed_ie_CondensedCountryStr(
 }; /* End extern "C". */
 #endif /* C++ */
 
+/* EID 11 (0x0b) */
+typedef struct sDot11fIEExtRequestedInfo {
+	uint8_t             present;
+	uint8_t             req_element_id;
+	uint8_t             num_req_element_id_ext;
+	uint8_t             req_element_id_ext[255];
+} tDot11fIEExtRequestedInfo;
+
+#define DOT11F_EID_EXTREQUESTEDINFO (11)
+
+/* N.B. These #defines do *not* include the EID & length */
+#define DOT11F_IE_EXTREQUESTEDINFO_MIN_LEN (1)
+
+#define DOT11F_IE_EXTREQUESTEDINFO_MAX_LEN (256)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* C++ */
+__must_check uint32_t dot11f_unpack_ie_ExtRequestedInfo(
+	tpAniSirGlobal,
+	uint8_t *,
+	uint8_t,
+	tDot11fIEExtRequestedInfo*,
+	bool);
+
+uint32_t dot11f_pack_ie_ExtRequestedInfo(
+	tpAniSirGlobal,
+	tDot11fIEExtRequestedInfo *,
+	uint8_t *,
+	uint32_t,
+	uint32_t*);
+
+uint32_t dot11f_get_packed_ie_ExtRequestedInfo(
+	tpAniSirGlobal,
+	tDot11fIEExtRequestedInfo *,
+	uint32_t*);
+
+#ifdef __cplusplus
+}; /* End extern "C". */
+#endif /* C++ */
+
 /* EID 66 (0x42) */
 typedef struct sDot11fIEMeasurementPilot {
 	uint8_t             present;
@@ -4421,6 +4462,52 @@ uint32_t dot11f_get_packed_ie_beacon_report_frm_body_fragment_id(
 }; /* End extern "C". */
 #endif /* C++ */
 
+/* EID 255 (0xff) Extended EID 135 (0x87) */
+typedef struct sDot11fIEbw_ind_element {
+	uint8_t             present;
+	uint8_t             reserved:1;
+	uint8_t disabled_sub_chan_bitmap_present:1;
+	uint8_t           reserved_1:6;
+	uint8_t        channel_width:3;
+	uint8_t           reserved_2:5;
+	uint8_t             ccfs0;
+	uint8_t             ccfs1;
+	uint8_t             disabled_sub_chan_bitmap[1][2];
+} tDot11fIEbw_ind_element;
+
+#define DOT11F_EID_BW_IND_ELEMENT (255)
+
+/* N.B. These #defines do *not* include the EID & length */
+#define DOT11F_IE_BW_IND_ELEMENT_MIN_LEN (4)
+
+#define DOT11F_IE_BW_IND_ELEMENT_MAX_LEN (6)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* C++ */
+__must_check uint32_t dot11f_unpack_ie_bw_ind_element(
+	tpAniSirGlobal,
+	uint8_t *,
+	uint8_t,
+	tDot11fIEbw_ind_element*,
+	bool);
+
+uint32_t dot11f_pack_ie_bw_ind_element(
+	tpAniSirGlobal,
+	tDot11fIEbw_ind_element *,
+	uint8_t *,
+	uint32_t,
+	uint32_t*);
+
+uint32_t dot11f_get_packed_ie_bw_ind_element(
+	tpAniSirGlobal,
+	tDot11fIEbw_ind_element *,
+	uint32_t*);
+
+#ifdef __cplusplus
+}; /* End extern "C". */
+#endif /* C++ */
+
 /* EID 164 (0xa4) */
 typedef struct sDot11fIElast_beacon_report_indication {
 	uint8_t             present;
@@ -5016,6 +5103,7 @@ typedef struct sDot11fIEChannelSwitchWrapper {
 	uint8_t                              present;
 	tDot11fIEWiderBWChanSwitchAnn        WiderBWChanSwitchAnn;
 	tDot11fIEtransmit_power_env          transmit_power_env;
+	tDot11fIEbw_ind_element              bw_ind_element;
 } tDot11fIEChannelSwitchWrapper;
 
 #define DOT11F_EID_CHANNELSWITCHWRAPPER (196)
@@ -5023,7 +5111,7 @@ typedef struct sDot11fIEChannelSwitchWrapper {
 /* N.B. These #defines do *not* include the EID & length */
 #define DOT11F_IE_CHANNELSWITCHWRAPPER_MIN_LEN (0)
 
-#define DOT11F_IE_CHANNELSWITCHWRAPPER_MAX_LEN (16)
+#define DOT11F_IE_CHANNELSWITCHWRAPPER_MAX_LEN (24)
 
 #ifdef __cplusplus
 extern "C" {
@@ -6166,6 +6254,7 @@ typedef struct sDot11fIEMeasurementRequest {
 	tDot11fIErrm_reporting rrm_reporting;
 	tDot11fIEBcnReportingDetail BcnReportingDetail;
 	tDot11fIERequestedInfo RequestedInfo;
+	tDot11fIEExtRequestedInfo ExtRequestedInfo;
 	uint16_t num_APChannelReport;
 	tDot11fIEAPChannelReport APChannelReport[2];
 	tDot11fIElast_beacon_report_indication last_beacon_report_indication;
@@ -12637,6 +12726,7 @@ typedef struct sDot11fext_channel_switch_action_frame{
 	tDot11fFfext_chan_switch_ann_action        ext_chan_switch_ann_action;
 	tDot11fIEWiderBWChanSwitchAnn              WiderBWChanSwitchAnn;
 	tDot11fIEqcn_ie                            qcn_ie;
+	tDot11fIEbw_ind_element                    bw_ind_element;
 } tDot11fext_channel_switch_action_frame;
 
 #define DOT11F_EXT_CHANNEL_SWITCH_ACTION_FRAME (52)

+ 20 - 0
core/mac/src/include/parser_api.h

@@ -1565,6 +1565,18 @@ QDF_STATUS populate_dot11f_eht_operation(struct mac_context *mac_ctx,
 					 struct pe_session *session,
 					 tDot11fIEeht_op *eht_op);
 
+/**
+ * populate_dot11f_bw_ind_element() - pouldate bandwidth ind element
+ * @mac_ctx: Global MAC context
+ * @session: PE session
+ * @bw_ind: pointer to bw ind element IE
+ *
+ * QDF_STATUS
+ */
+QDF_STATUS populate_dot11f_bw_ind_element(struct mac_context *mac_ctx,
+					  struct pe_session *session,
+					  tDot11fIEbw_ind_element *bw_ind);
+
 /**
  * lim_ieee80211_pack_ehtcap() - Pack EHT capabilities IE
  * @ie: output pointer for eht capabilities IE
@@ -1660,6 +1672,14 @@ populate_dot11f_eht_operation(struct mac_context *mac_ctx,
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline
+QDF_STATUS populate_dot11f_bw_ind_element(struct mac_context *mac_ctx,
+					  struct pe_session *session,
+					  tDot11fIEbw_ind_element *bw_ind)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static inline void lim_ieee80211_pack_ehtcap(uint8_t *ie,
 					     tDot11fIEeht_cap dot11f_eht_cap,
 					     tDot11fIEhe_cap dot11f_he_cap,

+ 1 - 2
core/mac/src/pe/include/lim_global.h

@@ -370,8 +370,7 @@ typedef struct sLimChannelSwitchInfo {
 
 typedef struct sLimOperatingModeInfo {
 	uint8_t present;
-	uint8_t chanWidth:2;
-	uint8_t reserved:2;
+	uint8_t chanWidth:4;
 	uint8_t rxNSS:3;
 	uint8_t rxNSSType:1;
 } tLimOperatingModeInfo, *tpLimOperatingModeInfo;

+ 17 - 0
core/mac/src/pe/include/lim_session.h

@@ -193,6 +193,18 @@ struct mld_capab_and_op {
 	uint16_t reserved:3;
 };
 
+/**
+ * struct ext_mld_capab_and_op - EXT MLD capability and operations info
+ * @op_parameter_update_support: operation parameter update support
+ * @rec_max_simultaneous_links: recommended max simultaneous links
+ * @reserved: reserved
+ */
+struct ext_mld_capab_and_op {
+	uint16_t op_parameter_update_support:1;
+	uint16_t rec_max_simultaneous_links:3;
+	uint16_t reserved:11;
+};
+
 /**
  * struct wlan_mlo_ie - wlan ML IE info
  * @type: the variant of the ML IE
@@ -214,6 +226,7 @@ struct mld_capab_and_op {
  * @eml_capabilities_info: structure of eml_capabilities
  * @mld_capab_and_op_info: structure of mld_capabilities and operations
  * @mld_id_info: MLD ID
+ * @ext_mld_capab_and_op_info: structure of ext_mld_capab_and operations
  * @num_sta_profile: the number of sta profile
  * @sta_profile: structure of wlan_mlo_sta_profile
  * @num_data: the length of data
@@ -239,6 +252,7 @@ struct wlan_mlo_ie {
 	struct eml_capabilities eml_capabilities_info;
 	struct mld_capab_and_op mld_capab_and_op_info;
 	uint8_t mld_id_info;
+	struct ext_mld_capab_and_op ext_mld_capab_and_op_info;
 	uint16_t num_sta_profile;
 	struct wlan_mlo_sta_profile sta_profile[WLAN_MLO_MAX_VDEVS];
 	uint16_t num_data;
@@ -558,6 +572,8 @@ struct wlan_mlo_ie_info {
  * @chainMask:
  * @dfsIncludeChanSwIe: Flag to indicate Chan Sw announcement is required
  * @dfsIncludeChanWrapperIe: Flag to indicate Chan Wrapper Element is required
+ * @bw_update_include_ch_sw_ie: Flag to indicate chan switch Element is required
+ *                              due to bandwidth update
  * @cc_switch_mode:
  * @isCiscoVendorAP:
  * @add_ie_params:
@@ -867,6 +883,7 @@ struct pe_session {
 	uint8_t dfsIncludeChanSwIe;
 
 	uint8_t dfsIncludeChanWrapperIe;
+	uint8_t bw_update_include_ch_sw_ie;
 
 #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
 	uint8_t cc_switch_mode;

+ 7 - 0
core/mac/src/pe/include/rrm_global.h

@@ -199,9 +199,16 @@ typedef struct sSirNeighborReportInd {
 	tSirNeighborBssDescription sNeighborBssDescription[1];
 } tSirNeighborReportInd, *tpSirNeighborReportInd;
 
+typedef struct eid_ext_info {
+	uint8_t eid;
+	uint8_t num_eid_ext;
+	uint8_t eid_ext[255];
+} eid_ext_info;
+
 typedef struct sRRMBeaconReportRequestedIes {
 	uint8_t num;
 	uint8_t *pElementIds;
+	eid_ext_info ext_info;
 } tRRMBeaconReportRequestedIes, *tpRRMBeaconReportRequestedIes;
 
 /* Reporting detail defines. */

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

@@ -4013,7 +4013,6 @@ QDF_STATUS lim_update_mlo_mgr_info(struct mac_context *mac_ctx,
 {
 	struct wlan_objmgr_pdev *pdev;
 	struct scan_cache_entry *cache_entry;
-	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct wlan_channel channel;
 
 	pdev = mac_ctx->pdev;
@@ -4038,7 +4037,7 @@ QDF_STATUS lim_update_mlo_mgr_info(struct mac_context *mac_ctx,
 	mlo_mgr_update_ap_channel_info(vdev, link_id, (uint8_t *)link_addr,
 				       channel);
 
-	return status;
+	return QDF_STATUS_SUCCESS;
 }
 #else
 static inline void

+ 8 - 1
core/mac/src/pe/lim/lim_process_action_frame.c

@@ -1122,7 +1122,14 @@ __lim_process_radio_measure_request(struct mac_context *mac, uint8_t *pRxPacketI
 	}
 	/* Call rrm function to handle the request. */
 
-	rrm_process_radio_measurement_request(mac, pHdr->sa, frm,
+	pe_debug("vdev: %d Received rrm req from sa addr:"QDF_MAC_ADDR_FMT" bssId:"QDF_MAC_ADDR_FMT" session addr:"QDF_MAC_ADDR_FMT" session self addr:"QDF_MAC_ADDR_FMT"",
+		 pe_session->vdev_id,
+		 QDF_MAC_ADDR_REF(pHdr->sa),
+		 QDF_MAC_ADDR_REF(pHdr->bssId),
+		 QDF_MAC_ADDR_REF(pe_session->bssId),
+		 QDF_MAC_ADDR_REF(pe_session->self_mac_addr));
+
+	rrm_process_radio_measurement_request(mac, pe_session->bssId, frm,
 					      pe_session);
 err:
 	qdf_mem_free(frm);

+ 7 - 17
core/mac/src/pe/lim/lim_process_beacon_frame.c

@@ -49,6 +49,7 @@
 #ifdef WLAN_FEATURE_11BE_MLO
 #include <cds_ieee80211_common.h>
 #endif
+#include "wlan_t2lm_api.h"
 
 #ifdef WLAN_FEATURE_11BE_MLO
 void lim_process_bcn_prb_rsp_t2lm(struct mac_context *mac_ctx,
@@ -67,20 +68,17 @@ void lim_process_bcn_prb_rsp_t2lm(struct mac_context *mac_ctx,
 	if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev))
 		return;
 
-	if (!mlo_check_if_all_links_up(vdev))
+	if (!wlan_cm_is_vdev_connected(vdev))
 		return;
 
-	if (bcn_ptr->t2lm_ctx.upcoming_t2lm.t2lm.direction ==
-	    WLAN_T2LM_INVALID_DIRECTION &&
-	    bcn_ptr->t2lm_ctx.established_t2lm.t2lm.direction ==
-	    WLAN_T2LM_INVALID_DIRECTION)
+	if (!mlo_check_if_all_links_up(vdev))
 		return;
 
 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
+
 	qdf_mem_copy((uint8_t *)&t2lm_ctx->tsf, (uint8_t *)bcn_ptr->timeStamp,
 		     sizeof(uint64_t));
-	wlan_process_bcn_prbrsp_t2lm_ie(vdev, &bcn_ptr->t2lm_ctx,
-					t2lm_ctx->tsf);
+	wlan_update_t2lm_mapping(vdev, &bcn_ptr->t2lm_ctx, t2lm_ctx->tsf);
 }
 
 void lim_process_beacon_mlo(struct mac_context *mac_ctx,
@@ -287,16 +285,8 @@ void lim_process_beacon_eht_op(struct pe_session *session,
 	chan_id = wlan_reg_freq_to_chan(wlan_vdev_get_pdev(vdev),
 					bcn_ptr->chan_freq);
 
-	if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) {
-		if (session->force_24ghz_in_ht20)
-			cb_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
-		else
-			cb_mode =
-			   mac_ctx->roam.configParam.channelBondingMode24GHz;
-	} else {
-		cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz;
-	}
-
+	cb_mode = lim_get_cb_mode_for_freq(mac_ctx, session,
+					   session->curr_op_freq);
 	if (cb_mode == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) {
 		/*
 		 * if channel bonding is disabled from INI do not

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

@@ -2119,6 +2119,11 @@ static void lim_process_messages(struct mac_context *mac_ctx,
 		qdf_mem_free(msg->bodyptr);
 		msg->bodyptr = NULL;
 		break;
+	case eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ:
+		lim_process_sme_req_messages(mac_ctx, msg);
+		qdf_mem_free((void *)msg->bodyptr);
+		msg->bodyptr = NULL;
+		break;
 	default:
 		qdf_mem_free((void *)msg->bodyptr);
 		msg->bodyptr = NULL;

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

@@ -283,7 +283,8 @@ lim_process_probe_req_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
 	tSirMacAddr dst_mac;
 
 	mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
-	if (LIM_IS_AP_ROLE(session)) {
+	if (LIM_IS_AP_ROLE(session) &&
+	    session->curr_op_freq == WMA_GET_RX_FREQ(rx_pkt_info)) {
 		frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info);
 
 		pe_debug("Received Probe Request: %d bytes from "QDF_MAC_ADDR_FMT,

+ 295 - 84
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -2111,12 +2111,18 @@ lim_get_bss_11be_mode_allowed(struct mac_context *mac_ctx,
 						  (struct qdf_mac_addr *)
 						  bss_desc->bssId);
 
+	/*
+	 * If AP advertises multiple AKMs(WPA2 PSK + WPA3), allow connection
+	 * in 11BE mode as our connection is going to be WPA3
+	 */
 	if (scan_entry) {
 		is_eht_allowed =
 			wlan_cm_is_eht_allowed_for_current_security(scan_entry);
 		util_scan_free_cache_entry(scan_entry);
-		if (!is_eht_allowed)
+		if (!is_eht_allowed) {
+			pe_debug("Downgrade to 11ax mode due to AP security validation failure");
 			return false;
+		}
 	}
 	return mlme_get_bss_11be_allowed(
 			mac_ctx->psoc,
@@ -5589,12 +5595,18 @@ void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session,
 	qdf_freq_t curr_op_freq, curr_freq;
 	enum reg_6g_client_type client_mobility_type;
 	struct ch_params ch_params = {0};
-	tDot11fIEtransmit_power_env single_tpe;
+	tDot11fIEtransmit_power_env single_tpe, local_tpe, reg_tpe;
 	/*
 	 * PSD is power spectral density, incoming TPE could contain
 	 * non PSD info, or PSD info, or both, so need to keep track of them
 	 */
 	bool use_local_tpe, non_psd_set = false, psd_set = false;
+	bool both_tpe_present = false;
+	bool local_eirp_set = false, local_psd_set = false;
+	bool reg_eirp_set = false, reg_psd_set = false;
+	uint8_t local_eirp_idx = 0, local_psd_idx = 0;
+	uint8_t reg_eirp_idx = 0, reg_psd_idx = 0;
+	uint8_t min_count = 0;
 
 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(session->vdev);
 	if (!vdev_mlme)
@@ -5632,34 +5644,35 @@ void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session,
 	else if (!local_tpe_count)
 		use_local_tpe = false;
 	else
-		use_local_tpe = wlan_mlme_is_local_tpe_pref(mac->psoc);
+		both_tpe_present = true;
 
 	for (i = 0; i < num_tpe_ies; i++) {
 		single_tpe = tpe_ies[i];
 		if (single_tpe.present &&
 		    (single_tpe.max_tx_pwr_category == client_mobility_type)) {
-			if (use_local_tpe) {
-				if (single_tpe.max_tx_pwr_interpret ==
-				    LOCAL_EIRP) {
-					non_psd_index = i;
-					non_psd_set = true;
-				}
-				if (single_tpe.max_tx_pwr_interpret ==
-				    LOCAL_EIRP_PSD) {
-					psd_index = i;
-					psd_set = true;
-				}
-			} else {
-				if (single_tpe.max_tx_pwr_interpret ==
-				    REGULATORY_CLIENT_EIRP) {
-					non_psd_index = i;
-					non_psd_set = true;
-				}
-				if (single_tpe.max_tx_pwr_interpret ==
-				    REGULATORY_CLIENT_EIRP_PSD) {
-					psd_index = i;
-					psd_set = true;
-				}
+			if (single_tpe.max_tx_pwr_interpret == LOCAL_EIRP) {
+				non_psd_index = i;
+				non_psd_set = true;
+				local_eirp_idx = non_psd_index;
+				local_eirp_set = non_psd_set;
+			} else if (single_tpe.max_tx_pwr_interpret ==
+				   LOCAL_EIRP_PSD) {
+				psd_index = i;
+				psd_set = true;
+				local_psd_idx = psd_index;
+				local_psd_set = psd_set;
+			} else if (single_tpe.max_tx_pwr_interpret ==
+				   REGULATORY_CLIENT_EIRP) {
+				non_psd_index = i;
+				non_psd_set = true;
+				reg_eirp_idx = non_psd_index;
+				reg_eirp_set = non_psd_set;
+			} else if (single_tpe.max_tx_pwr_interpret ==
+				   REGULATORY_CLIENT_EIRP_PSD) {
+				psd_index = i;
+				psd_set = true;
+				reg_psd_idx = psd_index;
+				reg_psd_set = psd_set;
 			}
 		}
 	}
@@ -5761,6 +5774,35 @@ void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session,
 			single_tpe.tx_power[single_tpe.max_tx_pwr_count];
 		vdev_mlme->reg_tpc_obj.is_psd_power = false;
 	}
+
+	if (both_tpe_present) {
+		pe_debug("Local: eirp: %d psd: %d, Regulatory: eirp: %d psd %d",
+			 local_eirp_set, local_psd_set, reg_eirp_set,
+			 reg_psd_set);
+		if (local_eirp_set && reg_eirp_set) {
+			local_tpe = tpe_ies[local_eirp_idx];
+			reg_tpe = tpe_ies[reg_eirp_idx];
+		} else if (local_psd_set && reg_psd_set) {
+			local_tpe = tpe_ies[local_psd_idx];
+			reg_tpe = tpe_ies[reg_psd_idx];
+		} else {
+			return;
+		}
+
+		min_count = QDF_MIN(local_tpe.max_tx_pwr_count,
+				    reg_tpe.max_tx_pwr_count);
+		for (i = 0; i < min_count + 1; i++) {
+			if (vdev_mlme->reg_tpc_obj.tpe[i] !=
+			    QDF_MIN(local_tpe.tx_power[i], reg_tpe.tx_power[i]))
+				*has_tpe_updated = true;
+			vdev_mlme->reg_tpc_obj.tpe[i] =
+						QDF_MIN(local_tpe.tx_power[i],
+							reg_tpe.tx_power[i]);
+			pe_debug("TPE: Local: %d, Reg: %d, power updated: %d",
+				 local_tpe.tx_power[i], reg_tpe.tx_power[i],
+				 *has_tpe_updated);
+		}
+	}
 }
 
 void lim_process_tpe_ie_from_beacon(struct mac_context *mac,
@@ -6833,7 +6875,7 @@ void lim_delete_all_peers(struct pe_session *session)
 		if (!sta_ds)
 			continue;
 		lim_mlo_notify_peer_disconn(session, sta_ds);
-		status = lim_del_sta(mac_ctx, sta_ds, true, session);
+		status = lim_del_sta(mac_ctx, sta_ds, false, session);
 		if (QDF_STATUS_SUCCESS == status) {
 			lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr,
 						  sta_ds->assocId, session);
@@ -8655,6 +8697,211 @@ static void lim_process_sme_deauth_req(struct mac_context *mac_ctx,
 	__lim_process_sme_deauth_req(mac_ctx, (uint32_t *)msg->bodyptr);
 }
 
+void lim_send_bcn_rsp(struct mac_context *mac_ctx, tpSendbeaconParams rsp)
+{
+	if (!rsp) {
+		pe_err("rsp is NULL");
+		return;
+	}
+
+	/* Success case response is sent from beacon_tx completion/timeout */
+	if (rsp->reason == REASON_CH_WIDTH_UPDATE &&
+	    QDF_IS_STATUS_SUCCESS(rsp->status))
+		return;
+
+	pe_debug("Send beacon resp status %d for reason %d",
+		 rsp->status, rsp->reason);
+
+	lim_nss_or_ch_width_update_rsp(mac_ctx, rsp->vdev_id,
+				       rsp->status, rsp->reason);
+}
+
+static void
+lim_update_bcn_with_new_ch_width(struct mac_context *mac_ctx,
+				 struct pe_session *session,
+				 enum phy_ch_width ch_width)
+{
+	QDF_STATUS status;
+
+	session->gLimOperatingMode.present = 1;
+	session->gLimOperatingMode.chanWidth = ch_width;
+
+	pe_debug("ch width %d",
+		 session->gLimOperatingMode.chanWidth);
+
+	session->bw_update_include_ch_sw_ie = true;
+	status = qdf_mc_timer_start(&session->ap_ecsa_timer,
+				    MAX_WAIT_FOR_CH_WIDTH_UPDATE_COMPLETE);
+	if (QDF_IS_STATUS_ERROR(status))
+		pe_err("cannot start ap_ecsa_timer");
+
+	/* Send nss update request from here */
+	status = sch_set_fixed_beacon_fields(mac_ctx, session);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Unable to set op mode IE in beacon");
+		goto end;
+	}
+
+	status = lim_send_beacon_ind(mac_ctx, session,
+				     REASON_CH_WIDTH_UPDATE);
+	if (QDF_IS_STATUS_SUCCESS(status))
+		return;
+
+	pe_err("Unable to send beacon");
+end:
+	/*
+	 * send resp only in case of failure,
+	 * success case response will be from wma.
+	 */
+	lim_nss_or_ch_width_update_rsp(mac_ctx, session->vdev_id, status,
+				       REASON_CH_WIDTH_UPDATE);
+}
+
+static enum phy_ch_width
+lim_calculate_peer_ch_width(struct pe_session *session,
+			    uint8_t *mac_addr,
+			    enum phy_ch_width new_ch_width)
+{
+	enum phy_ch_width peer_org_bw, updated_bw;
+	struct peer_oper_mode_event data = {0};
+	QDF_STATUS status;
+
+	peer_org_bw = wlan_mlme_get_peer_ch_width(
+				wlan_vdev_get_psoc(session->vdev), mac_addr);
+
+	updated_bw = new_ch_width;
+
+	qdf_mem_copy(&data.peer_mac_address.bytes, mac_addr, QDF_MAC_ADDR_SIZE);
+	status = wlan_mlme_get_peer_indicated_ch_width(
+				wlan_vdev_get_psoc(session->vdev), &data);
+	if (QDF_IS_STATUS_SUCCESS(status))
+		updated_bw = data.new_bw;
+
+	pe_debug("Peer: " QDF_MAC_ADDR_FMT " original bw: %d, updated bw: %d, new bw: %d",
+		 QDF_MAC_ADDR_REF(mac_addr), peer_org_bw, updated_bw,
+		 new_ch_width);
+
+	return qdf_min(peer_org_bw, qdf_min(updated_bw, new_ch_width));
+}
+
+static void
+lim_update_new_ch_width_to_fw(struct mac_context *mac_ctx,
+			      struct pe_session *session,
+			      enum phy_ch_width ch_bandwidth)
+{
+	uint8_t i;
+	tpDphHashNode psta;
+	tUpdateVHTOpMode params;
+
+	wlan_mlme_set_ap_oper_ch_width(session->vdev, ch_bandwidth);
+
+	for (i = 0; i <= mac_ctx->lim.max_sta_of_pe_session; i++) {
+		psta = session->dph.dphHashTable.pDphNodeArray + i;
+		if (!psta || !psta->added)
+			continue;
+
+		params.opMode = lim_calculate_peer_ch_width(session,
+					psta->staAddr, ch_bandwidth);
+		params.smesessionId = session->smeSessionId;
+		qdf_mem_copy(params.peer_mac, psta->staAddr,
+			     sizeof(tSirMacAddr));
+
+		lim_send_mode_update(mac_ctx, &params, session);
+	}
+}
+
+/**
+ * lim_process_sap_ch_width_update() - process sme nss update req
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @msg_buf: pointer to the SME message buffer
+ *
+ * This function processes SME request messages from HDD or upper layer
+ * application.
+ *
+ * Return: None
+ */
+static void
+lim_process_sap_ch_width_update(struct mac_context *mac_ctx,
+				uint32_t *msg_buf)
+{
+	struct sir_sap_ch_width_update *req;
+	struct pe_session *session = NULL;
+	uint8_t vdev_id;
+	struct sir_bcn_update_rsp *param;
+	struct scheduler_msg msg_return = {0};
+	uint8_t primary_channel;
+	struct ch_params ch_params = {0};
+
+	if (!msg_buf) {
+		pe_err("Buffer is Pointing to NULL");
+		return;
+	}
+
+	req = (struct sir_sap_ch_width_update *)msg_buf;
+	vdev_id = req->vdev_id;
+	session = pe_find_session_by_vdev_id(mac_ctx, req->vdev_id);
+	if (!session) {
+		pe_err("vdev %d session not found", req->vdev_id);
+		goto fail;
+	}
+
+	if (session->opmode != QDF_SAP_MODE) {
+		pe_err("Invalid opmode %d", session->opmode);
+		goto fail;
+	}
+
+	ch_params.ch_width = req->ch_width;
+	wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev,
+						session->curr_op_freq,
+						0,
+						&ch_params,
+						REG_CURRENT_PWR_MODE);
+
+	session->gLimChannelSwitch.switchCount = 1;
+	session->gLimChannelSwitch.sw_target_freq = session->curr_op_freq;
+	primary_channel = wlan_reg_freq_to_chan(mac_ctx->pdev,
+						session->curr_op_freq);
+	session->gLimChannelSwitch.primaryChannel = primary_channel;
+	session->gLimChannelSwitch.ch_width = req->ch_width;
+	session->gLimChannelSwitch.ch_center_freq_seg0 =
+						ch_params.center_freq_seg0;
+	session->gLimChannelSwitch.ch_center_freq_seg1 =
+						ch_params.center_freq_seg1;
+
+	wlan_mlme_set_ap_oper_ch_width(session->vdev, req->ch_width);
+
+	/* Send ECSA to the peers */
+	send_extended_chan_switch_action_frame(mac_ctx,
+				       session->curr_op_freq,
+				       req->ch_width, session);
+
+	/* Send beacon template to firmware */
+	lim_update_bcn_with_new_ch_width(mac_ctx, session, req->ch_width);
+	/* Send updated bw info of each peer to firmware */
+	lim_update_new_ch_width_to_fw(mac_ctx, session, req->ch_width);
+
+	/*
+	 * Release the SER command only after this, otherwise it may cause
+	 * out of sync issues if any other WMI commands go to fw
+	 */
+	return;
+
+fail:
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param)
+		return;
+
+	pe_err("vdev %d: send bandwidth update fail", vdev_id);
+	param->status = QDF_STATUS_E_FAILURE;
+	param->vdev_id = INVALID_VDEV_ID;
+	param->reason = REASON_CH_WIDTH_UPDATE;
+	msg_return.type = eWNI_SME_SAP_CH_WIDTH_UPDATE_RSP;
+	msg_return.bodyptr = param;
+	msg_return.bodyval = 0;
+	sys_process_mmh_msg(mac_ctx, &msg_return);
+}
+
 /**
  * lim_process_sme_req_messages()
  *
@@ -8864,6 +9111,9 @@ bool lim_process_sme_req_messages(struct mac_context *mac,
 		lim_process_sme_send_vdev_pause(mac,
 					(struct sme_vdev_pause *)msg_buf);
 		break;
+	case eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ:
+		lim_process_sap_ch_width_update(mac, msg_buf);
+		break;
 	default:
 		qdf_mem_free((void *)pMsg->bodyptr);
 		pMsg->bodyptr = NULL;
@@ -9479,36 +9729,42 @@ void send_extended_chan_switch_action_frame(struct mac_context *mac_ctx,
 	uint8_t op_class = 0;
 	uint8_t switch_mode = 0, i;
 	tpDphHashNode psta;
-	uint8_t switch_count;
 	uint8_t new_channel = 0;
+	enum phy_ch_width ch_width;
+	tLimChannelSwitchInfo *ch_switch = &session_entry->gLimChannelSwitch;
 
 	op_class =
 		lim_op_class_from_bandwidth(mac_ctx, new_channel_freq,
 					    ch_bandwidth,
-					    session_entry->gLimChannelSwitch.sec_ch_offset);
+					    ch_switch->sec_ch_offset);
 	new_channel = wlan_reg_freq_to_chan(mac_ctx->pdev, new_channel_freq);
 	if (LIM_IS_AP_ROLE(session_entry) &&
 		(mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false))
-		switch_mode = session_entry->gLimChannelSwitch.switchMode;
-
-	switch_count = session_entry->gLimChannelSwitch.switchCount;
+		switch_mode = ch_switch->switchMode;
 
 	if (LIM_IS_AP_ROLE(session_entry)) {
 		for (i = 0; i <= mac_ctx->lim.max_sta_of_pe_session; i++) {
 			psta =
 			  session_entry->dph.dphHashTable.pDphNodeArray + i;
-			if (psta && psta->added)
-				lim_send_extended_chan_switch_action_frame(
-					mac_ctx,
-					psta->staAddr,
+			if (!psta || !psta->added)
+				continue;
+			ch_width = lim_calculate_peer_ch_width(session_entry,
+							       psta->staAddr,
+							       ch_bandwidth);
+			op_class = lim_op_class_from_bandwidth(mac_ctx,
+						new_channel_freq, ch_width,
+						ch_switch->sec_ch_offset);
+			lim_send_extended_chan_switch_action_frame(
+					mac_ctx, psta->staAddr,
 					switch_mode, op_class, new_channel,
-					switch_count, session_entry);
+					ch_switch->switchCount, session_entry);
 		}
 	} else if (LIM_IS_STA_ROLE(session_entry)) {
 		lim_send_extended_chan_switch_action_frame(mac_ctx,
 					session_entry->bssId,
 					switch_mode, op_class, new_channel,
-					switch_count, session_entry);
+					ch_switch->switchCount,
+					session_entry);
 	}
 
 }
@@ -9786,52 +10042,6 @@ static void lim_process_ext_change_channel(struct mac_context *mac_ctx,
 					       session_entry);
 }
 
-/**
- * lim_nss_update_rsp() - send NSS update response to SME
- * @mac_ctx Pointer to Global MAC structure
- * @vdev_id: vdev id
- * @status: nss update status
- *
- * Return: None
- */
-static void lim_nss_update_rsp(struct mac_context *mac_ctx,
-			       uint8_t vdev_id, QDF_STATUS status)
-{
-	struct scheduler_msg msg = {0};
-	struct sir_bcn_update_rsp *nss_rsp;
-	QDF_STATUS qdf_status;
-
-	nss_rsp = qdf_mem_malloc(sizeof(*nss_rsp));
-	if (!nss_rsp)
-		return;
-
-	nss_rsp->vdev_id = vdev_id;
-	nss_rsp->status = status;
-	nss_rsp->reason = REASON_NSS_UPDATE;
-
-	msg.type = eWNI_SME_NSS_UPDATE_RSP;
-	msg.bodyptr = nss_rsp;
-	msg.bodyval = 0;
-	qdf_status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_SME,
-					    QDF_MODULE_ID_SME, &msg);
-	if (QDF_IS_STATUS_ERROR(qdf_status))
-		qdf_mem_free(nss_rsp);
-}
-
-void lim_send_bcn_rsp(struct mac_context *mac_ctx, tpSendbeaconParams rsp)
-{
-	if (!rsp) {
-		pe_err("rsp is NULL");
-		return;
-	}
-
-	pe_debug("Send beacon resp status %d for reason %d",
-		 rsp->status, rsp->reason);
-
-	if (rsp->reason == REASON_NSS_UPDATE)
-		lim_nss_update_rsp(mac_ctx, rsp->vdev_id, rsp->status);
-}
-
 /**
  * lim_process_nss_update_request() - process sme nss update req
  *
@@ -9907,7 +10117,8 @@ end:
 	 * send resp only in case of failure,
 	 * success case response will be from wma.
 	 */
-	lim_nss_update_rsp(mac_ctx, vdev_id, status);
+	lim_nss_or_ch_width_update_rsp(mac_ctx, vdev_id, status,
+				       REASON_NSS_UPDATE);
 }
 
 /**

Some files were not shown because too many files changed in this diff